Print this page
    
3605 Xen HVM hangs during boot if apix is enabled
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/os/ddi_intr.c
          +++ new/usr/src/uts/common/os/ddi_intr.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   */
  24   24  
  25   25  #include <sys/note.h>
  26   26  #include <sys/sysmacros.h>
  27   27  #include <sys/types.h>
  28   28  #include <sys/param.h>
  29   29  #include <sys/systm.h>
  30   30  #include <sys/kmem.h>
  31   31  #include <sys/cmn_err.h>
  32   32  #include <sys/debug.h>
  33   33  #include <sys/avintr.h>
  34   34  #include <sys/autoconf.h>
  35   35  #include <sys/sunndi.h>
  36   36  #include <sys/ndi_impldefs.h>   /* include prototypes */
  37   37  #include <sys/atomic.h>
  38   38  
  39   39  /*
  40   40   * New DDI interrupt framework
  41   41   */
  42   42  
  43   43  /*
  44   44   * ddi_intr_get_supported_types:
  45   45   *      Return, as a bit mask, the hardware interrupt types supported by
  46   46   *      both the device and by the host in the integer pointed
  47   47   *      to be the 'typesp' argument.
  48   48   */
  49   49  int
  50   50  ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
  51   51  {
  52   52          int                     ret;
  53   53          ddi_intr_handle_impl_t  hdl;
  54   54  
  55   55          if (dip == NULL)
  56   56                  return (DDI_EINVAL);
  57   57  
  58   58          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
  59   59              (void *)dip));
  60   60  
  61   61          if (*typesp = i_ddi_intr_get_supported_types(dip))
  62   62                  return (DDI_SUCCESS);
  63   63  
  64   64          bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
  65   65          hdl.ih_dip = dip;
  66   66  
  67   67          ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
  68   68              (void *)typesp);
  69   69  
  70   70          if (ret != DDI_SUCCESS)
  71   71                  return (DDI_INTR_NOTFOUND);
  72   72  
  73   73          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
  74   74              *typesp));
  75   75  
  76   76          return (ret);
  77   77  }
  78   78  
  79   79  /*
  80   80   * ddi_intr_get_nintrs:
  81   81   *      Return as an integer in the integer pointed to by the argument
  82   82   *      *nintrsp*, the number of interrupts the device supports for the
  83   83   *      given interrupt type.
  84   84   */
  85   85  int
  86   86  ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
  87   87  {
  88   88          int                     ret;
  89   89          ddi_intr_handle_impl_t  hdl;
  90   90  
  91   91          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n",
  92   92              (void *)dip, type));
  93   93  
  94   94          if ((dip == NULL) || (nintrsp == NULL) ||
  95   95              !DDI_INTR_TYPE_FLAG_VALID(type) ||
  96   96              !(i_ddi_intr_get_supported_types(dip) & type)) {
  97   97                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: "
  98   98                      "Invalid input args\n"));
  99   99                  return (DDI_EINVAL);
 100  100          }
 101  101  
 102  102          if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
 103  103                  return (DDI_SUCCESS);
 104  104  
 105  105          bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
 106  106          hdl.ih_dip = dip;
 107  107          hdl.ih_type = type;
 108  108  
 109  109          ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
 110  110              (void *)nintrsp);
 111  111  
 112  112          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
 113  113              *nintrsp));
 114  114  
 115  115          return (ret);
 116  116  }
 117  117  
 118  118  /*
 119  119   * ddi_intr_get_navail:
 120  120   *      Bus nexus driver will return availble interrupt count value for
 121  121   *      a given interrupt type.
 122  122   *
 123  123   *      Return as an integer in the integer pointed to by the argument
 124  124   *      *navailp*, the number of interrupts currently available for the
 125  125   *      given interrupt type.
 126  126   */
 127  127  int
 128  128  ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
 129  129  {
 130  130          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n",
 131  131              (void *)dip, type));
 132  132  
 133  133          if ((dip == NULL) || (navailp == NULL) ||
 134  134              !DDI_INTR_TYPE_FLAG_VALID(type) ||
 135  135              !(i_ddi_intr_get_supported_types(dip) & type)) {
 136  136                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: "
 137  137                      "Invalid input args\n"));
 138  138                  return (DDI_EINVAL);
 139  139          }
 140  140  
 141  141          if ((*navailp = i_ddi_intr_get_current_navail(dip, type)) == 0)
 142  142                  return (DDI_INTR_NOTFOUND);
 143  143  
 144  144          return (DDI_SUCCESS);
 145  145  }
 146  146  
 147  147  /*
 148  148   * Interrupt allocate/free functions
 149  149   */
 150  150  int
 151  151  ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
 152  152      int count, int *actualp, int behavior)
 153  153  {
 154  154          ddi_intr_handle_impl_t  *hdlp, tmp_hdl;
 155  155          int                     i, ret, cap = 0, curr_type, nintrs;
 156  156          uint_t                  pri, navail, curr_nintrs = 0;
 157  157  
 158  158          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
 159  159              "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
 160  160              (void *)dip, type, inum, count, behavior));
 161  161  
 162  162          /* Validate parameters */
 163  163          if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) ||
 164  164              (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) {
 165  165                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
 166  166                      "Invalid input args\n"));
 167  167                  return (DDI_EINVAL);
 168  168          }
 169  169  
 170  170          /* Validate interrupt type */
 171  171          if (!DDI_INTR_TYPE_FLAG_VALID(type) ||
 172  172              !(i_ddi_intr_get_supported_types(dip) & type)) {
 173  173                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
 174  174                      "supported\n", type));
 175  175                  return (DDI_EINVAL);
 176  176          }
 177  177  
 178  178          /* Validate inum not previously allocated */
 179  179          if ((type == DDI_INTR_TYPE_FIXED) &&
 180  180              (i_ddi_get_intr_handle(dip, inum) != NULL)) {
 181  181                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already "
 182  182                      "in use, cannot allocate again!!\n", inum));
 183  183                  return (DDI_EINVAL);
 184  184          }
 185  185  
 186  186          /* Get how many interrupts the device supports */
 187  187          if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) {
 188  188                  if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
 189  189                          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
 190  190                              "interrupts found of type %d\n", type));
 191  191                          return (DDI_INTR_NOTFOUND);
 192  192                  }
 193  193          }
 194  194  
 195  195          /* Get how many interrupts the device is already using */
 196  196          if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) {
 197  197                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
 198  198                      "is already being used\n", curr_type));
 199  199                  curr_nintrs = i_ddi_intr_get_current_nintrs(dip);
 200  200          }
 201  201  
 202  202          /* Validate interrupt type consistency */
 203  203          if ((curr_type != 0) && (type != curr_type)) {
 204  204                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
 205  205                      "interrupt type %x is different from interrupt type %x"
 206  206                      "already in use\n", type, curr_type));
 207  207                  return (DDI_EINVAL);
 208  208          }
 209  209  
 210  210          /* Validate count does not exceed what device supports */
 211  211          if (count > nintrs) {
 212  212                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
 213  213                      "requested %d is more than supported %d\n", count, nintrs));
 214  214                  return (DDI_EINVAL);
 215  215          } else if ((count + curr_nintrs) > nintrs) {
 216  216                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
 217  217                      "+ intrs in use %d exceeds supported %d intrs\n",
 218  218                      count, curr_nintrs, nintrs));
 219  219                  return (DDI_EINVAL);
 220  220          }
 221  221  
 222  222          /* Validate power of 2 requirements for MSI */
 223  223          if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) {
 224  224                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
 225  225                      "MSI count %d is not a power of two\n", count));
 226  226                  return (DDI_EINVAL);
 227  227          }
 228  228  
 229  229          /*
 230  230           * Initialize the device's interrupt information structure,
 231  231           * and establish an association with IRM if it is supported.
 232  232           *
 233  233           * NOTE: IRM checks minimum support, and can return DDI_EAGAIN.
 234  234           */
 235  235          if (curr_nintrs == 0) {
 236  236                  i_ddi_intr_devi_init(dip);
 237  237                  if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) {
 238  238                          cmn_err(CE_WARN, "ddi_intr_alloc: "
 239  239                              "cannot fit into interrupt pool\n");
 240  240                          return (DDI_EAGAIN);
 241  241                  }
 242  242          }
 243  243  
 244  244          /* Synchronously adjust IRM associations for non-IRM aware drivers */
 245  245          if (curr_nintrs && (i_ddi_irm_supported(dip, type) != DDI_SUCCESS))
 246  246                  (void) i_ddi_irm_modify(dip, count + curr_nintrs);
 247  247  
 248  248          /* Get how many interrupts are currently available */
 249  249          navail = i_ddi_intr_get_current_navail(dip, type);
 250  250  
 251  251          /* Validate that requested number of interrupts are available */
 252  252          if (curr_nintrs == navail) {
 253  253                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d "
 254  254                      "already allocated\n", navail));
 255  255                  return (DDI_EAGAIN);
 256  256          }
 257  257          if ((count + curr_nintrs) > navail) {
 258  258                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of "
 259  259                      "intrs %d exceeds # of available intrs %d\n", count,
 260  260                      navail - curr_nintrs));
 261  261                  if (behavior == DDI_INTR_ALLOC_STRICT) {
 262  262                          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
 263  263                              "DDI_INTR_ALLOC_STRICT flag is passed, "
 264  264                              "return failure\n"));
 265  265                          if (curr_nintrs == 0)
 266  266                                  i_ddi_intr_devi_fini(dip);
 267  267                          else if (i_ddi_irm_supported(dip, type) != DDI_SUCCESS)
 268  268                                  (void) i_ddi_irm_modify(dip, curr_nintrs);
 269  269                          return (DDI_EAGAIN);
 270  270                  }
  
    | 
      ↓ open down ↓ | 
    270 lines elided | 
    
      ↑ open up ↑ | 
  
 271  271                  count = navail - curr_nintrs;
 272  272          }
 273  273  
 274  274          /* Now allocate required number of interrupts */
 275  275          bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
 276  276          tmp_hdl.ih_type = type;
 277  277          tmp_hdl.ih_inum = inum;
 278  278          tmp_hdl.ih_scratch1 = count;
 279  279          tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior;
 280  280          tmp_hdl.ih_dip = dip;
      281 +        tmp_hdl.ih_irq = -1;
 281  282  
 282  283          if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC,
 283  284              &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
 284  285                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
 285  286                      "failed\n"));
 286  287                  i_ddi_intr_devi_fini(dip);
 287  288                  return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
 288  289          }
 289  290  
 290  291          if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI,
 291  292              &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
 292  293                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
 293  294                      "failed\n"));
 294  295                  goto fail;
 295  296          }
 296  297  
 297  298          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
 298  299  
 299  300          if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP,
 300  301              &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
 301  302                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
 302  303                      "failed\n"));
 303  304                  goto fail;
 304  305          }
 305  306  
 306  307          /*
 307  308           * Save current interrupt type, supported and current intr count.
 308  309           */
 309  310          i_ddi_intr_set_current_type(dip, type);
 310  311          i_ddi_intr_set_supported_nintrs(dip, nintrs);
 311  312          i_ddi_intr_set_current_nintrs(dip,
 312  313              i_ddi_intr_get_current_nintrs(dip) + *actualp);
 313  314  
 314  315          /* Now, go and handle each "handle" */
 315  316          for (i = inum; i < (inum + *actualp); i++) {
 316  317                  hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
  
    | 
      ↓ open down ↓ | 
    26 lines elided | 
    
      ↑ open up ↑ | 
  
 317  318                      (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
 318  319                  rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
 319  320                  h_array[i] = (struct __ddi_intr_handle *)hdlp;
 320  321                  hdlp->ih_type = type;
 321  322                  hdlp->ih_pri = pri;
 322  323                  hdlp->ih_cap = cap;
 323  324                  hdlp->ih_ver = DDI_INTR_VERSION;
 324  325                  hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
 325  326                  hdlp->ih_dip = dip;
 326  327                  hdlp->ih_inum = i;
      328 +                hdlp->ih_irq = -1;
 327  329                  i_ddi_alloc_intr_phdl(hdlp);
 328      -                if (type & DDI_INTR_TYPE_FIXED)
      330 +                if (type & DDI_INTR_TYPE_FIXED) {
      331 +                        if (tmp_hdl.ih_irq != -1)
      332 +                                hdlp->ih_irq = tmp_hdl.ih_irq;
 329  333                          i_ddi_set_intr_handle(dip, hdlp->ih_inum,
 330  334                              (ddi_intr_handle_t)hdlp);
      335 +                }
 331  336  
 332  337                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
 333  338                      (void *)h_array[i]));
 334  339          }
 335  340  
 336  341          return (DDI_SUCCESS);
 337  342  
 338  343  fail:
 339  344          (void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip,
 340  345              DDI_INTROP_FREE, &tmp_hdl, NULL);
 341  346          i_ddi_intr_devi_fini(dip);
 342  347  
 343  348          return (ret);
 344  349  }
 345  350  
 346  351  int
 347  352  ddi_intr_free(ddi_intr_handle_t h)
 348  353  {
 349  354          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 350  355          int                     ret;
 351  356  
 352  357          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
 353  358  
 354  359          if (hdlp == NULL)
 355  360                  return (DDI_EINVAL);
 356  361  
 357  362          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 358  363          if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) &&
 359  364              (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) ||
 360  365              ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) &&
 361  366              (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) {
 362  367                  rw_exit(&hdlp->ih_rwlock);
 363  368                  return (DDI_EINVAL);
 364  369          }
 365  370  
 366  371          /* Set the number of interrupts to free */
 367  372          hdlp->ih_scratch1 = 1;
 368  373  
 369  374          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 370  375              DDI_INTROP_FREE, hdlp, NULL);
 371  376  
 372  377          rw_exit(&hdlp->ih_rwlock);
 373  378          if (ret == DDI_SUCCESS) {
 374  379                  /* This would be the dup vector */
 375  380                  if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
 376  381                          atomic_dec_32(&hdlp->ih_main->ih_dup_cnt);
 377  382                  else {
 378  383                          int     n, curr_type;
 379  384  
 380  385                          n = i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1;
 381  386                          curr_type = i_ddi_intr_get_current_type(hdlp->ih_dip);
 382  387  
 383  388                          i_ddi_intr_set_current_nintrs(hdlp->ih_dip, n);
 384  389  
 385  390                          if ((i_ddi_irm_supported(hdlp->ih_dip, curr_type)
 386  391                              != DDI_SUCCESS) && (n > 0))
 387  392                                  (void) i_ddi_irm_modify(hdlp->ih_dip, n);
 388  393  
 389  394                          if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
 390  395                                  i_ddi_set_intr_handle(hdlp->ih_dip,
 391  396                                      hdlp->ih_inum, NULL);
 392  397  
 393  398                          i_ddi_intr_devi_fini(hdlp->ih_dip);
 394  399                          i_ddi_free_intr_phdl(hdlp);
 395  400                  }
 396  401                  rw_destroy(&hdlp->ih_rwlock);
 397  402                  kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
 398  403          }
 399  404  
 400  405          return (ret);
 401  406  }
 402  407  
 403  408  /*
 404  409   * Interrupt get/set capacity functions
 405  410   *
 406  411   * The logic used to figure this out is shown here:
 407  412   *
 408  413   *                      Device level            Platform level      Intr source
 409  414   * 1. Fixed interrupts
 410  415   * (non-PCI)
 411  416   * o Flags supported    N/A                     Maskable/Pending/    rootnex
 412  417   *                                              No Block Enable
 413  418   * o navail                                     1
 414  419   *
 415  420   * 2. PCI Fixed interrupts
 416  421   * o Flags supported    pending/Maskable        Maskable/pending/    pci
 417  422   *                                              No Block enable
 418  423   * o navail             N/A                     1
 419  424   *
 420  425   * 3. PCI MSI
 421  426   * o Flags supported    Maskable/Pending        Maskable/Pending    pci
 422  427   *                      Block Enable            (if drvr doesn't)   Block Enable
 423  428   * o navail             N/A                     #vectors - #used    N/A
 424  429   *
 425  430   * 4. PCI MSI-X
 426  431   * o Flags supported    Maskable/Pending        Maskable/Pending    pci
 427  432   *                      Block Enable                                Block Enable
 428  433   * o navail             N/A                     #vectors - #used    N/A
 429  434   *
 430  435   * where:
 431  436   *      #vectors        - Total numbers of vectors available
 432  437   *      #used           - Total numbers of vectors currently being used
 433  438   *
 434  439   * For devices complying to PCI2.3 or greater, see bit10 of Command Register
 435  440   * 0 - enables assertion of INTx
 436  441   * 1 - disables assertion of INTx
 437  442   *
 438  443   * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
 439  444   * operations return failure.
 440  445   */
 441  446  int
 442  447  ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
 443  448  {
 444  449          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 445  450          int                     ret;
 446  451  
 447  452          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
 448  453              (void *)hdlp));
 449  454  
 450  455          *flagsp = 0;
 451  456          if (hdlp == NULL)
 452  457                  return (DDI_EINVAL);
 453  458  
 454  459          rw_enter(&hdlp->ih_rwlock, RW_READER);
 455  460  
 456  461          if (hdlp->ih_cap) {
 457  462                  *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
 458  463                  rw_exit(&hdlp->ih_rwlock);
 459  464                  return (DDI_SUCCESS);
 460  465          }
 461  466  
 462  467          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 463  468              DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
 464  469  
 465  470          if (ret == DDI_SUCCESS) {
 466  471                  hdlp->ih_cap = *flagsp;
 467  472  
 468  473                  /* Mask out MSI/X 64-bit support to the consumer */
 469  474                  *flagsp &= ~DDI_INTR_FLAG_MSI64;
 470  475          }
 471  476  
 472  477          rw_exit(&hdlp->ih_rwlock);
 473  478          return (ret);
 474  479  }
 475  480  
 476  481  int
 477  482  ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
 478  483  {
 479  484          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 480  485          int                     ret;
 481  486  
 482  487          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
 483  488  
 484  489          if (hdlp == NULL)
 485  490                  return (DDI_EINVAL);
 486  491  
 487  492          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 488  493          if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
 489  494                  rw_exit(&hdlp->ih_rwlock);
 490  495                  return (DDI_EINVAL);
 491  496          }
 492  497  
 493  498          /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
 494  499          if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
 495  500                  DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
 496  501                      "can be set\n", ddi_driver_name(hdlp->ih_dip),
 497  502                      ddi_get_instance(hdlp->ih_dip)));
 498  503                  rw_exit(&hdlp->ih_rwlock);
 499  504                  return (DDI_EINVAL);
 500  505          }
 501  506  
 502  507          /* Both level/edge flags must be currently supported */
 503  508          if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
 504  509                  DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
 505  510                      " must be supported\n", ddi_driver_name(hdlp->ih_dip),
 506  511                      ddi_get_instance(hdlp->ih_dip)));
 507  512                  rw_exit(&hdlp->ih_rwlock);
 508  513                  return (DDI_ENOTSUP);
 509  514          }
 510  515  
 511  516          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 512  517              DDI_INTROP_SETCAP, hdlp, &flags);
 513  518  
 514  519          rw_exit(&hdlp->ih_rwlock);
 515  520          return (ret);
 516  521  }
 517  522  
 518  523  /*
 519  524   * Priority related functions
 520  525   */
 521  526  
 522  527  /*
 523  528   * ddi_intr_get_hilevel_pri:
 524  529   *      Returns the minimum priority level for a
 525  530   *      high-level interrupt on a platform.
 526  531   */
 527  532  uint_t
 528  533  ddi_intr_get_hilevel_pri(void)
 529  534  {
 530  535          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
 531  536          return (LOCK_LEVEL + 1);
 532  537  }
 533  538  
 534  539  int
 535  540  ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
 536  541  {
 537  542          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 538  543          int                     ret;
 539  544  
 540  545          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
 541  546              (void *)hdlp));
 542  547  
 543  548          *prip = 0;
 544  549          if (hdlp == NULL)
 545  550                  return (DDI_EINVAL);
 546  551  
 547  552          rw_enter(&hdlp->ih_rwlock, RW_READER);
 548  553          /* Already initialized, just return that */
 549  554          if (hdlp->ih_pri) {
 550  555                  *prip = hdlp->ih_pri;
 551  556                  rw_exit(&hdlp->ih_rwlock);
 552  557                  return (DDI_SUCCESS);
 553  558          }
 554  559  
 555  560          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 556  561              DDI_INTROP_GETPRI, hdlp, (void *)prip);
 557  562  
 558  563          if (ret == DDI_SUCCESS)
 559  564                  hdlp->ih_pri = *prip;
 560  565  
 561  566          rw_exit(&hdlp->ih_rwlock);
 562  567          return (ret);
 563  568  }
 564  569  
 565  570  int
 566  571  ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
 567  572  {
 568  573          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 569  574          int                     ret;
 570  575  
 571  576          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
 572  577  
 573  578          if (hdlp == NULL)
 574  579                  return (DDI_EINVAL);
 575  580  
 576  581          /* Validate priority argument */
 577  582          if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
 578  583                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
 579  584                      "specified  = %x\n", pri));
 580  585                  return (DDI_EINVAL);
 581  586          }
 582  587  
 583  588          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 584  589          if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
 585  590                  rw_exit(&hdlp->ih_rwlock);
 586  591                  return (DDI_EINVAL);
 587  592          }
 588  593  
 589  594          /* If the passed priority is same as existing priority; do nothing */
 590  595          if (pri == hdlp->ih_pri) {
 591  596                  rw_exit(&hdlp->ih_rwlock);
 592  597                  return (DDI_SUCCESS);
 593  598          }
 594  599  
 595  600          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 596  601              DDI_INTROP_SETPRI, hdlp, &pri);
 597  602  
 598  603          if (ret == DDI_SUCCESS)
 599  604                  hdlp->ih_pri = pri;
 600  605  
 601  606          rw_exit(&hdlp->ih_rwlock);
 602  607          return (ret);
 603  608  }
 604  609  
 605  610  /*
 606  611   * Interrupt add/duplicate/remove handlers
 607  612   */
 608  613  int
 609  614  ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
 610  615      void *arg1, void *arg2)
 611  616  {
 612  617          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 613  618          int                     ret;
 614  619  
 615  620          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
 616  621              (void *)hdlp));
 617  622  
 618  623          if ((hdlp == NULL) || (inthandler == NULL))
 619  624                  return (DDI_EINVAL);
 620  625  
 621  626          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 622  627          if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
 623  628                  rw_exit(&hdlp->ih_rwlock);
 624  629                  return (DDI_EINVAL);
 625  630          }
 626  631  
 627  632          hdlp->ih_cb_func = inthandler;
 628  633          hdlp->ih_cb_arg1 = arg1;
 629  634          hdlp->ih_cb_arg2 = arg2;
 630  635  
 631  636          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 632  637              DDI_INTROP_ADDISR, hdlp, NULL);
 633  638  
 634  639          if (ret != DDI_SUCCESS) {
 635  640                  hdlp->ih_cb_func = NULL;
 636  641                  hdlp->ih_cb_arg1 = NULL;
 637  642                  hdlp->ih_cb_arg2 = NULL;
 638  643          } else
 639  644                  hdlp->ih_state = DDI_IHDL_STATE_ADDED;
 640  645  
 641  646          rw_exit(&hdlp->ih_rwlock);
 642  647          return (ret);
 643  648  }
 644  649  
 645  650  int
 646  651  ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum,
 647  652      ddi_intr_handle_t *dup)
 648  653  {
 649  654          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)org;
 650  655          ddi_intr_handle_impl_t  *dup_hdlp;
 651  656          int                     ret;
 652  657  
 653  658          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
 654  659              (void *)hdlp));
 655  660  
 656  661          /* Do some input argument checking ("dup" handle is not allocated) */
 657  662          if ((hdlp == NULL) || (*dup != NULL) || (dup_inum < 0)) {
 658  663                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: Invalid "
 659  664                      "input args\n"));
 660  665                  return (DDI_EINVAL);
 661  666          }
 662  667  
 663  668          rw_enter(&hdlp->ih_rwlock, RW_READER);
 664  669  
 665  670          /* Do some input argument checking */
 666  671          if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */
 667  672              (hdlp->ih_type != DDI_INTR_TYPE_MSIX) ||    /* only MSI-X allowed */
 668  673              (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) {     /* only dup original */
 669  674                  rw_exit(&hdlp->ih_rwlock);
 670  675                  return (DDI_EINVAL);
 671  676          }
 672  677  
 673  678          hdlp->ih_scratch1 = dup_inum;
 674  679          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 675  680              DDI_INTROP_DUPVEC, hdlp, NULL);
 676  681  
 677  682          if (ret == DDI_SUCCESS) {
 678  683                  dup_hdlp = (ddi_intr_handle_impl_t *)
 679  684                      kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
 680  685  
 681  686                  atomic_inc_32(&hdlp->ih_dup_cnt);
 682  687  
 683  688                  *dup = (ddi_intr_handle_t)dup_hdlp;
 684  689                  bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t));
 685  690  
 686  691                  /* These fields are unique to each dupped msi-x vector */
 687  692                  rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
 688  693                  dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
 689  694                  dup_hdlp->ih_inum = dup_inum;
 690  695                  dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP;
 691  696                  dup_hdlp->ih_dup_cnt = 0;
 692  697  
 693  698                  /* Point back to original vector */
 694  699                  dup_hdlp->ih_main = hdlp;
 695  700          }
 696  701  
 697  702          rw_exit(&hdlp->ih_rwlock);
 698  703          return (ret);
 699  704  }
 700  705  
 701  706  int
 702  707  ddi_intr_remove_handler(ddi_intr_handle_t h)
 703  708  {
 704  709          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 705  710          int                     ret = DDI_SUCCESS;
 706  711  
 707  712          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
 708  713              (void *)hdlp));
 709  714  
 710  715          if (hdlp == NULL)
 711  716                  return (DDI_EINVAL);
 712  717  
 713  718          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 714  719  
 715  720          if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
 716  721                  ret = DDI_EINVAL;
 717  722                  goto done;
 718  723          } else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
 719  724                  goto done;
 720  725  
 721  726          ASSERT(hdlp->ih_dup_cnt == 0);
 722  727          if (hdlp->ih_dup_cnt > 0) {
 723  728                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X "
 724  729                      "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt));
 725  730                  ret = DDI_FAILURE;
 726  731                  goto done;
 727  732          }
 728  733  
 729  734          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 730  735              DDI_INTROP_REMISR, hdlp, NULL);
 731  736  
 732  737          if (ret == DDI_SUCCESS) {
 733  738                  hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
 734  739                  hdlp->ih_cb_func = NULL;
 735  740                  hdlp->ih_cb_arg1 = NULL;
 736  741                  hdlp->ih_cb_arg2 = NULL;
 737  742          }
 738  743  
 739  744  done:
 740  745          rw_exit(&hdlp->ih_rwlock);
 741  746          return (ret);
 742  747  }
 743  748  
 744  749  
 745  750  /*
 746  751   * Interrupt enable/disable/block_enable/block_disable handlers
 747  752   */
 748  753  int
 749  754  ddi_intr_enable(ddi_intr_handle_t h)
 750  755  {
 751  756          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 752  757          int                     ret;
 753  758  
 754  759          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
 755  760              (void *)hdlp));
 756  761  
 757  762          if (hdlp == NULL)
 758  763                  return (DDI_EINVAL);
 759  764  
 760  765          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 761  766          if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
 762  767              ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
 763  768              (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
 764  769                  rw_exit(&hdlp->ih_rwlock);
 765  770                  return (DDI_EINVAL);
 766  771          }
 767  772  
 768  773          I_DDI_VERIFY_MSIX_HANDLE(hdlp);
 769  774  
 770  775          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 771  776              DDI_INTROP_ENABLE, hdlp, NULL);
 772  777  
 773  778          if (ret == DDI_SUCCESS) {
 774  779                  hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
 775  780                  i_ddi_intr_set_current_nenables(hdlp->ih_dip,
 776  781                      i_ddi_intr_get_current_nenables(hdlp->ih_dip) + 1);
 777  782          }
 778  783  
 779  784          rw_exit(&hdlp->ih_rwlock);
 780  785          return (ret);
 781  786  }
 782  787  
 783  788  int
 784  789  ddi_intr_disable(ddi_intr_handle_t h)
 785  790  {
 786  791          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 787  792          int                     ret;
 788  793  
 789  794          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
 790  795              (void *)hdlp));
 791  796  
 792  797          if (hdlp == NULL)
 793  798                  return (DDI_EINVAL);
 794  799  
 795  800          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 796  801          if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
 797  802              ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
 798  803              (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
 799  804                  rw_exit(&hdlp->ih_rwlock);
 800  805                  return (DDI_EINVAL);
 801  806          }
 802  807  
 803  808          I_DDI_VERIFY_MSIX_HANDLE(hdlp);
 804  809  
 805  810          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 806  811              DDI_INTROP_DISABLE, hdlp, NULL);
 807  812  
 808  813          if (ret == DDI_SUCCESS) {
 809  814                  hdlp->ih_state = DDI_IHDL_STATE_ADDED;
 810  815                  i_ddi_intr_set_current_nenables(hdlp->ih_dip,
 811  816                      i_ddi_intr_get_current_nenables(hdlp->ih_dip) - 1);
 812  817          }
 813  818  
 814  819          rw_exit(&hdlp->ih_rwlock);
 815  820          return (ret);
 816  821  }
 817  822  
 818  823  int
 819  824  ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
 820  825  {
 821  826          ddi_intr_handle_impl_t  *hdlp;
 822  827          int                     i, ret;
 823  828  
 824  829          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
 825  830              (void *)h_array));
 826  831  
 827  832          if (h_array == NULL)
 828  833                  return (DDI_EINVAL);
 829  834  
 830  835          for (i = 0; i < count; i++) {
 831  836                  hdlp = (ddi_intr_handle_impl_t *)h_array[i];
 832  837                  rw_enter(&hdlp->ih_rwlock, RW_READER);
 833  838  
 834  839                  if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
 835  840                      hdlp->ih_type != DDI_INTR_TYPE_MSI ||
 836  841                      !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
 837  842                          rw_exit(&hdlp->ih_rwlock);
 838  843                          return (DDI_EINVAL);
 839  844                  }
 840  845                  rw_exit(&hdlp->ih_rwlock);
 841  846          }
 842  847  
 843  848          hdlp = (ddi_intr_handle_impl_t *)h_array[0];
 844  849          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 845  850          hdlp->ih_scratch1 = count;
 846  851          hdlp->ih_scratch2 = (void *)h_array;
 847  852  
 848  853          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 849  854              DDI_INTROP_BLOCKENABLE, hdlp, NULL);
 850  855  
 851  856          rw_exit(&hdlp->ih_rwlock);
 852  857  
 853  858          if (ret == DDI_SUCCESS) {
 854  859                  for (i = 0; i < count; i++) {
 855  860                          hdlp = (ddi_intr_handle_impl_t *)h_array[i];
 856  861                          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 857  862                          hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
 858  863                          rw_exit(&hdlp->ih_rwlock);
 859  864                  }
 860  865                  i_ddi_intr_set_current_nenables(hdlp->ih_dip, 1);
 861  866          }
 862  867  
 863  868          return (ret);
 864  869  }
 865  870  
 866  871  int
 867  872  ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
 868  873  {
 869  874          ddi_intr_handle_impl_t  *hdlp;
 870  875          int                     i, ret;
 871  876  
 872  877          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
 873  878              (void *)h_array));
 874  879  
 875  880          if (h_array == NULL)
 876  881                  return (DDI_EINVAL);
 877  882  
 878  883          for (i = 0; i < count; i++) {
 879  884                  hdlp = (ddi_intr_handle_impl_t *)h_array[i];
 880  885                  rw_enter(&hdlp->ih_rwlock, RW_READER);
 881  886                  if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
 882  887                      hdlp->ih_type != DDI_INTR_TYPE_MSI ||
 883  888                      !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
 884  889                          rw_exit(&hdlp->ih_rwlock);
 885  890                          return (DDI_EINVAL);
 886  891                  }
 887  892                  rw_exit(&hdlp->ih_rwlock);
 888  893          }
 889  894  
 890  895          hdlp = (ddi_intr_handle_impl_t *)h_array[0];
 891  896          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 892  897          hdlp->ih_scratch1 = count;
 893  898          hdlp->ih_scratch2 = (void *)h_array;
 894  899  
 895  900          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 896  901              DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
 897  902  
 898  903          rw_exit(&hdlp->ih_rwlock);
 899  904  
 900  905          if (ret == DDI_SUCCESS) {
 901  906                  for (i = 0; i < count; i++) {
 902  907                          hdlp = (ddi_intr_handle_impl_t *)h_array[i];
 903  908                          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 904  909                          hdlp->ih_state = DDI_IHDL_STATE_ADDED;
 905  910                          rw_exit(&hdlp->ih_rwlock);
 906  911                  }
 907  912                  i_ddi_intr_set_current_nenables(hdlp->ih_dip, 0);
 908  913          }
 909  914  
 910  915          return (ret);
 911  916  }
 912  917  
 913  918  /*
 914  919   * Interrupt set/clr mask handlers
 915  920   */
 916  921  int
 917  922  ddi_intr_set_mask(ddi_intr_handle_t h)
 918  923  {
 919  924          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 920  925          int                     ret;
 921  926  
 922  927          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
 923  928              (void *)hdlp));
 924  929  
 925  930          if (hdlp == NULL)
 926  931                  return (DDI_EINVAL);
 927  932  
 928  933          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 929  934          if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
 930  935              (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
 931  936                  rw_exit(&hdlp->ih_rwlock);
 932  937                  return (DDI_EINVAL);
 933  938          }
 934  939  
 935  940          ret =  i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 936  941              DDI_INTROP_SETMASK, hdlp, NULL);
 937  942  
 938  943          rw_exit(&hdlp->ih_rwlock);
 939  944          return (ret);
 940  945  }
 941  946  
 942  947  int
 943  948  ddi_intr_clr_mask(ddi_intr_handle_t h)
 944  949  {
 945  950          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 946  951          int                     ret;
 947  952  
 948  953          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
 949  954              (void *)hdlp));
 950  955  
 951  956          if (hdlp == NULL)
 952  957                  return (DDI_EINVAL);
 953  958  
 954  959          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
 955  960          if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
 956  961              (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
 957  962                  rw_exit(&hdlp->ih_rwlock);
 958  963                  return (DDI_EINVAL);
 959  964          }
 960  965  
 961  966          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 962  967              DDI_INTROP_CLRMASK, hdlp, NULL);
 963  968  
 964  969          rw_exit(&hdlp->ih_rwlock);
 965  970          return (ret);
 966  971  }
 967  972  
 968  973  /*
 969  974   * Interrupt get_pending handler
 970  975   */
 971  976  int
 972  977  ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
 973  978  {
 974  979          ddi_intr_handle_impl_t  *hdlp = (ddi_intr_handle_impl_t *)h;
 975  980          int                     ret;
 976  981  
 977  982          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
 978  983              (void *)hdlp));
 979  984  
 980  985          if (hdlp == NULL)
 981  986                  return (DDI_EINVAL);
 982  987  
 983  988          rw_enter(&hdlp->ih_rwlock, RW_READER);
 984  989          if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
 985  990                  rw_exit(&hdlp->ih_rwlock);
 986  991                  return (DDI_EINVAL);
 987  992          }
 988  993  
 989  994          ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 990  995              DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
 991  996  
 992  997          rw_exit(&hdlp->ih_rwlock);
 993  998          return (ret);
 994  999  }
 995 1000  
 996 1001  /*
 997 1002   * Set the number of interrupts requested from IRM
 998 1003   */
 999 1004  int
1000 1005  ddi_intr_set_nreq(dev_info_t *dip, int nreq)
1001 1006  {
1002 1007          int     curr_type, nintrs;
1003 1008  
1004 1009          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_nreq: dip %p, nreq %d\n",
1005 1010              (void *)dip, nreq));
1006 1011  
1007 1012          ASSERT(dip != NULL);
1008 1013          ASSERT(nreq > 0);
1009 1014  
1010 1015          /* Sanity check inputs */
1011 1016          if ((dip == NULL) || (nreq < 1))
1012 1017                  return (DDI_EINVAL);
1013 1018  
1014 1019          curr_type = i_ddi_intr_get_current_type(dip);
1015 1020  
1016 1021          /* Only valid for IRM drivers actively using interrupts */
1017 1022          if ((curr_type == 0) ||
1018 1023              (i_ddi_irm_supported(dip, curr_type) != DDI_SUCCESS))
1019 1024                  return (DDI_ENOTSUP);
1020 1025  
1021 1026          /* Range check */
1022 1027          if (ddi_intr_get_nintrs(dip, curr_type, &nintrs) != DDI_SUCCESS)
1023 1028                  return (DDI_FAILURE);
1024 1029          if (nreq > nintrs)
1025 1030                  return (DDI_EINVAL);
1026 1031  
1027 1032          return (i_ddi_irm_modify(dip, nreq));
1028 1033  }
1029 1034  
1030 1035  /*
1031 1036   * Soft interrupt handlers
1032 1037   */
1033 1038  /*
1034 1039   * Add a soft interrupt and register its handler
1035 1040   */
1036 1041  /* ARGSUSED */
1037 1042  int
1038 1043  ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
1039 1044      ddi_intr_handler_t handler, void *arg1)
1040 1045  {
1041 1046          ddi_softint_hdl_impl_t  *hdlp;
1042 1047          int                     ret;
1043 1048  
1044 1049          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
1045 1050              "softpri = 0x%x\n", (void *)dip, soft_pri));
1046 1051  
1047 1052          if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
1048 1053                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
1049 1054                      "invalid arguments"));
1050 1055  
1051 1056                  return (DDI_EINVAL);
1052 1057          }
1053 1058  
1054 1059          /* Validate input arguments */
1055 1060          if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
1056 1061              soft_pri > DDI_INTR_SOFTPRI_MAX) {
1057 1062                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
1058 1063                      "soft_pri input given  = %x\n", soft_pri));
1059 1064                  return (DDI_EINVAL);
1060 1065          }
1061 1066  
1062 1067          hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
1063 1068              sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
1064 1069  
1065 1070          /* fill up internally */
1066 1071          rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
1067 1072          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1068 1073          hdlp->ih_pri = soft_pri;
1069 1074          hdlp->ih_dip = dip;
1070 1075          hdlp->ih_cb_func = handler;
1071 1076          hdlp->ih_cb_arg1 = arg1;
1072 1077          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
1073 1078              (void *)hdlp));
1074 1079  
1075 1080          /* do the platform specific calls */
1076 1081          if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
1077 1082                  rw_exit(&hdlp->ih_rwlock);
1078 1083                  rw_destroy(&hdlp->ih_rwlock);
1079 1084                  kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
1080 1085                  return (ret);
1081 1086          }
1082 1087  
1083 1088          *h_p = (ddi_softint_handle_t)hdlp;
1084 1089          rw_exit(&hdlp->ih_rwlock);
1085 1090          return (ret);
1086 1091  }
1087 1092  
1088 1093  /*
1089 1094   * Remove the soft interrupt
1090 1095   */
1091 1096  int
1092 1097  ddi_intr_remove_softint(ddi_softint_handle_t h)
1093 1098  {
1094 1099          ddi_softint_hdl_impl_t  *hdlp = (ddi_softint_hdl_impl_t *)h;
1095 1100  
1096 1101          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
1097 1102              (void *)hdlp));
1098 1103  
1099 1104          if (hdlp == NULL)
1100 1105                  return (DDI_EINVAL);
1101 1106  
1102 1107          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1103 1108          i_ddi_remove_softint(hdlp);
1104 1109          rw_exit(&hdlp->ih_rwlock);
1105 1110          rw_destroy(&hdlp->ih_rwlock);
1106 1111  
1107 1112          /* kmem_free the hdl impl_t structure allocated earlier */
1108 1113          kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
1109 1114          return (DDI_SUCCESS);
1110 1115  }
1111 1116  
1112 1117  /*
1113 1118   * Trigger a soft interrupt
1114 1119   */
1115 1120  int
1116 1121  ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
1117 1122  {
1118 1123          ddi_softint_hdl_impl_t  *hdlp = (ddi_softint_hdl_impl_t *)h;
1119 1124          int                     ret;
1120 1125  
1121 1126          if (hdlp == NULL)
1122 1127                  return (DDI_EINVAL);
1123 1128  
1124 1129          if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) {
1125 1130                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
1126 1131                      " ret 0%x\n", ret));
1127 1132  
1128 1133                  return (ret);
1129 1134          }
1130 1135  
1131 1136          hdlp->ih_cb_arg2 = arg2;
1132 1137          return (DDI_SUCCESS);
1133 1138  }
1134 1139  
1135 1140  /*
1136 1141   * Get the soft interrupt priority
1137 1142   */
1138 1143  int
1139 1144  ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
1140 1145  {
1141 1146          ddi_softint_hdl_impl_t  *hdlp = (ddi_softint_hdl_impl_t *)h;
1142 1147  
1143 1148          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
1144 1149              (void *)h));
1145 1150  
1146 1151          if (hdlp == NULL)
1147 1152                  return (DDI_EINVAL);
1148 1153  
1149 1154          rw_enter(&hdlp->ih_rwlock, RW_READER);
1150 1155          *soft_prip = hdlp->ih_pri;
1151 1156          rw_exit(&hdlp->ih_rwlock);
1152 1157          return (DDI_SUCCESS);
1153 1158  }
1154 1159  
1155 1160  /*
1156 1161   * Set the soft interrupt priority
1157 1162   */
1158 1163  int
1159 1164  ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
1160 1165  {
1161 1166          ddi_softint_hdl_impl_t  *hdlp = (ddi_softint_hdl_impl_t *)h;
1162 1167          int                     ret;
1163 1168          uint_t                  orig_soft_pri;
1164 1169  
1165 1170          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
1166 1171              (void *)h));
1167 1172  
1168 1173          if (hdlp == NULL)
1169 1174                  return (DDI_EINVAL);
1170 1175  
1171 1176          /* Validate priority argument */
1172 1177          if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
1173 1178              soft_pri > DDI_INTR_SOFTPRI_MAX) {
1174 1179                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
1175 1180                      "soft_pri input given  = %x\n", soft_pri));
1176 1181                  return (DDI_EINVAL);
1177 1182          }
1178 1183  
1179 1184          rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1180 1185          orig_soft_pri = hdlp->ih_pri;
1181 1186          hdlp->ih_pri = soft_pri;
1182 1187  
1183 1188          if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
1184 1189                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
1185 1190                      " ret 0%x\n", ret));
1186 1191                  hdlp->ih_pri = orig_soft_pri;
1187 1192          }
1188 1193  
1189 1194          rw_exit(&hdlp->ih_rwlock);
1190 1195          return (ret);
1191 1196  }
1192 1197  
1193 1198  /*
1194 1199   * Old DDI interrupt framework
1195 1200   *
1196 1201   * The following DDI interrupt interfaces are obsolete.
1197 1202   * Use the above new DDI interrupt interfaces instead.
1198 1203   */
1199 1204  
1200 1205  int
1201 1206  ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
1202 1207  {
1203 1208          ddi_intr_handle_t       hdl;
1204 1209          ddi_intr_handle_t       *hdl_p;
1205 1210          size_t                  hdl_sz = 0;
1206 1211          int                     actual, ret;
1207 1212          uint_t                  high_pri, pri;
1208 1213  
1209 1214          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
1210 1215              "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1211 1216              (void *)dip, inumber));
1212 1217  
1213 1218          /*
1214 1219           * The device driver may have already registed with the
1215 1220           * framework. If so, first try to get the existing interrupt handle
1216 1221           * for that given inumber and use that handle.
1217 1222           */
1218 1223          if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
1219 1224                  hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
1220 1225                  hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
1221 1226                  if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1222 1227                      inumber, 1, &actual,
1223 1228                      DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
1224 1229                          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
1225 1230                              "ddi_intr_alloc failed, ret 0x%x\n", ret));
1226 1231                          kmem_free(hdl_p, hdl_sz);
1227 1232                          return (0);
1228 1233                  }
1229 1234                  hdl = hdl_p[inumber];
1230 1235          }
1231 1236  
1232 1237          if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
1233 1238                  DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
1234 1239                      "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1235 1240                  (void) ddi_intr_free(hdl);
1236 1241                  if (hdl_sz)
1237 1242                          kmem_free(hdl_p, hdl_sz);
1238 1243                  return (0);
1239 1244          }
1240 1245  
1241 1246          high_pri = ddi_intr_get_hilevel_pri();
1242 1247  
1243 1248          DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
1244 1249              "high_pri = %x\n", pri, high_pri));
1245 1250  
1246 1251          /* Free the handle allocated here only if no existing handle exists */
1247 1252          if (hdl_sz) {
1248 1253                  (void) ddi_intr_free(hdl);
1249 1254                  kmem_free(hdl_p, hdl_sz);
1250 1255          }
1251 1256  
1252 1257          return (pri >= high_pri);
1253 1258  }
1254 1259  
1255 1260  int
1256 1261  ddi_dev_nintrs(dev_info_t *dip, int *result)
1257 1262  {
1258 1263          DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
1259 1264              ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
1260 1265  
1261 1266          if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
1262 1267              result) != DDI_SUCCESS) {
1263 1268                  DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
1264 1269                      "ddi_intr_get_nintrs failed\n"));
1265 1270                  *result = 0;
1266 1271          }
1267 1272  
1268 1273          return (DDI_SUCCESS);
1269 1274  }
1270 1275  
1271 1276  int
1272 1277  ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
1273 1278      ddi_iblock_cookie_t *iblock_cookiep)
1274 1279  {
1275 1280          ddi_intr_handle_t       hdl;
1276 1281          ddi_intr_handle_t       *hdl_p;
1277 1282          size_t                  hdl_sz = 0;
1278 1283          int                     actual, ret;
1279 1284          uint_t                  pri;
1280 1285  
1281 1286          DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
1282 1287              "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1283 1288              (void *)dip, inumber));
1284 1289  
1285 1290          ASSERT(iblock_cookiep != NULL);
1286 1291  
1287 1292          /*
1288 1293           * The device driver may have already registed with the
1289 1294           * framework. If so, first try to get the existing interrupt handle
1290 1295           * for that given inumber and use that handle.
1291 1296           */
1292 1297          if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
1293 1298                  hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
1294 1299                  hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
1295 1300                  if ((ret = ddi_intr_alloc(dip, hdl_p,
1296 1301                      DDI_INTR_TYPE_FIXED, inumber, 1, &actual,
1297 1302                      DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
1298 1303                          DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
1299 1304                              "ddi_intr_alloc failed, ret 0x%x\n", ret));
1300 1305                          kmem_free(hdl_p, hdl_sz);
1301 1306                          return (DDI_INTR_NOTFOUND);
1302 1307                  }
1303 1308                  hdl = hdl_p[inumber];
1304 1309          }
1305 1310  
1306 1311          if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
1307 1312                  DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
1308 1313                      "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1309 1314                  (void) ddi_intr_free(hdl);
1310 1315                  if (hdl_sz)
1311 1316                          kmem_free(hdl_p, hdl_sz);
1312 1317                  return (DDI_FAILURE);
1313 1318          }
1314 1319  
1315 1320          *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
1316 1321          /* Free the handle allocated here only if no existing handle exists */
1317 1322          if (hdl_sz) {
1318 1323                  (void) ddi_intr_free(hdl);
1319 1324                  kmem_free(hdl_p, hdl_sz);
1320 1325          }
1321 1326  
1322 1327          return (DDI_SUCCESS);
1323 1328  }
1324 1329  
1325 1330  int
1326 1331  ddi_add_intr(dev_info_t *dip, uint_t inumber,
1327 1332      ddi_iblock_cookie_t *iblock_cookiep,
1328 1333      ddi_idevice_cookie_t *idevice_cookiep,
1329 1334      uint_t (*int_handler)(caddr_t int_handler_arg),
1330 1335      caddr_t int_handler_arg)
1331 1336  {
1332 1337          ddi_intr_handle_t       *hdl_p;
1333 1338          size_t                  hdl_sz;
1334 1339          int                     actual, ret;
1335 1340          uint_t                  pri;
1336 1341  
1337 1342          DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
1338 1343              "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1339 1344              (void *)dip, inumber));
1340 1345  
1341 1346          hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
1342 1347          hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
1343 1348  
1344 1349          if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1345 1350              inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
1346 1351                  DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1347 1352                      "ddi_intr_alloc failed, ret 0x%x\n", ret));
1348 1353                  kmem_free(hdl_p, hdl_sz);
1349 1354                  return (DDI_INTR_NOTFOUND);
1350 1355          }
1351 1356  
1352 1357          if ((ret = ddi_intr_get_pri(hdl_p[inumber], &pri)) != DDI_SUCCESS)  {
1353 1358                  DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1354 1359                      "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1355 1360                  (void) ddi_intr_free(hdl_p[inumber]);
1356 1361                  kmem_free(hdl_p, hdl_sz);
1357 1362                  return (DDI_FAILURE);
1358 1363          }
1359 1364  
1360 1365          if ((ret = ddi_intr_add_handler(hdl_p[inumber], (ddi_intr_handler_t *)
1361 1366              int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
1362 1367                  DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1363 1368                      "ddi_intr_add_handler failed, ret 0x%x\n", ret));
1364 1369                  (void) ddi_intr_free(hdl_p[inumber]);
1365 1370                  kmem_free(hdl_p, hdl_sz);
1366 1371                  return (DDI_FAILURE);
1367 1372          }
1368 1373  
1369 1374          if ((ret = ddi_intr_enable(hdl_p[inumber])) != DDI_SUCCESS) {
1370 1375                  DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1371 1376                      "ddi_intr_enable failed, ret 0x%x\n", ret));
1372 1377                  (void) ddi_intr_remove_handler(hdl_p[inumber]);
1373 1378                  (void) ddi_intr_free(hdl_p[inumber]);
1374 1379                  kmem_free(hdl_p, hdl_sz);
1375 1380                  return (DDI_FAILURE);
1376 1381          }
1377 1382  
1378 1383          if (iblock_cookiep)
1379 1384                  *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
1380 1385  
1381 1386          if (idevice_cookiep) {
1382 1387                  idevice_cookiep->idev_vector = 0;
1383 1388                  idevice_cookiep->idev_priority = pri;
1384 1389          }
1385 1390  
1386 1391          kmem_free(hdl_p, hdl_sz);
1387 1392  
1388 1393          return (DDI_SUCCESS);
1389 1394  }
1390 1395  
1391 1396  /* ARGSUSED */
1392 1397  int
1393 1398  ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
1394 1399      ddi_iblock_cookie_t *iblock_cookiep,
1395 1400      ddi_idevice_cookie_t *idevice_cookiep,
1396 1401      uint_t (*hi_int_handler)(void))
1397 1402  {
1398 1403          DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
1399 1404              "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
1400 1405              ddi_get_instance(dip), (void *)dip, inumber));
1401 1406  
1402 1407          return (DDI_FAILURE);
1403 1408  }
1404 1409  
1405 1410  /* ARGSUSED */
1406 1411  void
1407 1412  ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
1408 1413  {
1409 1414          ddi_intr_handle_t       hdl;
1410 1415          int                     ret;
1411 1416  
1412 1417          DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
1413 1418              "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1414 1419              (void *)dip, inum));
1415 1420  
1416 1421          if ((hdl = i_ddi_get_intr_handle(dip, inum)) == NULL) {
1417 1422                  DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
1418 1423                      "found\n"));
1419 1424                  return;
1420 1425          }
1421 1426  
1422 1427          if ((ret = ddi_intr_disable(hdl)) != DDI_SUCCESS) {
1423 1428                  DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1424 1429                      "ddi_intr_disable failed, ret 0x%x\n", ret));
1425 1430                  return;
1426 1431          }
1427 1432  
1428 1433          if ((ret = ddi_intr_remove_handler(hdl)) != DDI_SUCCESS) {
1429 1434                  DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1430 1435                      "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
1431 1436                  return;
1432 1437          }
1433 1438  
1434 1439          if ((ret = ddi_intr_free(hdl)) != DDI_SUCCESS) {
1435 1440                  DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1436 1441                      "ddi_intr_free failed, ret 0x%x\n", ret));
1437 1442                  return;
1438 1443          }
1439 1444  }
1440 1445  
1441 1446  /* ARGSUSED */
1442 1447  int
1443 1448  ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
1444 1449      ddi_iblock_cookie_t *iblock_cookiep)
1445 1450  {
1446 1451          DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
1447 1452              "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1448 1453              (void *)dip, preference));
1449 1454  
1450 1455          ASSERT(iblock_cookiep != NULL);
1451 1456  
1452 1457          if (preference == DDI_SOFTINT_FIXED)
1453 1458                  return (DDI_FAILURE);
1454 1459  
1455 1460          *iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t)
1456 1461              ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
1457 1462              DDI_SOFT_INTR_PRI_M));
1458 1463  
1459 1464          return (DDI_SUCCESS);
1460 1465  }
1461 1466  
1462 1467  int
1463 1468  ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
1464 1469      ddi_iblock_cookie_t *iblock_cookiep,
1465 1470      ddi_idevice_cookie_t *idevice_cookiep,
1466 1471      uint_t (*int_handler)(caddr_t int_handler_arg),
1467 1472      caddr_t int_handler_arg)
1468 1473  {
1469 1474          ddi_softint_handle_t    *hdl_p;
1470 1475          uint64_t                softpri;
1471 1476          int                     ret;
1472 1477  
1473 1478          DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
1474 1479              "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1475 1480              (void *)dip, preference));
1476 1481  
1477 1482          if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
1478 1483              (iblock_cookiep == NULL)))
1479 1484                  return (DDI_FAILURE);
1480 1485  
1481 1486          /* Translate the priority preference */
1482 1487          if (preference == DDI_SOFTINT_FIXED) {
1483 1488                  softpri = (uint64_t)(uintptr_t)*iblock_cookiep;
1484 1489                  softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
1485 1490          } else {
1486 1491                  softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
1487 1492                      DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
1488 1493          }
1489 1494  
1490 1495          DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
1491 1496              "softpri 0x%lx\n", preference, (long)softpri));
1492 1497  
1493 1498          hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
1494 1499          if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
1495 1500              (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
1496 1501              DDI_SUCCESS) {
1497 1502                  DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
1498 1503                      "ddi_intr_add_softint failed, ret 0x%x\n", ret));
1499 1504  
1500 1505                  kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
1501 1506                  return (DDI_FAILURE);
1502 1507          }
1503 1508  
1504 1509          if (iblock_cookiep)
1505 1510                  *iblock_cookiep =  (ddi_iblock_cookie_t)(uintptr_t)softpri;
1506 1511  
1507 1512          if (idevice_cookiep) {
1508 1513                  idevice_cookiep->idev_vector = 0;
1509 1514                  idevice_cookiep->idev_priority = softpri;
1510 1515          }
1511 1516  
1512 1517          *idp = (ddi_softintr_t)hdl_p;
1513 1518  
1514 1519          DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
1515 1520              "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
1516 1521  
1517 1522          return (DDI_SUCCESS);
1518 1523  }
1519 1524  
1520 1525  void
1521 1526  ddi_remove_softintr(ddi_softintr_t id)
1522 1527  {
1523 1528          ddi_softint_handle_t    *h_p = (ddi_softint_handle_t *)id;
1524 1529  
1525 1530          DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
1526 1531              (void *)id));
1527 1532  
1528 1533          if (h_p == NULL)
1529 1534                  return;
1530 1535  
1531 1536          DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
1532 1537              (void *)h_p));
1533 1538  
1534 1539          (void) ddi_intr_remove_softint(*h_p);
1535 1540          kmem_free(h_p, sizeof (ddi_softint_handle_t));
1536 1541  }
1537 1542  
1538 1543  void
1539 1544  ddi_trigger_softintr(ddi_softintr_t id)
1540 1545  {
1541 1546          ddi_softint_handle_t    *h_p = (ddi_softint_handle_t *)id;
1542 1547          int                     ret;
1543 1548  
1544 1549          if (h_p == NULL)
1545 1550                  return;
1546 1551  
1547 1552          if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
1548 1553                  DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
1549 1554                      "ddi_intr_trigger_softint failed, hdlp 0x%p "
1550 1555                      "ret 0x%x\n", (void *)h_p, ret));
1551 1556          }
1552 1557  }
  
    | 
      ↓ open down ↓ | 
    1212 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX