ia64/xen-unstable

annotate xen/common/event_channel.c @ 5308:3c5a200df2c1

bitkeeper revision 1.1664.1.1 (42a08862ToP8uoeBgUzDwAQBMXo4wg)

Event-channel CPU affinity. Currently all event channels still bind to
VCPU#0 at start of day, and have their binding automatically changed
when bound to a VIRQ or IPI source. XenLinux maintains a per-cpu
evtchn mask denoting which event channels are bound to each cpu.
Todo: Allow guests to change binding of of non-ipi and non-virq evtchns.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Jun 03 16:42:10 2005 +0000 (2005-06-03)
parents 8651a99cdc09
children fa68b7fb217f
rev   line source
kaf24@954 1 /******************************************************************************
kaf24@954 2 * event_channel.c
kaf24@954 3 *
kaf24@1509 4 * Event notifications from VIRQs, PIRQs, and other domains.
kaf24@954 5 *
kaf24@1127 6 * Copyright (c) 2003-2004, K A Fraser.
kaf24@954 7 *
kaf24@954 8 * This program is distributed in the hope that it will be useful,
kaf24@954 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
kaf24@954 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kaf24@954 11 * GNU General Public License for more details.
kaf24@954 12 *
kaf24@954 13 * You should have received a copy of the GNU General Public License
kaf24@954 14 * along with this program; if not, write to the Free Software
kaf24@954 15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kaf24@954 16 */
kaf24@954 17
kaf24@1210 18 #include <xen/config.h>
kaf24@1210 19 #include <xen/init.h>
kaf24@1210 20 #include <xen/lib.h>
kaf24@1210 21 #include <xen/errno.h>
kaf24@1210 22 #include <xen/sched.h>
kaf24@1210 23 #include <xen/event.h>
kaf24@1239 24 #include <xen/irq.h>
cl349@5291 25 #include <asm/current.h>
kaf24@954 26
kaf24@2789 27 #include <public/xen.h>
kaf24@2789 28 #include <public/event_channel.h>
kaf24@1127 29
kaf24@5308 30 #define bucket_from_port(d,p) \
kaf24@5308 31 ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
kaf24@5308 32 #define port_is_valid(d,p) \
kaf24@5308 33 (((p) >= 0) && ((p) < MAX_EVTCHNS) && \
kaf24@5308 34 (bucket_from_port(d,p) != NULL))
kaf24@5308 35 #define evtchn_from_port(d,p) \
kaf24@5308 36 (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])
kaf24@1127 37
kaf24@5308 38 static int get_free_port(struct domain *d)
kaf24@5308 39 {
kaf24@5308 40 struct evtchn *chn;
kaf24@5308 41 int port;
cl349@3114 42
kaf24@5308 43 for ( port = 0; port_is_valid(d, port); port++ )
kaf24@5308 44 if ( evtchn_from_port(d, port)->state == ECS_FREE )
kaf24@5308 45 return port;
kaf24@1127 46
kaf24@5308 47 if ( port == MAX_EVTCHNS )
kaf24@5308 48 return -ENOSPC;
kaf24@1127 49
kaf24@5308 50 chn = xmalloc_array(struct evtchn, EVTCHNS_PER_BUCKET);
kaf24@5308 51 if ( unlikely(chn == NULL) )
kaf24@5308 52 return -ENOMEM;
kaf24@5308 53 memset(chn, 0, EVTCHNS_PER_BUCKET * sizeof(*chn));
kaf24@5308 54 bucket_from_port(d, port) = chn;
kaf24@1127 55
kaf24@1127 56 return port;
kaf24@1127 57 }
kaf24@1127 58
kaf24@2713 59
kaf24@2713 60 static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
kaf24@2713 61 {
kaf24@5308 62 struct evtchn *chn;
cl349@2919 63 struct domain *d = current->domain;
kaf24@2713 64 int port;
kaf24@2713 65
kaf24@5308 66 spin_lock(&d->evtchn_lock);
kaf24@2713 67
kaf24@5308 68 if ( (port = get_free_port(d)) >= 0 )
kaf24@2713 69 {
kaf24@5308 70 chn = evtchn_from_port(d, port);
kaf24@5308 71 chn->state = ECS_UNBOUND;
kaf24@5308 72 chn->u.unbound.remote_domid = alloc->dom;
kaf24@2713 73 }
kaf24@2713 74
kaf24@5308 75 spin_unlock(&d->evtchn_lock);
kaf24@2713 76
kaf24@2713 77 if ( port < 0 )
kaf24@2713 78 return port;
kaf24@2713 79
kaf24@2713 80 alloc->port = port;
kaf24@2713 81 return 0;
kaf24@2713 82 }
kaf24@2713 83
kaf24@2713 84
kaf24@1218 85 static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
kaf24@1127 86 {
kaf24@2713 87 #define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
kaf24@5308 88 struct evtchn *chn1, *chn2;
kaf24@1506 89 struct domain *d1, *d2;
kaf24@2713 90 int port1 = bind->port1, port2 = bind->port2;
kaf24@1506 91 domid_t dom1 = bind->dom1, dom2 = bind->dom2;
kaf24@1506 92 long rc = 0;
kaf24@954 93
cl349@2919 94 if ( !IS_PRIV(current->domain) && (dom1 != DOMID_SELF) )
kaf24@1127 95 return -EPERM;
kaf24@954 96
kaf24@1129 97 if ( dom1 == DOMID_SELF )
kaf24@4877 98 dom1 = current->domain->domain_id;
kaf24@1129 99 if ( dom2 == DOMID_SELF )
kaf24@4877 100 dom2 = current->domain->domain_id;
kaf24@1127 101
kaf24@1506 102 if ( ((d1 = find_domain_by_id(dom1)) == NULL) ||
kaf24@1506 103 ((d2 = find_domain_by_id(dom2)) == NULL) )
kaf24@1127 104 {
kaf24@1506 105 if ( d1 != NULL )
kaf24@1506 106 put_domain(d1);
kaf24@1127 107 return -ESRCH;
kaf24@1127 108 }
kaf24@1127 109
kaf24@1127 110 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@1542 111 if ( d1 < d2 )
kaf24@954 112 {
kaf24@5308 113 spin_lock(&d1->evtchn_lock);
kaf24@5308 114 spin_lock(&d2->evtchn_lock);
kaf24@954 115 }
kaf24@954 116 else
kaf24@954 117 {
kaf24@1506 118 if ( d1 != d2 )
kaf24@5308 119 spin_lock(&d2->evtchn_lock);
kaf24@5308 120 spin_lock(&d1->evtchn_lock);
kaf24@954 121 }
kaf24@954 122
kaf24@2713 123 /* Obtain, or ensure that we already have, a valid <port1>. */
kaf24@2713 124 if ( port1 == 0 )
kaf24@954 125 {
kaf24@5308 126 if ( (port1 = get_free_port(d1)) < 0 )
kaf24@2713 127 ERROR_EXIT(port1);
kaf24@2713 128 }
kaf24@5308 129 else if ( !port_is_valid(d1, port1) )
kaf24@2713 130 ERROR_EXIT(-EINVAL);
kaf24@5308 131 chn1 = evtchn_from_port(d1, port1);
kaf24@2713 132
kaf24@2713 133 /* Obtain, or ensure that we already have, a valid <port2>. */
kaf24@2713 134 if ( port2 == 0 )
kaf24@2713 135 {
kaf24@2713 136 /* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
kaf24@5308 137 u16 state = chn1->state;
kaf24@5308 138 chn1->state = ECS_INTERDOMAIN;
kaf24@5308 139 port2 = get_free_port(d2);
kaf24@5308 140 chn1->state = state;
kaf24@2713 141 if ( port2 < 0 )
kaf24@2713 142 ERROR_EXIT(port2);
kaf24@2713 143 }
kaf24@5308 144 else if ( !port_is_valid(d2, port2) )
kaf24@2713 145 ERROR_EXIT(-EINVAL);
kaf24@5308 146 chn2 = evtchn_from_port(d2, port2);
kaf24@2713 147
kaf24@2713 148 /* Validate <dom1,port1>'s current state. */
kaf24@5308 149 switch ( chn1->state )
kaf24@2713 150 {
kaf24@2713 151 case ECS_FREE:
kaf24@2713 152 break;
kaf24@2713 153
kaf24@2713 154 case ECS_UNBOUND:
kaf24@5308 155 if ( chn1->u.unbound.remote_domid != dom2 )
kaf24@2713 156 ERROR_EXIT(-EINVAL);
kaf24@2713 157 break;
kaf24@2713 158
kaf24@2713 159 case ECS_INTERDOMAIN:
kaf24@5308 160 if ( chn1->u.interdomain.remote_dom != d2 )
kaf24@2719 161 ERROR_EXIT(-EINVAL);
kaf24@5308 162 if ( (chn1->u.interdomain.remote_port != port2) && (bind->port2 != 0) )
kaf24@2719 163 ERROR_EXIT(-EINVAL);
kaf24@5308 164 port2 = chn1->u.interdomain.remote_port;
kaf24@1127 165 goto out;
kaf24@2713 166
kaf24@2713 167 default:
kaf24@2713 168 ERROR_EXIT(-EINVAL);
kaf24@954 169 }
kaf24@954 170
kaf24@2713 171 /* Validate <dom2,port2>'s current state. */
kaf24@5308 172 switch ( chn2->state )
kaf24@2713 173 {
kaf24@2713 174 case ECS_FREE:
cl349@2919 175 if ( !IS_PRIV(current->domain) && (dom2 != DOMID_SELF) )
kaf24@2717 176 ERROR_EXIT(-EPERM);
kaf24@2713 177 break;
kaf24@1329 178
kaf24@2713 179 case ECS_UNBOUND:
kaf24@5308 180 if ( chn2->u.unbound.remote_domid != dom1 )
kaf24@2713 181 ERROR_EXIT(-EINVAL);
kaf24@2713 182 break;
kaf24@2713 183
kaf24@2719 184 case ECS_INTERDOMAIN:
kaf24@5308 185 if ( chn2->u.interdomain.remote_dom != d1 )
kaf24@2719 186 ERROR_EXIT(-EINVAL);
kaf24@5308 187 if ( (chn2->u.interdomain.remote_port != port1) && (bind->port1 != 0) )
kaf24@2719 188 ERROR_EXIT(-EINVAL);
kaf24@5308 189 port1 = chn2->u.interdomain.remote_port;
kaf24@2719 190 goto out;
kaf24@2719 191
kaf24@2713 192 default:
kaf24@2713 193 ERROR_EXIT(-EINVAL);
kaf24@1127 194 }
kaf24@954 195
kaf24@2713 196 /*
kaf24@2713 197 * Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
kaf24@2713 198 */
kaf24@2713 199
kaf24@5308 200 chn1->u.interdomain.remote_dom = d2;
kaf24@5308 201 chn1->u.interdomain.remote_port = (u16)port2;
kaf24@5308 202 chn1->state = ECS_INTERDOMAIN;
kaf24@2713 203
kaf24@5308 204 chn2->u.interdomain.remote_dom = d1;
kaf24@5308 205 chn2->u.interdomain.remote_port = (u16)port1;
kaf24@5308 206 chn2->state = ECS_INTERDOMAIN;
kaf24@1127 207
kaf24@954 208 out:
kaf24@5308 209 spin_unlock(&d1->evtchn_lock);
kaf24@1506 210 if ( d1 != d2 )
kaf24@5308 211 spin_unlock(&d2->evtchn_lock);
kaf24@1127 212
kaf24@1506 213 put_domain(d1);
kaf24@1506 214 put_domain(d2);
kaf24@1127 215
kaf24@1218 216 bind->port1 = port1;
kaf24@1218 217 bind->port2 = port2;
kaf24@954 218
kaf24@954 219 return rc;
kaf24@2713 220 #undef ERROR_EXIT
kaf24@954 221 }
kaf24@954 222
kaf24@954 223
kaf24@1218 224 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
kaf24@1218 225 {
kaf24@5308 226 struct evtchn *chn;
kaf24@5289 227 struct vcpu *v = current;
kaf24@5289 228 struct domain *d = v->domain;
kaf24@1506 229 int port, virq = bind->virq;
kaf24@1218 230
kaf24@5289 231 if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
kaf24@1218 232 return -EINVAL;
kaf24@1218 233
kaf24@5308 234 spin_lock(&d->evtchn_lock);
kaf24@1218 235
kaf24@1218 236 /*
kaf24@1218 237 * Port 0 is the fallback port for VIRQs that haven't been explicitly
cl349@3297 238 * bound yet.
kaf24@1218 239 */
kaf24@5289 240 if ( ((port = v->virq_to_evtchn[virq]) != 0) ||
kaf24@5308 241 ((port = get_free_port(d)) < 0) )
kaf24@1218 242 goto out;
kaf24@1218 243
kaf24@5308 244 chn = evtchn_from_port(d, port);
kaf24@5308 245 chn->state = ECS_VIRQ;
kaf24@5308 246 chn->notify_vcpu_id = v->vcpu_id;
kaf24@5308 247 chn->u.virq = virq;
kaf24@1218 248
kaf24@5289 249 v->virq_to_evtchn[virq] = port;
kaf24@1218 250
kaf24@1218 251 out:
kaf24@5308 252 spin_unlock(&d->evtchn_lock);
kaf24@1218 253
kaf24@1218 254 if ( port < 0 )
kaf24@1218 255 return port;
kaf24@1218 256
kaf24@1218 257 bind->port = port;
cl349@2932 258 return 0;
cl349@2932 259 }
cl349@2932 260
kaf24@5308 261
cl349@2932 262 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
cl349@2932 263 {
kaf24@5308 264 struct evtchn *chn;
kaf24@5308 265 struct domain *d = current->domain;
kaf24@5289 266 int port, ipi_vcpu = bind->ipi_vcpu;
cl349@2932 267
kaf24@5308 268 if ( (ipi_vcpu >= MAX_VIRT_CPUS) || (d->vcpu[ipi_vcpu] == NULL) )
kaf24@4202 269 return -EINVAL;
kaf24@4202 270
kaf24@5308 271 spin_lock(&d->evtchn_lock);
cl349@2932 272
kaf24@5308 273 if ( (port = get_free_port(d)) >= 0 )
cl349@2932 274 {
kaf24@5308 275 chn = evtchn_from_port(d, port);
kaf24@5308 276 chn->state = ECS_IPI;
kaf24@5308 277 chn->notify_vcpu_id = ipi_vcpu;
cl349@2932 278 }
cl349@2932 279
kaf24@5308 280 spin_unlock(&d->evtchn_lock);
cl349@2932 281
cl349@2932 282 if ( port < 0 )
cl349@2932 283 return port;
cl349@2932 284
cl349@2932 285 bind->port = port;
kaf24@1218 286 return 0;
kaf24@1218 287 }
kaf24@1218 288
kaf24@1218 289
kaf24@1235 290 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 291 {
kaf24@5308 292 struct evtchn *chn;
cl349@2919 293 struct domain *d = current->domain;
kaf24@1506 294 int port, rc, pirq = bind->pirq;
kaf24@1235 295
kaf24@1506 296 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 297 return -EINVAL;
kaf24@1235 298
kaf24@5308 299 spin_lock(&d->evtchn_lock);
kaf24@1235 300
kaf24@1506 301 if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
kaf24@5308 302 ((rc = port = get_free_port(d)) < 0) )
kaf24@1235 303 goto out;
kaf24@1235 304
kaf24@5308 305 chn = evtchn_from_port(d, port);
kaf24@5308 306
kaf24@1506 307 d->pirq_to_evtchn[pirq] = port;
kaf24@5308 308 rc = pirq_guest_bind(d->vcpu[chn->notify_vcpu_id], pirq,
kaf24@1253 309 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 310 if ( rc != 0 )
kaf24@1239 311 {
kaf24@1506 312 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 313 goto out;
kaf24@1239 314 }
kaf24@1239 315
kaf24@5308 316 chn->state = ECS_PIRQ;
kaf24@5308 317 chn->u.pirq = pirq;
kaf24@1235 318
kaf24@1235 319 out:
kaf24@5308 320 spin_unlock(&d->evtchn_lock);
kaf24@1235 321
kaf24@1239 322 if ( rc < 0 )
kaf24@1239 323 return rc;
kaf24@1235 324
kaf24@1235 325 bind->port = port;
kaf24@1235 326 return 0;
kaf24@1235 327 }
kaf24@1235 328
kaf24@1235 329
kaf24@1506 330 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 331 {
kaf24@5308 332 struct domain *d2 = NULL;
kaf24@5308 333 struct vcpu *v;
kaf24@5308 334 struct evtchn *chn1, *chn2;
kaf24@5308 335 int port2;
kaf24@5308 336 long rc = 0;
kaf24@954 337
kaf24@954 338 again:
kaf24@5308 339 spin_lock(&d1->evtchn_lock);
kaf24@954 340
kaf24@5308 341 if ( !port_is_valid(d1, port1) )
kaf24@954 342 {
kaf24@954 343 rc = -EINVAL;
kaf24@954 344 goto out;
kaf24@954 345 }
kaf24@954 346
kaf24@5308 347 chn1 = evtchn_from_port(d1, port1);
kaf24@5308 348 switch ( chn1->state )
kaf24@954 349 {
kaf24@1218 350 case ECS_FREE:
cl349@3297 351 case ECS_RESERVED:
kaf24@1218 352 rc = -EINVAL;
kaf24@1218 353 goto out;
kaf24@1218 354
kaf24@1218 355 case ECS_UNBOUND:
kaf24@1218 356 break;
kaf24@1218 357
kaf24@1218 358 case ECS_PIRQ:
kaf24@5308 359 if ( (rc = pirq_guest_unbind(d1, chn1->u.pirq)) == 0 )
kaf24@5308 360 d1->pirq_to_evtchn[chn1->u.pirq] = 0;
kaf24@1218 361 break;
kaf24@1218 362
kaf24@1218 363 case ECS_VIRQ:
kaf24@5289 364 for_each_vcpu ( d1, v )
kaf24@5308 365 if ( v->virq_to_evtchn[chn1->u.virq] == port1 )
kaf24@5308 366 v->virq_to_evtchn[chn1->u.virq] = 0;
kaf24@1218 367 break;
kaf24@1218 368
cl349@2932 369 case ECS_IPI:
cl349@2932 370 break;
cl349@2932 371
kaf24@1218 372 case ECS_INTERDOMAIN:
kaf24@1506 373 if ( d2 == NULL )
kaf24@954 374 {
kaf24@5308 375 d2 = chn1->u.interdomain.remote_dom;
kaf24@1505 376
kaf24@1506 377 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 378 if ( unlikely(!get_domain(d2)) )
kaf24@1505 379 {
kaf24@1505 380 /*
kaf24@1506 381 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 382 * and so will close this event channel for us.
kaf24@1505 383 */
kaf24@1506 384 d2 = NULL;
kaf24@1505 385 goto out;
kaf24@1505 386 }
kaf24@1127 387
kaf24@1542 388 if ( d1 < d2 )
kaf24@954 389 {
kaf24@5308 390 spin_lock(&d2->evtchn_lock);
kaf24@954 391 }
kaf24@1506 392 else if ( d1 != d2 )
kaf24@954 393 {
kaf24@5308 394 spin_unlock(&d1->evtchn_lock);
kaf24@5308 395 spin_lock(&d2->evtchn_lock);
kaf24@954 396 goto again;
kaf24@954 397 }
kaf24@954 398 }
kaf24@5308 399 else if ( d2 != chn1->u.interdomain.remote_dom )
kaf24@954 400 {
kaf24@954 401 rc = -EINVAL;
kaf24@954 402 goto out;
kaf24@954 403 }
kaf24@1505 404
kaf24@5308 405 port2 = chn1->u.interdomain.remote_port;
kaf24@5308 406 BUG_ON(!port_is_valid(d2, port2));
kaf24@954 407
kaf24@5308 408 chn2 = evtchn_from_port(d2, port2);
kaf24@5308 409 BUG_ON(chn2->state != ECS_INTERDOMAIN);
kaf24@5308 410 BUG_ON(chn2->u.interdomain.remote_dom != d1);
kaf24@954 411
kaf24@5308 412 chn2->state = ECS_UNBOUND;
kaf24@5308 413 chn2->u.unbound.remote_domid = d1->domain_id;
kaf24@1218 414 break;
kaf24@1218 415
kaf24@1218 416 default:
kaf24@1218 417 BUG();
kaf24@954 418 }
kaf24@954 419
kaf24@5308 420 chn1->state = ECS_FREE;
kaf24@1133 421
kaf24@954 422 out:
kaf24@1506 423 if ( d2 != NULL )
kaf24@954 424 {
kaf24@1506 425 if ( d1 != d2 )
kaf24@5308 426 spin_unlock(&d2->evtchn_lock);
kaf24@1506 427 put_domain(d2);
kaf24@954 428 }
kaf24@954 429
kaf24@5308 430 spin_unlock(&d1->evtchn_lock);
kaf24@1145 431
kaf24@954 432 return rc;
kaf24@954 433 }
kaf24@954 434
kaf24@954 435
kaf24@1218 436 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 437 {
kaf24@1506 438 struct domain *d;
kaf24@1506 439 long rc;
kaf24@1506 440 domid_t dom = close->dom;
kaf24@1127 441
kaf24@1129 442 if ( dom == DOMID_SELF )
kaf24@4877 443 dom = current->domain->domain_id;
cl349@2919 444 else if ( !IS_PRIV(current->domain) )
kaf24@1127 445 return -EPERM;
kaf24@1127 446
kaf24@1506 447 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 448 return -ESRCH;
kaf24@1127 449
kaf24@1506 450 rc = __evtchn_close(d, close->port);
kaf24@1127 451
kaf24@1506 452 put_domain(d);
kaf24@1127 453 return rc;
kaf24@1127 454 }
kaf24@1127 455
kaf24@1127 456
iap10@3290 457 long evtchn_send(int lport)
kaf24@954 458 {
kaf24@5308 459 struct evtchn *lchn, *rchn;
kaf24@5308 460 struct domain *ld = current->domain, *rd;
cl349@2937 461 int rport, ret = 0;
kaf24@954 462
kaf24@5308 463 spin_lock(&ld->evtchn_lock);
kaf24@954 464
kaf24@5308 465 if ( unlikely(!port_is_valid(ld, lport)) )
kaf24@954 466 {
kaf24@5308 467 spin_unlock(&ld->evtchn_lock);
kaf24@954 468 return -EINVAL;
kaf24@954 469 }
kaf24@954 470
kaf24@5308 471 lchn = evtchn_from_port(ld, lport);
kaf24@5308 472 switch ( lchn->state )
cl349@2937 473 {
cl349@2937 474 case ECS_INTERDOMAIN:
kaf24@5308 475 rd = lchn->u.interdomain.remote_dom;
kaf24@5308 476 rport = lchn->u.interdomain.remote_port;
kaf24@5308 477 rchn = evtchn_from_port(rd, rport);
kaf24@5308 478 evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
cl349@2937 479 break;
cl349@2937 480 case ECS_IPI:
kaf24@5308 481 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
cl349@2937 482 break;
cl349@2937 483 default:
cl349@2937 484 ret = -EINVAL;
cl349@2937 485 }
kaf24@954 486
kaf24@5308 487 spin_unlock(&ld->evtchn_lock);
kaf24@954 488
cl349@2937 489 return ret;
kaf24@954 490 }
kaf24@954 491
kaf24@5308 492 void send_guest_pirq(struct domain *d, int pirq)
kaf24@5308 493 {
kaf24@5308 494 int port = d->pirq_to_evtchn[pirq];
kaf24@5308 495 struct evtchn *chn = evtchn_from_port(d, port);
kaf24@5308 496 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
kaf24@5308 497 }
kaf24@954 498
kaf24@1218 499 static long evtchn_status(evtchn_status_t *status)
kaf24@954 500 {
kaf24@1506 501 struct domain *d;
kaf24@1506 502 domid_t dom = status->dom;
kaf24@1506 503 int port = status->port;
kaf24@5308 504 struct evtchn *chn;
kaf24@1506 505 long rc = 0;
kaf24@1127 506
kaf24@1129 507 if ( dom == DOMID_SELF )
kaf24@4877 508 dom = current->domain->domain_id;
cl349@2919 509 else if ( !IS_PRIV(current->domain) )
kaf24@1127 510 return -EPERM;
kaf24@1127 511
kaf24@1506 512 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 513 return -ESRCH;
kaf24@954 514
kaf24@5308 515 spin_lock(&d->evtchn_lock);
kaf24@954 516
kaf24@5308 517 if ( !port_is_valid(d, port) )
kaf24@954 518 {
kaf24@1266 519 rc = -EINVAL;
kaf24@1266 520 goto out;
kaf24@1127 521 }
kaf24@1127 522
kaf24@5308 523 chn = evtchn_from_port(d, port);
kaf24@5308 524 switch ( chn->state )
kaf24@1127 525 {
kaf24@1127 526 case ECS_FREE:
cl349@3297 527 case ECS_RESERVED:
kaf24@1127 528 status->status = EVTCHNSTAT_closed;
kaf24@1127 529 break;
kaf24@1218 530 case ECS_UNBOUND:
kaf24@1218 531 status->status = EVTCHNSTAT_unbound;
kaf24@5308 532 status->u.unbound.dom = chn->u.unbound.remote_domid;
kaf24@1127 533 break;
kaf24@1218 534 case ECS_INTERDOMAIN:
kaf24@1218 535 status->status = EVTCHNSTAT_interdomain;
cl349@2924 536 status->u.interdomain.dom =
kaf24@5308 537 chn->u.interdomain.remote_dom->domain_id;
kaf24@5308 538 status->u.interdomain.port = chn->u.interdomain.remote_port;
kaf24@1218 539 break;
kaf24@1218 540 case ECS_PIRQ:
kaf24@1218 541 status->status = EVTCHNSTAT_pirq;
kaf24@5308 542 status->u.pirq = chn->u.pirq;
kaf24@1218 543 break;
kaf24@1218 544 case ECS_VIRQ:
kaf24@1218 545 status->status = EVTCHNSTAT_virq;
kaf24@5308 546 status->u.virq = chn->u.virq;
kaf24@1127 547 break;
cl349@2932 548 case ECS_IPI:
cl349@2932 549 status->status = EVTCHNSTAT_ipi;
kaf24@5308 550 status->u.ipi_vcpu = chn->notify_vcpu_id;
cl349@2932 551 break;
kaf24@1127 552 default:
kaf24@1127 553 BUG();
kaf24@954 554 }
kaf24@954 555
kaf24@1266 556 out:
kaf24@5308 557 spin_unlock(&d->evtchn_lock);
kaf24@1506 558 put_domain(d);
kaf24@1266 559 return rc;
kaf24@954 560 }
kaf24@954 561
kaf24@954 562
kaf24@1127 563 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 564 {
kaf24@954 565 long rc;
kaf24@1127 566 evtchn_op_t op;
kaf24@954 567
kaf24@1127 568 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 569 return -EFAULT;
kaf24@1127 570
kaf24@1127 571 switch ( op.cmd )
kaf24@954 572 {
kaf24@2713 573 case EVTCHNOP_alloc_unbound:
kaf24@2713 574 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 575 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 576 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 577 break;
kaf24@2713 578
kaf24@1218 579 case EVTCHNOP_bind_interdomain:
kaf24@1218 580 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 581 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 582 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 583 break;
kaf24@1218 584
kaf24@1218 585 case EVTCHNOP_bind_virq:
kaf24@1218 586 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 587 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 588 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 589 break;
kaf24@1235 590
cl349@2932 591 case EVTCHNOP_bind_ipi:
cl349@2932 592 rc = evtchn_bind_ipi(&op.u.bind_ipi);
cl349@2932 593 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
cl349@2932 594 rc = -EFAULT; /* Cleaning up here would be a mess! */
cl349@2932 595 break;
cl349@2932 596
kaf24@1235 597 case EVTCHNOP_bind_pirq:
kaf24@1235 598 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 599 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 600 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 601 break;
kaf24@954 602
kaf24@954 603 case EVTCHNOP_close:
kaf24@1218 604 rc = evtchn_close(&op.u.close);
kaf24@954 605 break;
kaf24@954 606
kaf24@954 607 case EVTCHNOP_send:
kaf24@1218 608 rc = evtchn_send(op.u.send.local_port);
kaf24@954 609 break;
kaf24@954 610
kaf24@954 611 case EVTCHNOP_status:
kaf24@1218 612 rc = evtchn_status(&op.u.status);
kaf24@1235 613 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 614 rc = -EFAULT;
kaf24@954 615 break;
kaf24@954 616
kaf24@954 617 default:
kaf24@954 618 rc = -ENOSYS;
kaf24@954 619 break;
kaf24@954 620 }
kaf24@954 621
kaf24@954 622 return rc;
kaf24@954 623 }
kaf24@954 624
kaf24@954 625
kaf24@5308 626 int evtchn_init(struct domain *d)
kaf24@1218 627 {
kaf24@5308 628 spin_lock_init(&d->evtchn_lock);
kaf24@5308 629 if ( get_free_port(d) != 0 )
cl349@3291 630 return -EINVAL;
kaf24@5308 631 evtchn_from_port(d, 0)->state = ECS_RESERVED;
cl349@3291 632 return 0;
kaf24@1218 633 }
kaf24@1218 634
kaf24@1218 635
kaf24@5308 636 void evtchn_destroy(struct domain *d)
kaf24@954 637 {
kaf24@954 638 int i;
kaf24@5308 639
kaf24@5308 640 for ( i = 0; port_is_valid(d, i); i++ )
kaf24@1506 641 (void)__evtchn_close(d, i);
kaf24@5308 642
kaf24@5308 643 for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
kaf24@5308 644 if ( d->evtchn[i] != NULL )
kaf24@5308 645 xfree(d->evtchn[i]);
kaf24@954 646 }
kaf24@3914 647
kaf24@3914 648 /*
kaf24@3914 649 * Local variables:
kaf24@3914 650 * mode: C
kaf24@3914 651 * c-set-style: "BSD"
kaf24@3914 652 * c-basic-offset: 4
kaf24@3914 653 * tab-width: 4
kaf24@3914 654 * indent-tabs-mode: nil
kaf24@3988 655 * End:
kaf24@3914 656 */