1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 /*
  29  * evtchn.c
  30  *
  31  * Driver for receiving and demuxing event-channel signals.
  32  *
  33  * Copyright (c) 2004-2005, K A Fraser
  34  * Multi-process extensions Copyright (c) 2004, Steven Smith
  35  *
  36  * This file may be distributed separately from the Linux kernel, or
  37  * incorporated into other software packages, subject to the following license:
  38  *
  39  * Permission is hereby granted, free of charge, to any person obtaining a copy
  40  * of this source file (the "Software"), to deal in the Software without
  41  * restriction, including without limitation the rights to use, copy, modify,
  42  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
  43  * and to permit persons to whom the Software is furnished to do so, subject to
  44  * the following conditions:
  45  *
  46  * The above copyright notice and this permission notice shall be included in
  47  * all copies or substantial portions of the Software.
  48  *
  49  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  50  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  51  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  52  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  53  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  54  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  55  * IN THE SOFTWARE.
  56  */
  57 
  58 #include <sys/types.h>
  59 #include <sys/hypervisor.h>
  60 #include <sys/machsystm.h>
  61 #include <sys/mutex.h>
  62 #include <sys/evtchn_impl.h>
  63 #include <sys/ddi_impldefs.h>
  64 #include <sys/avintr.h>
  65 #include <sys/cpuvar.h>
  66 #include <sys/smp_impldefs.h>
  67 #include <sys/archsystm.h>
  68 #include <sys/sysmacros.h>
  69 #include <sys/fcntl.h>
  70 #include <sys/open.h>
  71 #include <sys/stat.h>
  72 #include <sys/psm.h>
  73 #include <sys/cpu.h>
  74 #include <sys/cmn_err.h>
  75 #include <sys/xen_errno.h>
  76 #include <sys/policy.h>
  77 #include <xen/sys/evtchn.h>
  78 
  79 /* Some handy macros */
  80 #define EVTCHNDRV_MINOR2INST(minor)     ((int)(minor))
  81 #define EVTCHNDRV_DEFAULT_NCLONES       256
  82 #define EVTCHNDRV_INST2SOFTS(inst)      \
  83         (ddi_get_soft_state(evtchndrv_statep, (inst)))
  84 
  85 /* Soft state data structure for evtchn driver */
  86 struct evtsoftdata {
  87         dev_info_t *dip;
  88         /* Notification ring, accessed via /dev/xen/evtchn. */
  89 #define EVTCHN_RING_SIZE        (PAGESIZE / sizeof (evtchn_port_t))
  90 #define EVTCHN_RING_MASK(_i)    ((_i) & (EVTCHN_RING_SIZE - 1))
  91         evtchn_port_t *ring;
  92         unsigned int ring_cons, ring_prod, ring_overflow;
  93 
  94         kcondvar_t evtchn_wait; /* Processes wait on this when ring is empty. */
  95         kmutex_t evtchn_lock;
  96         struct pollhead evtchn_pollhead;
  97 
  98         pid_t pid;              /* last pid to bind to this event channel. */
  99         processorid_t cpu;      /* cpu thread/evtchn is bound to */
 100 };
 101 
 102 static void *evtchndrv_statep;
 103 int evtchndrv_nclones = EVTCHNDRV_DEFAULT_NCLONES;
 104 static int *evtchndrv_clone_tab;
 105 static dev_info_t *evtchndrv_dip;
 106 static kmutex_t evtchndrv_clone_tab_mutex;
 107 
 108 static int evtchndrv_detach(dev_info_t *, ddi_detach_cmd_t);
 109 
 110 /* Who's bound to each port? */
 111 static struct evtsoftdata *port_user[NR_EVENT_CHANNELS];
 112 static kmutex_t port_user_lock;
 113 
 114 void
 115 evtchn_device_upcall()
 116 {
 117         struct evtsoftdata *ep;
 118         int port;
 119 
 120         /*
 121          * This is quite gross, we had to leave the evtchn that led to this
 122          * invocation in a per-cpu mailbox, retrieve it now.
 123          * We do this because the interface doesn't offer us a way to pass
 124          * a dynamic argument up through the generic interrupt service layer.
 125          * The mailbox is safe since we either run with interrupts disabled or
 126          * non-preemptable till we reach here.
 127          */
 128         port = CPU->cpu_m.mcpu_ec_mbox;
 129         ASSERT(port != 0);
 130         CPU->cpu_m.mcpu_ec_mbox = 0;
 131         ec_clear_evtchn(port);
 132         mutex_enter(&port_user_lock);
 133 
 134         if ((ep = port_user[port]) != NULL) {
 135                 mutex_enter(&ep->evtchn_lock);
 136                 if ((ep->ring_prod - ep->ring_cons) < EVTCHN_RING_SIZE) {
 137                         ep->ring[EVTCHN_RING_MASK(ep->ring_prod)] = port;
 138                         /*
 139                          * Wake up reader when ring goes non-empty
 140                          */
 141                         if (ep->ring_cons == ep->ring_prod++) {
 142                                 cv_signal(&ep->evtchn_wait);
 143                                 mutex_exit(&ep->evtchn_lock);
 144                                 pollwakeup(&ep->evtchn_pollhead,
 145                                     POLLIN | POLLRDNORM);
 146                                 goto done;
 147                         }
 148                 } else {
 149                         ep->ring_overflow = 1;
 150                 }
 151                 mutex_exit(&ep->evtchn_lock);
 152         }
 153 
 154 done:
 155         mutex_exit(&port_user_lock);
 156 }
 157 
 158 /* ARGSUSED */
 159 static int
 160 evtchndrv_read(dev_t dev, struct uio *uio, cred_t *cr)
 161 {
 162         int rc = 0;
 163         ssize_t count;
 164         unsigned int c, p, bytes1 = 0, bytes2 = 0;
 165         struct evtsoftdata *ep;
 166         minor_t minor = getminor(dev);
 167 
 168         if (secpolicy_xvm_control(cr))
 169                 return (EPERM);
 170 
 171         ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor));
 172 
 173         /* Whole number of ports. */
 174         count = uio->uio_resid;
 175         count &= ~(sizeof (evtchn_port_t) - 1);
 176 
 177         if (count == 0)
 178                 return (0);
 179 
 180         if (count > PAGESIZE)
 181                 count = PAGESIZE;
 182 
 183         mutex_enter(&ep->evtchn_lock);
 184         for (;;) {
 185                 if (ep->ring_overflow) {
 186                         rc = EFBIG;
 187                         goto done;
 188                 }
 189 
 190                 if ((c = ep->ring_cons) != (p = ep->ring_prod))
 191                         break;
 192 
 193                 if (uio->uio_fmode & O_NONBLOCK) {
 194                         rc = EAGAIN;
 195                         goto done;
 196                 }
 197 
 198                 if (cv_wait_sig(&ep->evtchn_wait, &ep->evtchn_lock) == 0) {
 199                         rc = EINTR;
 200                         goto done;
 201                 }
 202         }
 203 
 204         /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
 205         if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
 206                 bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
 207                     sizeof (evtchn_port_t);
 208                 bytes2 = EVTCHN_RING_MASK(p) * sizeof (evtchn_port_t);
 209         } else {
 210                 bytes1 = (p - c) * sizeof (evtchn_port_t);
 211                 bytes2 = 0;
 212         }
 213 
 214         /* Truncate chunks according to caller's maximum byte count. */
 215         if (bytes1 > count) {
 216                 bytes1 = count;
 217                 bytes2 = 0;
 218         } else if ((bytes1 + bytes2) > count) {
 219                 bytes2 = count - bytes1;
 220         }
 221 
 222         if (uiomove(&ep->ring[EVTCHN_RING_MASK(c)], bytes1, UIO_READ, uio) ||
 223             ((bytes2 != 0) && uiomove(&ep->ring[0], bytes2, UIO_READ, uio))) {
 224                 rc = EFAULT;
 225                 goto done;
 226         }
 227 
 228         ep->ring_cons += (bytes1 + bytes2) / sizeof (evtchn_port_t);
 229 done:
 230         mutex_exit(&ep->evtchn_lock);
 231         return (rc);
 232 }
 233 
 234 /* ARGSUSED */
 235 static int
 236 evtchndrv_write(dev_t dev, struct uio *uio, cred_t *cr)
 237 {
 238         int  rc, i;
 239         ssize_t count;
 240         evtchn_port_t *kbuf;
 241         struct evtsoftdata *ep;
 242         ulong_t flags;
 243         minor_t minor = getminor(dev);
 244         evtchn_port_t sbuf[32];
 245 
 246         if (secpolicy_xvm_control(cr))
 247                 return (EPERM);
 248 
 249         ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor));
 250 
 251 
 252         /* Whole number of ports. */
 253         count = uio->uio_resid;
 254         count &= ~(sizeof (evtchn_port_t) - 1);
 255 
 256         if (count == 0)
 257                 return (0);
 258 
 259         if (count > PAGESIZE)
 260                 count = PAGESIZE;
 261 
 262         if (count <= sizeof (sbuf))
 263                 kbuf = sbuf;
 264         else
 265                 kbuf = kmem_alloc(PAGESIZE, KM_SLEEP);
 266         if ((rc = uiomove(kbuf, count, UIO_WRITE, uio)) != 0)
 267                 goto out;
 268 
 269         mutex_enter(&port_user_lock);
 270         for (i = 0; i < (count / sizeof (evtchn_port_t)); i++)
 271                 if ((kbuf[i] < NR_EVENT_CHANNELS) &&
 272                     (port_user[kbuf[i]] == ep)) {
 273                         flags = intr_clear();
 274                         ec_unmask_evtchn(kbuf[i]);
 275                         intr_restore(flags);
 276                 }
 277         mutex_exit(&port_user_lock);
 278 
 279 out:
 280         if (kbuf != sbuf)
 281                 kmem_free(kbuf, PAGESIZE);
 282         return (rc);
 283 }
 284 
 285 static void
 286 evtchn_bind_to_user(struct evtsoftdata *u, int port)
 287 {
 288         ulong_t flags;
 289 
 290         /*
 291          * save away the PID of the last process to bind to this event channel.
 292          * Useful for debugging.
 293          */
 294         u->pid = ddi_get_pid();
 295 
 296         mutex_enter(&port_user_lock);
 297         ASSERT(port_user[port] == NULL);
 298         port_user[port] = u;
 299         ec_irq_add_evtchn(ec_dev_irq, port);
 300         flags = intr_clear();
 301         ec_unmask_evtchn(port);
 302         intr_restore(flags);
 303         mutex_exit(&port_user_lock);
 304 }
 305 
 306 static void
 307 evtchndrv_close_evtchn(int port)
 308 {
 309         struct evtsoftdata *ep;
 310 
 311         ASSERT(MUTEX_HELD(&port_user_lock));
 312         ep = port_user[port];
 313         ASSERT(ep != NULL);
 314         (void) ec_mask_evtchn(port);
 315         /*
 316          * It is possible the event is in transit to us.
 317          * If it is already in the ring buffer, then a client may
 318          * get a spurious event notification on the next read of
 319          * of the evtchn device.  Clients will need to be able to
 320          * handle getting a spurious event notification.
 321          */
 322         port_user[port] = NULL;
 323         /*
 324          * The event is masked and should stay so, clean it up.
 325          */
 326         ec_irq_rm_evtchn(ec_dev_irq, port);
 327 }
 328 
 329 /* ARGSUSED */
 330 static int
 331 evtchndrv_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cr,
 332     int *rvalp)
 333 {
 334         int err = 0;
 335         struct evtsoftdata *ep;
 336         minor_t minor = getminor(dev);
 337 
 338         if (secpolicy_xvm_control(cr))
 339                 return (EPERM);
 340 
 341         ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor));
 342 
 343         *rvalp = 0;
 344 
 345         switch (cmd) {
 346         case IOCTL_EVTCHN_BIND_VIRQ: {
 347                 struct ioctl_evtchn_bind_virq bind;
 348 
 349                 if (copyin((void *)data, &bind, sizeof (bind))) {
 350                         err = EFAULT;
 351                         break;
 352                 }
 353 
 354                 if ((err = xen_bind_virq(bind.virq, 0, rvalp)) != 0)
 355                         break;
 356 
 357                 evtchn_bind_to_user(ep, *rvalp);
 358                 break;
 359         }
 360 
 361         case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
 362                 struct ioctl_evtchn_bind_interdomain bind;
 363 
 364                 if (copyin((void *)data, &bind, sizeof (bind))) {
 365                         err = EFAULT;
 366                         break;
 367                 }
 368 
 369                 if ((err = xen_bind_interdomain(bind.remote_domain,
 370                     bind.remote_port, rvalp)) != 0)
 371                         break;
 372 
 373                 ec_bind_vcpu(*rvalp, 0);
 374                 evtchn_bind_to_user(ep, *rvalp);
 375                 break;
 376         }
 377 
 378         case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
 379                 struct ioctl_evtchn_bind_unbound_port bind;
 380 
 381                 if (copyin((void *)data, &bind, sizeof (bind))) {
 382                         err = EFAULT;
 383                         break;
 384                 }
 385 
 386                 if ((err = xen_alloc_unbound_evtchn(bind.remote_domain,
 387                     rvalp)) != 0)
 388                         break;
 389 
 390                 evtchn_bind_to_user(ep, *rvalp);
 391                 break;
 392         }
 393 
 394         case IOCTL_EVTCHN_UNBIND: {
 395                 struct ioctl_evtchn_unbind unbind;
 396 
 397                 if (copyin((void *)data, &unbind, sizeof (unbind))) {
 398                         err = EFAULT;
 399                         break;
 400                 }
 401 
 402                 if (unbind.port >= NR_EVENT_CHANNELS) {
 403                         err = EFAULT;
 404                         break;
 405                 }
 406 
 407                 mutex_enter(&port_user_lock);
 408 
 409                 if (port_user[unbind.port] != ep) {
 410                         mutex_exit(&port_user_lock);
 411                         err = ENOTCONN;
 412                         break;
 413                 }
 414 
 415                 evtchndrv_close_evtchn(unbind.port);
 416                 mutex_exit(&port_user_lock);
 417                 break;
 418         }
 419 
 420         case IOCTL_EVTCHN_NOTIFY: {
 421                 struct ioctl_evtchn_notify notify;
 422 
 423                 if (copyin((void *)data, &notify, sizeof (notify))) {
 424                         err = EFAULT;
 425                         break;
 426                 }
 427 
 428                 if (notify.port >= NR_EVENT_CHANNELS) {
 429                         err = EINVAL;
 430                 } else if (port_user[notify.port] != ep) {
 431                         err = ENOTCONN;
 432                 } else {
 433                         ec_notify_via_evtchn(notify.port);
 434                 }
 435                 break;
 436         }
 437 
 438         default:
 439                 err = ENOSYS;
 440         }
 441 
 442         return (err);
 443 }
 444 
 445 static int
 446 evtchndrv_poll(dev_t dev, short ev, int anyyet, short *revp, pollhead_t **phpp)
 447 {
 448         struct evtsoftdata *ep;
 449         minor_t minor = getminor(dev);
 450         short mask = 0;
 451 
 452         ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor));
 453         *phpp = (struct pollhead *)NULL;
 454 
 455         if (ev & POLLOUT)
 456                 mask |= POLLOUT;
 457         if (ep->ring_overflow)
 458                 mask |= POLLERR;
 459         if (ev & (POLLIN | POLLRDNORM)) {
 460                 mutex_enter(&ep->evtchn_lock);
 461                 if (ep->ring_cons != ep->ring_prod)
 462                         mask |= (POLLIN | POLLRDNORM) & ev;
 463                 else
 464                         if (mask == 0 && !anyyet)
 465                                 *phpp = &ep->evtchn_pollhead;
 466                 mutex_exit(&ep->evtchn_lock);
 467         }
 468         *revp = mask;
 469         return (0);
 470 }
 471 
 472 
 473 /* ARGSUSED */
 474 static int
 475 evtchndrv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
 476 {
 477         struct evtsoftdata *ep;
 478         minor_t minor = getminor(*devp);
 479 
 480         if (otyp == OTYP_BLK)
 481                 return (ENXIO);
 482 
 483         /*
 484          * only allow open on minor = 0 - the clone device
 485          */
 486         if (minor != 0)
 487                 return (ENXIO);
 488 
 489         /*
 490          * find a free slot and grab it
 491          */
 492         mutex_enter(&evtchndrv_clone_tab_mutex);
 493         for (minor = 1; minor < evtchndrv_nclones; minor++) {
 494                 if (evtchndrv_clone_tab[minor] == 0) {
 495                         evtchndrv_clone_tab[minor] = 1;
 496                         break;
 497                 }
 498         }
 499         mutex_exit(&evtchndrv_clone_tab_mutex);
 500         if (minor == evtchndrv_nclones)
 501                 return (EAGAIN);
 502 
 503         /* Allocate softstate structure */
 504         if (ddi_soft_state_zalloc(evtchndrv_statep,
 505             EVTCHNDRV_MINOR2INST(minor)) != DDI_SUCCESS) {
 506                 mutex_enter(&evtchndrv_clone_tab_mutex);
 507                 evtchndrv_clone_tab[minor] = 0;
 508                 mutex_exit(&evtchndrv_clone_tab_mutex);
 509                 return (EAGAIN);
 510         }
 511         ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor));
 512 
 513         /* ... and init it */
 514         ep->dip = evtchndrv_dip;
 515 
 516         cv_init(&ep->evtchn_wait, NULL, CV_DEFAULT, NULL);
 517         mutex_init(&ep->evtchn_lock, NULL, MUTEX_DEFAULT, NULL);
 518 
 519         ep->ring = kmem_alloc(PAGESIZE, KM_SLEEP);
 520 
 521         /* clone driver */
 522         *devp = makedevice(getmajor(*devp), minor);
 523 
 524         return (0);
 525 }
 526 
 527 /* ARGSUSED */
 528 static int
 529 evtchndrv_close(dev_t dev, int flag, int otyp, struct cred *credp)
 530 {
 531         struct evtsoftdata *ep;
 532         minor_t minor = getminor(dev);
 533         int i;
 534 
 535         ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor));
 536         if (ep == NULL)
 537                 return (ENXIO);
 538 
 539         mutex_enter(&port_user_lock);
 540 
 541 
 542         for (i = 0; i < NR_EVENT_CHANNELS; i++) {
 543                 if (port_user[i] != ep)
 544                         continue;
 545 
 546                 evtchndrv_close_evtchn(i);
 547         }
 548 
 549         mutex_exit(&port_user_lock);
 550 
 551         kmem_free(ep->ring, PAGESIZE);
 552         ddi_soft_state_free(evtchndrv_statep, EVTCHNDRV_MINOR2INST(minor));
 553 
 554         /*
 555          * free clone tab slot
 556          */
 557         mutex_enter(&evtchndrv_clone_tab_mutex);
 558         evtchndrv_clone_tab[minor] = 0;
 559         mutex_exit(&evtchndrv_clone_tab_mutex);
 560 
 561         return (0);
 562 }
 563 
 564 /* ARGSUSED */
 565 static int
 566 evtchndrv_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 567 {
 568         dev_t   dev = (dev_t)arg;
 569         minor_t minor = getminor(dev);
 570         int     retval;
 571 
 572         switch (cmd) {
 573         case DDI_INFO_DEVT2DEVINFO:
 574                 if (minor != 0 || evtchndrv_dip == NULL) {
 575                         *result = (void *)NULL;
 576                         retval = DDI_FAILURE;
 577                 } else {
 578                         *result = (void *)evtchndrv_dip;
 579                         retval = DDI_SUCCESS;
 580                 }
 581                 break;
 582         case DDI_INFO_DEVT2INSTANCE:
 583                 *result = (void *)0;
 584                 retval = DDI_SUCCESS;
 585                 break;
 586         default:
 587                 retval = DDI_FAILURE;
 588         }
 589         return (retval);
 590 }
 591 
 592 
 593 static int
 594 evtchndrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 595 {
 596         int     error;
 597         int     unit = ddi_get_instance(dip);
 598 
 599 
 600         switch (cmd) {
 601         case DDI_ATTACH:
 602                 break;
 603         case DDI_RESUME:
 604                 return (DDI_SUCCESS);
 605         default:
 606                 cmn_err(CE_WARN, "evtchn_attach: unknown cmd 0x%x\n", cmd);
 607                 return (DDI_FAILURE);
 608         }
 609 
 610         /* DDI_ATTACH */
 611 
 612         /*
 613          * only one instance - but we clone using the open routine
 614          */
 615         if (ddi_get_instance(dip) > 0)
 616                 return (DDI_FAILURE);
 617 
 618         mutex_init(&evtchndrv_clone_tab_mutex, NULL, MUTEX_DRIVER,
 619             NULL);
 620 
 621         error = ddi_create_minor_node(dip, "evtchn", S_IFCHR, unit,
 622             DDI_PSEUDO, NULL);
 623         if (error != DDI_SUCCESS)
 624                 goto fail;
 625 
 626         /*
 627          * save dip for getinfo
 628          */
 629         evtchndrv_dip = dip;
 630         ddi_report_dev(dip);
 631 
 632         mutex_init(&port_user_lock, NULL, MUTEX_DRIVER, NULL);
 633         (void) memset(port_user, 0, sizeof (port_user));
 634 
 635         ec_dev_irq = ec_dev_alloc_irq();
 636         (void) add_avintr(NULL, IPL_EVTCHN, (avfunc)evtchn_device_upcall,
 637             "evtchn_driver", ec_dev_irq, NULL, NULL, NULL, dip);
 638 
 639         return (DDI_SUCCESS);
 640 
 641 fail:
 642         (void) evtchndrv_detach(dip, DDI_DETACH);
 643         return (error);
 644 }
 645 
 646 /*ARGSUSED*/
 647 static int
 648 evtchndrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 649 {
 650         /*
 651          * Don't allow detach for now.
 652          */
 653         return (DDI_FAILURE);
 654 }
 655 
 656 /* Solaris driver framework */
 657 
 658 static  struct cb_ops evtchndrv_cb_ops = {
 659         evtchndrv_open,         /* cb_open */
 660         evtchndrv_close,        /* cb_close */
 661         nodev,                  /* cb_strategy */
 662         nodev,                  /* cb_print */
 663         nodev,                  /* cb_dump */
 664         evtchndrv_read,         /* cb_read */
 665         evtchndrv_write,        /* cb_write */
 666         evtchndrv_ioctl,        /* cb_ioctl */
 667         nodev,                  /* cb_devmap */
 668         nodev,                  /* cb_mmap */
 669         nodev,                  /* cb_segmap */
 670         evtchndrv_poll,         /* cb_chpoll */
 671         ddi_prop_op,            /* cb_prop_op */
 672         0,                      /* cb_stream */
 673         D_NEW | D_MP | D_64BIT  /* cb_flag */
 674 };
 675 
 676 static struct dev_ops evtchndrv_dev_ops = {
 677         DEVO_REV,               /* devo_rev */
 678         0,                      /* devo_refcnt */
 679         evtchndrv_info,         /* devo_getinfo */
 680         nulldev,                /* devo_identify */
 681         nulldev,                /* devo_probe */
 682         evtchndrv_attach,       /* devo_attach */
 683         evtchndrv_detach,       /* devo_detach */
 684         nodev,                  /* devo_reset */
 685         &evtchndrv_cb_ops,  /* devo_cb_ops */
 686         NULL,                   /* devo_bus_ops */
 687         NULL,                   /* power */
 688         ddi_quiesce_not_needed,         /* devo_quiesce */
 689 };
 690 
 691 static struct modldrv modldrv = {
 692         &mod_driverops,             /* Type of module.  This one is a driver */
 693         "Evtchn driver",        /* Name of the module. */
 694         &evtchndrv_dev_ops  /* driver ops */
 695 };
 696 
 697 static struct modlinkage modlinkage = {
 698         MODREV_1,
 699         { &modldrv, NULL }
 700 };
 701 
 702 int
 703 _init(void)
 704 {
 705         int err;
 706 
 707         err = ddi_soft_state_init(&evtchndrv_statep,
 708             sizeof (struct evtsoftdata), 1);
 709         if (err)
 710                 return (err);
 711 
 712         err = mod_install(&modlinkage);
 713         if (err)
 714                 ddi_soft_state_fini(&evtchndrv_statep);
 715         else
 716                 evtchndrv_clone_tab = kmem_zalloc(
 717                     sizeof (int) * evtchndrv_nclones, KM_SLEEP);
 718         return (err);
 719 }
 720 
 721 int
 722 _fini(void)
 723 {
 724         int e;
 725 
 726         e = mod_remove(&modlinkage);
 727         if (e)
 728                 return (e);
 729 
 730         ddi_soft_state_fini(&evtchndrv_statep);
 731 
 732         return (0);
 733 }
 734 
 735 int
 736 _info(struct modinfo *modinfop)
 737 {
 738         return (mod_info(&modlinkage, modinfop));
 739 }