ia64/xen-unstable

annotate xen/common/event_channel.c @ 1509:4fe70431c2d1

bitkeeper revision 1.986 (40d55284M764fMeIuW4JzqETaZKJBA)

Fixes.
author kaf24@scramble.cl.cam.ac.uk
date Sun Jun 20 09:01:56 2004 +0000 (2004-06-20)
parents 729cac1fb14e
children e5ddcc390f7c 7d2b7e6dad4c
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>
kaf24@954 25
kaf24@1127 26 #include <hypervisor-ifs/hypervisor-if.h>
kaf24@1127 27 #include <hypervisor-ifs/event_channel.h>
kaf24@1127 28
kaf24@1218 29 #define INIT_EVENT_CHANNELS 16
kaf24@1218 30 #define MAX_EVENT_CHANNELS 1024
kaf24@954 31
kaf24@1506 32 static int get_free_port(struct domain *d)
kaf24@954 33 {
kaf24@1127 34 int max, port;
kaf24@1127 35 event_channel_t *chn;
kaf24@1127 36
kaf24@1506 37 max = d->max_event_channel;
kaf24@1506 38 chn = d->event_channel;
kaf24@1127 39
kaf24@1127 40 for ( port = 0; port < max; port++ )
kaf24@1127 41 if ( chn[port].state == ECS_FREE )
kaf24@1127 42 break;
kaf24@1127 43
kaf24@1127 44 if ( port == max )
kaf24@1127 45 {
kaf24@1127 46 if ( max == MAX_EVENT_CHANNELS )
kaf24@1127 47 return -ENOSPC;
kaf24@1127 48
kaf24@1258 49 max *= 2;
kaf24@1127 50
kaf24@1127 51 chn = kmalloc(max * sizeof(event_channel_t), GFP_KERNEL);
kaf24@1127 52 if ( unlikely(chn == NULL) )
kaf24@1127 53 return -ENOMEM;
kaf24@1127 54
kaf24@1127 55 memset(chn, 0, max * sizeof(event_channel_t));
kaf24@1127 56
kaf24@1506 57 if ( d->event_channel != NULL )
kaf24@1127 58 {
kaf24@1506 59 memcpy(chn, d->event_channel, (max/2) * sizeof(event_channel_t));
kaf24@1506 60 kfree(d->event_channel);
kaf24@1127 61 }
kaf24@1127 62
kaf24@1506 63 d->event_channel = chn;
kaf24@1506 64 d->max_event_channel = max;
kaf24@1127 65 }
kaf24@1127 66
kaf24@1127 67 return port;
kaf24@1127 68 }
kaf24@1127 69
kaf24@1218 70 static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
kaf24@1127 71 {
kaf24@1506 72 struct domain *d1, *d2;
kaf24@1506 73 int port1 = 0, port2 = 0;
kaf24@1506 74 domid_t dom1 = bind->dom1, dom2 = bind->dom2;
kaf24@1506 75 long rc = 0;
kaf24@954 76
kaf24@1127 77 if ( !IS_PRIV(current) )
kaf24@1127 78 return -EPERM;
kaf24@954 79
kaf24@1129 80 if ( dom1 == DOMID_SELF )
kaf24@1129 81 dom1 = current->domain;
kaf24@1129 82 if ( dom2 == DOMID_SELF )
kaf24@1135 83 dom2 = current->domain;
kaf24@1127 84
kaf24@1506 85 if ( ((d1 = find_domain_by_id(dom1)) == NULL) ||
kaf24@1506 86 ((d2 = find_domain_by_id(dom2)) == NULL) )
kaf24@1127 87 {
kaf24@1506 88 if ( d1 != NULL )
kaf24@1506 89 put_domain(d1);
kaf24@1127 90 return -ESRCH;
kaf24@1127 91 }
kaf24@1127 92
kaf24@1127 93 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@1129 94 if ( dom1 < dom2 )
kaf24@954 95 {
kaf24@1506 96 spin_lock(&d1->event_channel_lock);
kaf24@1506 97 spin_lock(&d2->event_channel_lock);
kaf24@954 98 }
kaf24@954 99 else
kaf24@954 100 {
kaf24@1506 101 if ( d1 != d2 )
kaf24@1506 102 spin_lock(&d2->event_channel_lock);
kaf24@1506 103 spin_lock(&d1->event_channel_lock);
kaf24@954 104 }
kaf24@954 105
kaf24@1506 106 if ( (port1 = get_free_port(d1)) < 0 )
kaf24@954 107 {
kaf24@1129 108 rc = port1;
kaf24@1127 109 goto out;
kaf24@954 110 }
kaf24@954 111
kaf24@1329 112 /* 'Allocate' port1 before searching for a free port2. */
kaf24@1506 113 d1->event_channel[port1].state = ECS_INTERDOMAIN;
kaf24@1329 114
kaf24@1506 115 if ( (port2 = get_free_port(d2)) < 0 )
kaf24@954 116 {
kaf24@1506 117 d1->event_channel[port1].state = ECS_FREE;
kaf24@1129 118 rc = port2;
kaf24@1127 119 goto out;
kaf24@1127 120 }
kaf24@954 121
kaf24@1506 122 d1->event_channel[port1].u.remote.dom = d2;
kaf24@1506 123 d1->event_channel[port1].u.remote.port = (u16)port2;
kaf24@954 124
kaf24@1506 125 d2->event_channel[port2].u.remote.dom = d1;
kaf24@1506 126 d2->event_channel[port2].u.remote.port = (u16)port1;
kaf24@1506 127 d2->event_channel[port2].state = ECS_INTERDOMAIN;
kaf24@1127 128
kaf24@1506 129 evtchn_set_pending(d1, port1);
kaf24@1506 130 evtchn_set_pending(d2, port2);
kaf24@954 131
kaf24@954 132 out:
kaf24@1506 133 spin_unlock(&d1->event_channel_lock);
kaf24@1506 134 if ( d1 != d2 )
kaf24@1506 135 spin_unlock(&d2->event_channel_lock);
kaf24@1127 136
kaf24@1506 137 put_domain(d1);
kaf24@1506 138 put_domain(d2);
kaf24@1127 139
kaf24@1218 140 bind->port1 = port1;
kaf24@1218 141 bind->port2 = port2;
kaf24@954 142
kaf24@954 143 return rc;
kaf24@954 144 }
kaf24@954 145
kaf24@954 146
kaf24@1218 147 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
kaf24@1218 148 {
kaf24@1506 149 struct domain *d = current;
kaf24@1506 150 int port, virq = bind->virq;
kaf24@1218 151
kaf24@1506 152 if ( virq >= ARRAY_SIZE(d->virq_to_evtchn) )
kaf24@1218 153 return -EINVAL;
kaf24@1218 154
kaf24@1506 155 spin_lock(&d->event_channel_lock);
kaf24@1218 156
kaf24@1218 157 /*
kaf24@1218 158 * Port 0 is the fallback port for VIRQs that haven't been explicitly
kaf24@1249 159 * bound yet. The exception is the 'misdirect VIRQ', which is permanently
kaf24@1218 160 * bound to port 0.
kaf24@1218 161 */
kaf24@1506 162 if ( ((port = d->virq_to_evtchn[virq]) != 0) ||
kaf24@1249 163 (virq == VIRQ_MISDIRECT) ||
kaf24@1506 164 ((port = get_free_port(d)) < 0) )
kaf24@1218 165 goto out;
kaf24@1218 166
kaf24@1506 167 d->event_channel[port].state = ECS_VIRQ;
kaf24@1506 168 d->event_channel[port].u.virq = virq;
kaf24@1218 169
kaf24@1506 170 d->virq_to_evtchn[virq] = port;
kaf24@1218 171
kaf24@1218 172 out:
kaf24@1506 173 spin_unlock(&d->event_channel_lock);
kaf24@1218 174
kaf24@1218 175 if ( port < 0 )
kaf24@1218 176 return port;
kaf24@1218 177
kaf24@1218 178 bind->port = port;
kaf24@1218 179 return 0;
kaf24@1218 180 }
kaf24@1218 181
kaf24@1218 182
kaf24@1235 183 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 184 {
kaf24@1506 185 struct domain *d = current;
kaf24@1506 186 int port, rc, pirq = bind->pirq;
kaf24@1235 187
kaf24@1506 188 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 189 return -EINVAL;
kaf24@1235 190
kaf24@1506 191 spin_lock(&d->event_channel_lock);
kaf24@1235 192
kaf24@1506 193 if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
kaf24@1506 194 ((rc = port = get_free_port(d)) < 0) )
kaf24@1235 195 goto out;
kaf24@1235 196
kaf24@1506 197 d->pirq_to_evtchn[pirq] = port;
kaf24@1506 198 rc = pirq_guest_bind(d, pirq,
kaf24@1253 199 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 200 if ( rc != 0 )
kaf24@1239 201 {
kaf24@1506 202 d->pirq_to_evtchn[pirq] = 0;
kaf24@1251 203 DPRINTK("Couldn't bind to PIRQ %d (error=%d)\n", pirq, rc);
kaf24@1239 204 goto out;
kaf24@1239 205 }
kaf24@1239 206
kaf24@1506 207 d->event_channel[port].state = ECS_PIRQ;
kaf24@1506 208 d->event_channel[port].u.pirq = pirq;
kaf24@1235 209
kaf24@1235 210 out:
kaf24@1506 211 spin_unlock(&d->event_channel_lock);
kaf24@1235 212
kaf24@1239 213 if ( rc < 0 )
kaf24@1239 214 return rc;
kaf24@1235 215
kaf24@1235 216 bind->port = port;
kaf24@1235 217 return 0;
kaf24@1235 218 }
kaf24@1235 219
kaf24@1235 220
kaf24@1506 221 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 222 {
kaf24@1506 223 struct domain *d2 = NULL;
kaf24@1506 224 event_channel_t *chn1, *chn2;
kaf24@1506 225 int port2;
kaf24@1506 226 long rc = 0;
kaf24@954 227
kaf24@954 228 again:
kaf24@1506 229 spin_lock(&d1->event_channel_lock);
kaf24@954 230
kaf24@1506 231 chn1 = d1->event_channel;
kaf24@954 232
kaf24@1249 233 /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
kaf24@1506 234 if ( (port1 <= 0) || (port1 >= d1->max_event_channel) )
kaf24@954 235 {
kaf24@954 236 rc = -EINVAL;
kaf24@954 237 goto out;
kaf24@954 238 }
kaf24@954 239
kaf24@1218 240 switch ( chn1[port1].state )
kaf24@954 241 {
kaf24@1218 242 case ECS_FREE:
kaf24@1218 243 rc = -EINVAL;
kaf24@1218 244 goto out;
kaf24@1218 245
kaf24@1218 246 case ECS_UNBOUND:
kaf24@1218 247 break;
kaf24@1218 248
kaf24@1218 249 case ECS_PIRQ:
kaf24@1506 250 if ( (rc = pirq_guest_unbind(d1, chn1[port1].u.pirq)) == 0 )
kaf24@1506 251 d1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
kaf24@1218 252 break;
kaf24@1218 253
kaf24@1218 254 case ECS_VIRQ:
kaf24@1506 255 d1->virq_to_evtchn[chn1[port1].u.virq] = 0;
kaf24@1218 256 break;
kaf24@1218 257
kaf24@1218 258 case ECS_INTERDOMAIN:
kaf24@1506 259 if ( d2 == NULL )
kaf24@954 260 {
kaf24@1506 261 d2 = chn1[port1].u.remote.dom;
kaf24@1505 262
kaf24@1506 263 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 264 if ( unlikely(!get_domain(d2)) )
kaf24@1505 265 {
kaf24@1505 266 /*
kaf24@1506 267 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 268 * and so will close this event channel for us.
kaf24@1505 269 */
kaf24@1506 270 d2 = NULL;
kaf24@1505 271 goto out;
kaf24@1505 272 }
kaf24@1127 273
kaf24@1506 274 if ( d1->domain < d2->domain )
kaf24@954 275 {
kaf24@1506 276 spin_lock(&d2->event_channel_lock);
kaf24@954 277 }
kaf24@1506 278 else if ( d1 != d2 )
kaf24@954 279 {
kaf24@1506 280 spin_unlock(&d1->event_channel_lock);
kaf24@1506 281 spin_lock(&d2->event_channel_lock);
kaf24@954 282 goto again;
kaf24@954 283 }
kaf24@954 284 }
kaf24@1506 285 else if ( d2 != chn1[port1].u.remote.dom )
kaf24@954 286 {
kaf24@954 287 rc = -EINVAL;
kaf24@954 288 goto out;
kaf24@954 289 }
kaf24@1505 290
kaf24@1506 291 chn2 = d2->event_channel;
kaf24@1218 292 port2 = chn1[port1].u.remote.port;
kaf24@954 293
kaf24@1506 294 if ( port2 >= d2->max_event_channel )
kaf24@1127 295 BUG();
kaf24@1218 296 if ( chn2[port2].state != ECS_INTERDOMAIN )
kaf24@1127 297 BUG();
kaf24@1506 298 if ( chn2[port2].u.remote.dom != d1 )
kaf24@1127 299 BUG();
kaf24@954 300
kaf24@1258 301 chn2[port2].state = ECS_UNBOUND;
kaf24@1506 302 evtchn_set_exception(d2, port2);
kaf24@1218 303
kaf24@1218 304 break;
kaf24@1218 305
kaf24@1218 306 default:
kaf24@1218 307 BUG();
kaf24@954 308 }
kaf24@954 309
kaf24@1258 310 chn1[port1].state = ECS_FREE;
kaf24@1506 311 evtchn_set_exception(d1, port1);
kaf24@1133 312
kaf24@954 313 out:
kaf24@1506 314 if ( d2 != NULL )
kaf24@954 315 {
kaf24@1506 316 if ( d1 != d2 )
kaf24@1506 317 spin_unlock(&d2->event_channel_lock);
kaf24@1506 318 put_domain(d2);
kaf24@954 319 }
kaf24@954 320
kaf24@1506 321 spin_unlock(&d1->event_channel_lock);
kaf24@1145 322
kaf24@954 323 return rc;
kaf24@954 324 }
kaf24@954 325
kaf24@954 326
kaf24@1218 327 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 328 {
kaf24@1506 329 struct domain *d;
kaf24@1506 330 long rc;
kaf24@1506 331 domid_t dom = close->dom;
kaf24@1127 332
kaf24@1129 333 if ( dom == DOMID_SELF )
kaf24@1129 334 dom = current->domain;
kaf24@1127 335 else if ( !IS_PRIV(current) )
kaf24@1127 336 return -EPERM;
kaf24@1127 337
kaf24@1506 338 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 339 return -ESRCH;
kaf24@1127 340
kaf24@1506 341 rc = __evtchn_close(d, close->port);
kaf24@1127 342
kaf24@1506 343 put_domain(d);
kaf24@1127 344 return rc;
kaf24@1127 345 }
kaf24@1127 346
kaf24@1127 347
kaf24@1218 348 static long evtchn_send(int lport)
kaf24@954 349 {
kaf24@1506 350 struct domain *ld = current, *rd;
kaf24@1506 351 int rport;
kaf24@954 352
kaf24@1506 353 spin_lock(&ld->event_channel_lock);
kaf24@954 354
kaf24@1127 355 if ( unlikely(lport < 0) ||
kaf24@1506 356 unlikely(lport >= ld->max_event_channel) ||
kaf24@1506 357 unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) )
kaf24@954 358 {
kaf24@1506 359 spin_unlock(&ld->event_channel_lock);
kaf24@954 360 return -EINVAL;
kaf24@954 361 }
kaf24@954 362
kaf24@1506 363 rd = ld->event_channel[lport].u.remote.dom;
kaf24@1506 364 rport = ld->event_channel[lport].u.remote.port;
kaf24@1127 365
kaf24@1506 366 evtchn_set_pending(rd, rport);
kaf24@954 367
kaf24@1506 368 spin_unlock(&ld->event_channel_lock);
kaf24@954 369
kaf24@954 370 return 0;
kaf24@954 371 }
kaf24@954 372
kaf24@954 373
kaf24@1218 374 static long evtchn_status(evtchn_status_t *status)
kaf24@954 375 {
kaf24@1506 376 struct domain *d;
kaf24@1506 377 domid_t dom = status->dom;
kaf24@1506 378 int port = status->port;
kaf24@1506 379 event_channel_t *chn;
kaf24@1506 380 long rc = 0;
kaf24@1127 381
kaf24@1129 382 if ( dom == DOMID_SELF )
kaf24@1129 383 dom = current->domain;
kaf24@1127 384 else if ( !IS_PRIV(current) )
kaf24@1127 385 return -EPERM;
kaf24@1127 386
kaf24@1506 387 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 388 return -ESRCH;
kaf24@954 389
kaf24@1506 390 spin_lock(&d->event_channel_lock);
kaf24@954 391
kaf24@1506 392 chn = d->event_channel;
kaf24@954 393
kaf24@1506 394 if ( (port < 0) || (port >= d->max_event_channel) )
kaf24@954 395 {
kaf24@1266 396 rc = -EINVAL;
kaf24@1266 397 goto out;
kaf24@1127 398 }
kaf24@1127 399
kaf24@1129 400 switch ( chn[port].state )
kaf24@1127 401 {
kaf24@1127 402 case ECS_FREE:
kaf24@1127 403 status->status = EVTCHNSTAT_closed;
kaf24@1127 404 break;
kaf24@1218 405 case ECS_UNBOUND:
kaf24@1218 406 status->status = EVTCHNSTAT_unbound;
kaf24@1127 407 break;
kaf24@1218 408 case ECS_INTERDOMAIN:
kaf24@1218 409 status->status = EVTCHNSTAT_interdomain;
kaf24@1218 410 status->u.interdomain.dom = chn[port].u.remote.dom->domain;
kaf24@1218 411 status->u.interdomain.port = chn[port].u.remote.port;
kaf24@1218 412 break;
kaf24@1218 413 case ECS_PIRQ:
kaf24@1218 414 status->status = EVTCHNSTAT_pirq;
kaf24@1218 415 status->u.pirq = chn[port].u.pirq;
kaf24@1218 416 break;
kaf24@1218 417 case ECS_VIRQ:
kaf24@1218 418 status->status = EVTCHNSTAT_virq;
kaf24@1218 419 status->u.virq = chn[port].u.virq;
kaf24@1127 420 break;
kaf24@1127 421 default:
kaf24@1127 422 BUG();
kaf24@954 423 }
kaf24@954 424
kaf24@1266 425 out:
kaf24@1506 426 spin_unlock(&d->event_channel_lock);
kaf24@1506 427 put_domain(d);
kaf24@1266 428 return rc;
kaf24@954 429 }
kaf24@954 430
kaf24@954 431
kaf24@1127 432 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 433 {
kaf24@954 434 long rc;
kaf24@1127 435 evtchn_op_t op;
kaf24@954 436
kaf24@1127 437 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 438 return -EFAULT;
kaf24@1127 439
kaf24@1127 440 switch ( op.cmd )
kaf24@954 441 {
kaf24@1218 442 case EVTCHNOP_bind_interdomain:
kaf24@1218 443 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 444 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 445 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 446 break;
kaf24@1218 447
kaf24@1218 448 case EVTCHNOP_bind_virq:
kaf24@1218 449 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 450 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 451 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 452 break;
kaf24@1235 453
kaf24@1235 454 case EVTCHNOP_bind_pirq:
kaf24@1235 455 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 456 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 457 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 458 break;
kaf24@954 459
kaf24@954 460 case EVTCHNOP_close:
kaf24@1218 461 rc = evtchn_close(&op.u.close);
kaf24@954 462 break;
kaf24@954 463
kaf24@954 464 case EVTCHNOP_send:
kaf24@1218 465 rc = evtchn_send(op.u.send.local_port);
kaf24@954 466 break;
kaf24@954 467
kaf24@954 468 case EVTCHNOP_status:
kaf24@1218 469 rc = evtchn_status(&op.u.status);
kaf24@1235 470 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 471 rc = -EFAULT;
kaf24@954 472 break;
kaf24@954 473
kaf24@954 474 default:
kaf24@954 475 rc = -ENOSYS;
kaf24@954 476 break;
kaf24@954 477 }
kaf24@954 478
kaf24@954 479 return rc;
kaf24@954 480 }
kaf24@954 481
kaf24@954 482
kaf24@1506 483 int init_event_channels(struct domain *d)
kaf24@1218 484 {
kaf24@1506 485 spin_lock_init(&d->event_channel_lock);
kaf24@1506 486 d->event_channel = kmalloc(INIT_EVENT_CHANNELS * sizeof(event_channel_t),
kaf24@1218 487 GFP_KERNEL);
kaf24@1506 488 if ( unlikely(d->event_channel == NULL) )
kaf24@1218 489 return -ENOMEM;
kaf24@1506 490 d->max_event_channel = INIT_EVENT_CHANNELS;
kaf24@1506 491 memset(d->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 492 d->event_channel[0].state = ECS_VIRQ;
kaf24@1506 493 d->event_channel[0].u.virq = VIRQ_MISDIRECT;
kaf24@1218 494 return 0;
kaf24@1218 495 }
kaf24@1218 496
kaf24@1218 497
kaf24@1506 498 void destroy_event_channels(struct domain *d)
kaf24@954 499 {
kaf24@954 500 int i;
kaf24@1506 501 if ( d->event_channel != NULL )
kaf24@954 502 {
kaf24@1506 503 for ( i = 0; i < d->max_event_channel; i++ )
kaf24@1506 504 (void)__evtchn_close(d, i);
kaf24@1506 505 kfree(d->event_channel);
kaf24@954 506 }
kaf24@954 507 }