Print this page
    
NEX-1890 update oce from source provided by Emulex
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/fibre-channel/fca/oce/oce_intr.c
          +++ new/usr/src/uts/common/io/fibre-channel/fca/oce/oce_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.
  
    | 
      ↓ open down ↓ | 
    11 lines elided | 
    
      ↑ open up ↑ | 
  
  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      -/* Copyright © 2003-2011 Emulex. All rights reserved.  */
       22 +/*
       23 + * Copyright (c) 2009-2012 Emulex. All rights reserved.
       24 + * Use is subject to license terms.
       25 + */
  23   26  
       27 +
       28 +
  24   29  /*
  25   30   * Source file interrupt registration
  26   31   * and related helper functions
  27   32   */
  28   33  
  29   34  #include <oce_impl.h>
  30   35  
  31      -
  32   36  static uint_t oce_isr(caddr_t arg1, caddr_t arg2);
       37 +static int
       38 +oce_adjust_intrs(struct oce_dev *dev, ddi_cb_action_t action, int count);
  33   39  
  34   40  /*
  35   41   * top level function to setup interrupts
  36   42   *
  37   43   * dev - software handle to the device
  38   44   *
  39   45   * return DDI_SUCCESS => success, failure otherwise
  40   46   */
  41   47  int
  42   48  oce_setup_intr(struct oce_dev *dev)
  43   49  {
  44      -        int ret;
       50 +        int ret, i;
  45   51          int intr_types = 0;
  46   52          int navail = 0;
  47   53          int nsupported = 0;
  48   54          int min = 0;
  49   55          int nreqd = 0;
  50   56          int nallocd = 0;
       57 +        extern int oce_irm_enable;
  51   58  
  52   59          /* get supported intr types */
  53   60          ret = ddi_intr_get_supported_types(dev->dip, &intr_types);
  54   61          if (ret != DDI_SUCCESS) {
  55      -                oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
  56      -                    "Failed to retrieve intr types ");
       62 +                oce_log(dev, CE_WARN, MOD_CONFIG,
       63 +                    "Failed to retrieve intr types 0x%x", ret);
  57   64                  return (DDI_FAILURE);
  58   65          }
  59   66  
       67 +        dev->rx_rings = min(dev->rx_rings, ncpus + dev->rss_cnt);
       68 +        dev->tx_rings = min(dev->tx_rings, ncpus);
       69 +#ifdef __sparc
       70 +        nreqd = min(dev->tx_rings + dev->rx_rings - dev->rss_cnt, ncpus);
       71 +        dev->rx_group[0].eq_idx = dev->tx_rings;
       72 +#else
       73 +        nreqd = max(dev->tx_rings, dev->rx_rings - dev->rss_cnt);
       74 +#endif
       75 +        min  = OCE_MIN_VECTORS;
       76 +
  60   77  retry_intr:
       78 +
  61   79          if (intr_types & DDI_INTR_TYPE_MSIX) {
  62   80                  dev->intr_type = DDI_INTR_TYPE_MSIX;
  63      -                /* one vector is shared by MCC and Tx */
  64      -                nreqd = dev->rx_rings + 1;
  65      -                min = OCE_MIN_VECTORS;
  66      -        } else if (intr_types & DDI_INTR_TYPE_FIXED) {
  67      -                dev->intr_type = DDI_INTR_TYPE_FIXED;
       81 +        } else {
       82 +                oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
       83 +                    "MSIX not available");
       84 +
       85 +                if (intr_types & DDI_INTR_TYPE_FIXED) {
       86 +                        dev->intr_type = DDI_INTR_TYPE_FIXED;
       87 +                        dev->rx_rings = dev->tx_rings = min;
       88 +                } else {
       89 +                        return (DDI_FAILURE);
       90 +                }
  68   91                  nreqd = OCE_MIN_VECTORS;
  69      -                min = OCE_MIN_VECTORS;
  70   92          }
  71   93  
  72   94          ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported);
  73   95          if (ret != DDI_SUCCESS) {
  74   96                  oce_log(dev, CE_WARN, MOD_CONFIG,
  75      -                    "Could not get nintrs:0x%d", ret);
       97 +                    "Could not get supported intrs:0x%x", ret);
  76   98                  return (DDI_FAILURE);
  77   99          }
  78  100  
  79  101          /* get the number of vectors available */
  80  102          ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail);
  81  103          if (ret != DDI_SUCCESS || navail < min) {
  82      -                oce_log(dev, CE_WARN, MOD_CONFIG,
  83      -                    "Could not get msix vectors:0x%x",
  84      -                    navail);
  85      -                return (DDI_FAILURE);
      104 +                oce_log(dev, CE_NOTE, MOD_CONFIG,
      105 +                    "Vectors: supported:0x%x, available:0x%x, ret:0x%x",
      106 +                    nsupported, navail, ret);
      107 +                intr_types &= ~dev->intr_type;
      108 +                goto retry_intr;
  86  109          }
  87  110  
  88      -        if (navail < min) {
  89      -                return (DDI_FAILURE);
  90      -        }
  91      -
  92      -        /* if the requested number is more than available reset reqd */
  93  111          if (navail < nreqd) {
  94  112                  nreqd = navail;
  95  113          }
  96  114  
  97  115          /* allocate htable */
  98  116          dev->hsize  = nreqd *  sizeof (ddi_intr_handle_t);
  99  117          dev->htable = kmem_zalloc(dev->hsize,  KM_NOSLEEP);
 100  118  
 101  119          if (dev->htable == NULL)
 102  120                  return (DDI_FAILURE);
 103  121  
 104      -        nallocd = 0;
 105      -        /* allocate interrupt handlers */
      122 +        /* allocate interrupt */
 106  123          ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type,
 107  124              0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL);
 108  125  
 109      -        if (ret != DDI_SUCCESS) {
 110      -                goto fail_intr;
      126 +        if (ret != DDI_SUCCESS || nallocd < min) {
      127 +                oce_log(dev, CE_WARN, MOD_CONFIG,
      128 +                    "Alloc intr failed: %d %d",
      129 +                    navail, ret);
      130 +                kmem_free(dev->htable, nreqd * sizeof (ddi_intr_handle_t));
      131 +                intr_types &= ~dev->intr_type;
      132 +                goto retry_intr;
 111  133          }
 112  134  
 113      -        dev->num_vectors = nallocd;
 114      -        if (nallocd < min) {
 115      -                goto fail_intr;
 116      -        }
 117      -
 118  135          /*
 119  136           * get the interrupt priority. Assumption is that all handlers have
 120  137           * equal priority
 121  138           */
 122  139  
 123  140          ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
 124  141  
 125  142          if (ret != DDI_SUCCESS) {
 126      -                goto fail_intr;
      143 +                oce_log(dev, CE_WARN, MOD_CONFIG,
      144 +                    "Unable to get intr priority: 0x%x", ret);
      145 +
      146 +                for (i = 0; i < dev->num_vectors; i++) {
      147 +                        (void) ddi_intr_free(dev->htable[i]);
      148 +                }
      149 +                kmem_free(dev->htable, nreqd * sizeof (ddi_intr_handle_t));
      150 +                return (DDI_FAILURE);
 127  151          }
 128  152  
 129  153          (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
 130  154  
 131      -        if ((intr_types & DDI_INTR_TYPE_MSIX) && (nallocd > 1)) {
 132      -                dev->rx_rings = nallocd - 1;
      155 +        /* update the actual number of interrupts allocated */
      156 +        dev->num_vectors = nallocd;
      157 +        if (oce_irm_enable && dev->intr_type == DDI_INTR_TYPE_MSIX) {
      158 +                dev->max_vectors = nreqd;
 133  159          } else {
 134      -                dev->rx_rings = 1;
      160 +                dev->max_vectors = nallocd;
      161 +                dev->tx_rings = min(dev->tx_rings, nallocd);
      162 +                dev->rx_rings = min(dev->rx_rings, nallocd + dev->rss_cnt);
 135  163          }
 136  164  
      165 +        oce_group_rings(dev);
 137  166          return (DDI_SUCCESS);
 138      -
 139      -fail_intr:
 140      -        (void) oce_teardown_intr(dev);
 141      -        if ((dev->intr_type == DDI_INTR_TYPE_MSIX) &&
 142      -            (intr_types & DDI_INTR_TYPE_FIXED)) {
 143      -                intr_types &= ~DDI_INTR_TYPE_MSIX;
 144      -                oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
 145      -                    "Could not get MSIX vectors, trying for FIXED vectors");
 146      -                goto retry_intr;
 147      -        }
 148      -        return (DDI_FAILURE);
 149  167  }
 150  168  
      169 +
 151  170  /*
 152  171   * top level function to undo initialization in oce_setup_intr
 153  172   *
 154  173   * dev - software handle to the device
 155  174   *
 156  175   * return DDI_SUCCESS => success, failure otherwise
 157  176   */
 158  177  int
 159  178  oce_teardown_intr(struct oce_dev *dev)
 160  179  {
 161  180          int i;
 162  181  
 163  182          /* release handlers */
 164  183          for (i = 0; i < dev->num_vectors; i++) {
 165  184                  (void) ddi_intr_free(dev->htable[i]);
 166  185          }
 167  186  
 168  187          /* release htable */
 169  188          kmem_free(dev->htable, dev->hsize);
 170  189          dev->htable = NULL;
 171      -
      190 +        if (dev->attach_state & ATTACH_CB_REG) {
      191 +                (void) ddi_cb_unregister(dev->cb_handle);
      192 +        }
 172  193          return (DDI_SUCCESS);
 173  194  }
 174  195  
 175  196  /*
 176  197   * helper function to add ISR based on interrupt type
 177  198   *
 178  199   * dev - software handle to the device
 179  200   *
 180  201   * return DDI_SUCCESS => success, failure otherwise
 181  202   */
 182  203  int
 183  204  oce_setup_handlers(struct oce_dev *dev)
 184  205  {
 185  206          int i = 0;
 186  207          int ret;
 187  208          for (i = 0; i < dev->num_vectors; i++) {
 188  209                  ret = ddi_intr_add_handler(dev->htable[i], oce_isr,
 189      -                    (caddr_t)dev->eq[i], NULL);
      210 +                    (caddr_t)&dev->eq[i], NULL);
 190  211                  if (ret != DDI_SUCCESS) {
 191      -                        oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 192      -                            "Failed to add interrupt handlers");
      212 +                        oce_log(dev, CE_WARN, MOD_CONFIG,
      213 +                            "Failed to add interrupt handler %d, ret = 0x%x",
      214 +                            i, ret);
 193  215                          for (i--; i >= 0; i--) {
 194  216                                  (void) ddi_intr_remove_handler(dev->htable[i]);
 195  217                          }
 196  218                          return (DDI_FAILURE);
 197  219                  }
 198  220          }
 199  221          return (DDI_SUCCESS);
 200  222  }
 201  223  
 202  224  /*
 203  225   * helper function to remove ISRs added in oce_setup_handlers
 204  226   *
 205  227   * dev - software handle to the device
 206  228   *
 207  229   * return DDI_SUCCESS => success, failure otherwise
 208  230   */
 209  231  void
 210  232  oce_remove_handler(struct oce_dev *dev)
 211  233  {
 212  234          int nvec;
 213  235          for (nvec = 0; nvec < dev->num_vectors; nvec++) {
 214  236                  (void) ddi_intr_remove_handler(dev->htable[nvec]);
 215  237          }
 216  238  }
 217  239  
 218  240  void
 219  241  oce_chip_ei(struct oce_dev *dev)
 220  242  {
 221  243          uint32_t reg;
 222  244  
 223  245          reg =  OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
 224  246          reg |= HOSTINTR_MASK;
  
    | 
      ↓ open down ↓ | 
    22 lines elided | 
    
      ↑ open up ↑ | 
  
 225  247          OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
 226  248  }
 227  249  
 228  250  /*
 229  251   * function to enable interrupts
 230  252   *
 231  253   * dev - software handle to the device
 232  254   *
 233  255   * return DDI_SUCCESS => success, failure otherwise
 234  256   */
 235      -void
      257 +int
 236  258  oce_ei(struct oce_dev *dev)
 237  259  {
 238  260          int i;
 239  261          int ret;
 240  262  
 241  263          if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 242      -                (void) ddi_intr_block_enable(dev->htable, dev->num_vectors);
      264 +                ret =  ddi_intr_block_enable(dev->htable, dev->num_vectors);
      265 +                if (ret !=  DDI_SUCCESS) {
      266 +                        oce_log(dev, CE_WARN, MOD_CONFIG,
      267 +                            "Interrupts block enable failed :%d\n", ret);
      268 +                        return (DDI_FAILURE);
      269 +                }
 243  270          } else {
 244      -
 245  271                  for (i = 0; i < dev->num_vectors; i++) {
 246  272                          ret = ddi_intr_enable(dev->htable[i]);
 247  273                          if (ret != DDI_SUCCESS) {
      274 +                                oce_log(dev, CE_WARN, MOD_CONFIG,
      275 +                                    "Failed  to enable, ret %d, interrupt %d,"
      276 +                                    " type %d, cnt %d ",
      277 +                                    ret, i, dev->intr_type, dev->num_vectors);
 248  278                                  for (i--; i >= 0; i--) {
 249  279                                          (void) ddi_intr_disable(dev->htable[i]);
 250  280                                  }
      281 +                                return (DDI_FAILURE);
 251  282                          }
 252  283                  }
 253  284          }
 254      -        oce_chip_ei(dev);
      285 +
      286 +        return (DDI_SUCCESS);
 255  287  } /* oce_ei */
 256  288  
 257  289  void
 258  290  oce_chip_di(struct oce_dev *dev)
 259  291  {
 260  292          uint32_t reg;
 261  293  
 262  294          reg =  OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
 263  295          reg &= ~HOSTINTR_MASK;
 264  296          OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
 265  297  }
 266  298  
 267  299  /*
 268  300   * function to disable interrupts
 269  301   *
 270  302   * dev - software handle to the device
 271  303   *
 272  304   * return DDI_SUCCESS => success, failure otherwise
 273  305   */
 274      -void
      306 +int
 275  307  oce_di(struct oce_dev *dev)
 276  308  {
 277  309          int i;
 278  310          int ret;
 279  311  
 280      -        oce_chip_di(dev);
      312 +        dev->state &= ~STATE_INTR_ENABLED;
      313 +        if (!LANCER_CHIP(dev))
      314 +                oce_chip_di(dev);
      315 +
 281  316          if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 282      -                (void) ddi_intr_block_disable(dev->htable, dev->num_vectors);
      317 +                ret =  ddi_intr_block_disable(dev->htable, dev->num_vectors);
      318 +                if (ret !=  DDI_SUCCESS) {
      319 +                        oce_log(dev, CE_WARN, MOD_CONFIG,
      320 +                            "Interrupt block disable failed :%d\n", ret);
      321 +                        return (DDI_FAILURE);
      322 +                }
 283  323          } else {
 284  324                  for (i = 0; i < dev->num_vectors; i++) {
 285  325                          ret = ddi_intr_disable(dev->htable[i]);
 286  326                          if (ret != DDI_SUCCESS) {
 287  327                                  oce_log(dev, CE_WARN, MOD_CONFIG,
 288      -                                    "Failed to disable interrupts 0x%x", ret);
      328 +                                    "Failed to disable the interrupts 0x%x",
      329 +                                    ret);
      330 +                                return (DDI_FAILURE);
 289  331                          }
 290  332                  }
 291  333          }
 292      -
      334 +        return (DDI_SUCCESS);
 293  335  } /* oce_di */
 294  336  
 295      -/*
 296      - * command interrupt handler routine added to all vectors
 297      - *
 298      - * arg1 = callback data
 299      - * arg2 - callback data
 300      - *
 301      - * return DDI_INTR_CLAIMED => interrupt was claimed by the ISR
 302      - */
 303      -static uint_t
 304      -oce_isr(caddr_t arg1, caddr_t arg2)
      337 +
      338 +int
      339 +oce_ring_intr_enable(mac_intr_handle_t ring_handle)
 305  340  {
 306      -        struct oce_eq *eq;
      341 +        struct oce_rq *rx_ring = (struct oce_rq *)ring_handle;
      342 +        struct oce_dev *dev;
      343 +        dev = rx_ring->parent;
      344 +        oce_group_t *grp = rx_ring->grp;
      345 +        mutex_enter(&grp->grp_lock);
      346 +        if (grp->state & GROUP_SUSPEND) {
      347 +                mutex_exit(&grp->grp_lock);
      348 +                return (DDI_SUCCESS);
      349 +        }
      350 +        mutex_enter(&rx_ring->rx_lock);
      351 +        oce_arm_cq(dev, rx_ring->cq->cq_id, 0, B_TRUE);
      352 +        rx_ring->qmode = OCE_MODE_INTR;
      353 +        mutex_exit(&rx_ring->rx_lock);
      354 +        mutex_exit(&grp->grp_lock);
      355 +        return (DDI_SUCCESS);
      356 +}
      357 +
      358 +
      359 +int
      360 +oce_ring_intr_disable(mac_intr_handle_t ring_handle)
      361 +{
      362 +        struct oce_rq *rx_ring = (struct oce_rq *)ring_handle;
      363 +        struct oce_dev *dev;
      364 +
      365 +        dev = rx_ring->parent;
      366 +        mutex_enter(&rx_ring->rx_lock);
      367 +        oce_arm_cq(dev, rx_ring->cq->cq_id, 0, B_FALSE);
      368 +        rx_ring->qmode = OCE_MODE_POLL;
      369 +        mutex_exit(&rx_ring->rx_lock);
      370 +        return (DDI_SUCCESS);
      371 +}
      372 +
      373 +uint_t
      374 +oce_ring_common_drain(struct oce_eq *eq)
      375 +{
 307  376          struct oce_eqe *eqe;
 308  377          uint16_t num_eqe = 0;
 309  378          uint16_t cq_id;
 310  379          struct oce_cq *cq;
 311  380          struct oce_dev  *dev;
 312  381  
 313      -        _NOTE(ARGUNUSED(arg2));
 314      -
 315      -        eq = (struct oce_eq *)(void *)(arg1);
 316      -
 317  382          dev = eq->parent;
 318  383  
 319  384          eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
 320  385  
 321      -        while (eqe->u0.dw0) {
 322      -
      386 +        if (eqe->u0.dw0) {
 323  387                  eqe->u0.dw0 = LE_32(eqe->u0.dw0);
 324  388  
 325      -                /* if not CQ then continue else flag an error */
 326      -                if (EQ_MAJOR_CODE_COMPLETION != eqe->u0.s.major_code) {
 327      -                        oce_log(dev, CE_WARN, MOD_ISR,
 328      -                            "NOT a CQ event. 0x%x",
 329      -                            eqe->u0.s.major_code);
 330      -                }
 331      -
 332  389                  /* get the cq from the eqe */
 333  390                  cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ;
 334  391                  cq = dev->cq[cq_id];
 335  392  
 336      -                /* Call the completion handler */
 337      -                (void) cq->cq_handler(cq->cb_arg);
 338      -
 339  393                  /* clear valid bit and progress eqe */
 340  394                  eqe->u0.dw0 = 0;
 341  395                  RING_GET(eq->ring, 1);
 342      -                eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
 343  396                  num_eqe++;
 344      -        } /* for all EQEs */
 345  397  
      398 +                if (cq) {
      399 +                        /* Call the completion handler */
      400 +                        (void) cq->cq_handler(cq->cb_arg, 0, 0);
      401 +                }
      402 +        }
      403 +
 346  404          /* ring the eq doorbell, signify that it's done processing  */
 347  405          oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE);
 348      -        if (num_eqe > 0) {
      406 +
      407 +        return (num_eqe);
      408 +
      409 +} /* oce_ring_common_drain */
      410 +
      411 +
      412 +/* MSI/INTX handler: common vector for TX/RX/MQ */
      413 +uint_t
      414 +oce_isr(caddr_t arg1, caddr_t arg2)
      415 +{
      416 +        struct oce_eq *eq;
      417 +        struct oce_dev *dev;
      418 +        uint16_t num_eqe = 0;
      419 +
      420 +        _NOTE(ARGUNUSED(arg2));
      421 +
      422 +        eq = (struct oce_eq *)(void *)(arg1);
      423 +        dev = eq->parent;
      424 +
      425 +        if ((dev == NULL) ||
      426 +            !(dev->state & STATE_INTR_ENABLED)) {
      427 +                oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
      428 +                    "Dummy interrupt received");
 349  429                  return (DDI_INTR_CLAIMED);
      430 +        }
      431 +
      432 +        mutex_enter(&eq->lock);
      433 +        if (eq->qstate != QSTARTED) {
      434 +                mutex_exit(&eq->lock);
      435 +                oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
      436 +                    "oce_isr EQ Not started");
      437 +                return (DDI_INTR_CLAIMED);
      438 +        }
      439 +        num_eqe = oce_ring_common_drain(eq);
      440 +        mutex_exit(&eq->lock);
      441 +        if (num_eqe) {
      442 +                return (DDI_INTR_CLAIMED);
 350  443          } else {
 351  444                  return (DDI_INTR_UNCLAIMED);
 352  445          }
 353      -} /* oce_msix_handler */
      446 +}
      447 +
      448 +/*
      449 + * IRM callback routine
      450 + */
      451 +int
      452 +oce_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
      453 +    void *arg1, void *arg2)
      454 +{
      455 +        struct oce_dev *dev = (struct oce_dev *)arg1;
      456 +        int count = (int)(uintptr_t)cbarg, ret = DDI_ENOTSUP;
      457 +
      458 +        _NOTE(ARGUNUSED(dip));
      459 +        _NOTE(ARGUNUSED(arg2));
      460 +
      461 +        switch (cbaction) {
      462 +        case DDI_CB_INTR_ADD:
      463 +        case DDI_CB_INTR_REMOVE:
      464 +
      465 +                oce_log(dev, CE_NOTE, MOD_CONFIG,
      466 +                    "IRM cbaction %d count %d vectors %d max_vectors %d",
      467 +                    cbaction, count, dev->num_vectors, dev->max_vectors);
      468 +                ret = oce_adjust_intrs(dev, cbaction, count);
      469 +                if (ret != DDI_SUCCESS) {
      470 +                        oce_log(dev, CE_NOTE,  MOD_CONFIG, "%s",
      471 +                            "IRM: Failed to adjust interrupts");
      472 +                        return (ret);
      473 +                }
      474 +                break;
      475 +
      476 +        default:
      477 +                return (ret);
      478 +        }
      479 +        return (ret);
      480 +}
      481 +
      482 +
      483 +static int
      484 +oce_adjust_intrs(struct oce_dev *dev, ddi_cb_action_t action, int count)
      485 +{
      486 +        int     i, nallocd, ret;
      487 +
      488 +        if (count == 0)
      489 +                return (DDI_SUCCESS);
      490 +
      491 +        if ((action == DDI_CB_INTR_ADD &&
      492 +            dev->num_vectors + count > dev->max_vectors) ||
      493 +            (action == DDI_CB_INTR_REMOVE &&
      494 +            dev->num_vectors - count < OCE_MIN_VECTORS)) {
      495 +                return (DDI_FAILURE);
      496 +        }
      497 +
      498 +        if (!(dev->state & STATE_MAC_STARTED)) {
      499 +                return (DDI_FAILURE);
      500 +        }
      501 +
      502 +        mutex_enter(&dev->dev_lock);
      503 +        dev->state |= STATE_INTR_ADJUST;
      504 +        dev->suspended = B_TRUE;
      505 +
      506 +        /* stop the groups */
      507 +        for (i = 0; i < dev->num_rx_groups; i++) {
      508 +                mutex_enter(&dev->rx_group[i].grp_lock);
      509 +                oce_suspend_group_rings(&dev->rx_group[i]);
      510 +                oce_stop_group(&dev->rx_group[i], B_FALSE);
      511 +                mutex_exit(&dev->rx_group[i].grp_lock);
      512 +        }
      513 +
      514 +        oce_stop(dev);
      515 +        oce_remove_handler(dev);
      516 +        if (action == DDI_CB_INTR_ADD) {
      517 +                /* allocate additional vectors */
      518 +                ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_MSIX,
      519 +                    dev->num_vectors, count, &nallocd, DDI_INTR_ALLOC_NORMAL);
      520 +
      521 +                if (ret != DDI_SUCCESS) {
      522 +                        goto irm_fail;
      523 +                }
      524 +
      525 +                /* update actual count of available interrupts */
      526 +                dev->num_vectors += nallocd;
      527 +                oce_log(dev, CE_NOTE, MOD_CONFIG,
      528 +                    "IRM: INTR_ADD - count=0x%x allocated=0x%x vectors=0x%x",
      529 +                    count, nallocd, dev->num_vectors);
      530 +        } else {
      531 +                /* free interrupt vectors */
      532 +                for (i = dev->num_vectors - count;
      533 +                    i < dev->num_vectors; i++) {
      534 +                        ret = ddi_intr_free(dev->htable[i]);
      535 +                        if (ret != DDI_SUCCESS) {
      536 +                                oce_log(dev, CE_WARN, MOD_CONFIG,
      537 +                                    "IRM: can't free vectors ret 0x%x", ret);
      538 +                                goto irm_fail;
      539 +                        }
      540 +                        dev->htable[i] = NULL;
      541 +                }
      542 +
      543 +                /* update actual count of available interrupts */
      544 +                dev->num_vectors -= count;
      545 +                oce_log(dev, CE_NOTE, MOD_CONFIG,
      546 +                    "IRM: INTR_REMOVE - count = 0x%x vectors = 0x%x",
      547 +                    count, dev->num_vectors);
      548 +        }
      549 +
      550 +        if (oce_setup_handlers(dev) != DDI_SUCCESS) {
      551 +                oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
      552 +                    "Failed to Setup handlers during IRM");
      553 +                goto irm_fail;
      554 +        }
      555 +
      556 +        /* re-start the device instance */
      557 +        if (oce_start(dev) != DDI_SUCCESS) {
      558 +                goto irm_fail;
      559 +        }
      560 +
      561 +        ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
      562 +
      563 +        if (ret != DDI_SUCCESS) {
      564 +                goto irm_fail;
      565 +        }
      566 +
      567 +        (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
      568 +
      569 +        /* re-start the groups */
      570 +        for (i = 0; i < dev->num_rx_groups; i++) {
      571 +                mutex_enter(&dev->rx_group[i].grp_lock);
      572 +                ret = oce_start_group(&dev->rx_group[i], B_FALSE);
      573 +                if (ret == DDI_SUCCESS) {
      574 +                        ret = oce_resume_group_rings(&dev->rx_group[i]);
      575 +                }
      576 +                mutex_exit(&dev->rx_group[i].grp_lock);
      577 +                if (ret != DDI_SUCCESS) {
      578 +                        goto irm_fail;
      579 +                }
      580 +        }
      581 +        dev->state &= ~STATE_INTR_ADJUST;
      582 +        dev->suspended = B_FALSE;
      583 +        mutex_exit(&dev->dev_lock);
      584 +
      585 +        /* Wakeup all Tx rings */
      586 +        for (i = 0; i < dev->tx_rings; i++) {
      587 +                mac_tx_ring_update(dev->mac_handle,
      588 +                    dev->default_tx_rings[i].tx->handle);
      589 +        }
      590 +
      591 +        return (DDI_SUCCESS);
      592 +
      593 +irm_fail:
      594 +        ddi_fm_service_impact(dev->dip, DDI_SERVICE_LOST);
      595 +        mutex_exit(&dev->dev_lock);
      596 +        return (DDI_FAILURE);
      597 +}
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX