Print this page
NEX-1890 update oce from source provided by Emulex


   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /* Copyright © 2003-2011 Emulex. All rights reserved.  */



  23 


  24 /*
  25  * Source file interrupt registration
  26  * and related helper functions
  27  */
  28 
  29 #include <oce_impl.h>
  30 
  31 
  32 static uint_t oce_isr(caddr_t arg1, caddr_t arg2);


  33 
  34 /*
  35  * top level function to setup interrupts
  36  *
  37  * dev - software handle to the device
  38  *
  39  * return DDI_SUCCESS => success, failure otherwise
  40  */
  41 int
  42 oce_setup_intr(struct oce_dev *dev)
  43 {
  44         int ret;
  45         int intr_types = 0;
  46         int navail = 0;
  47         int nsupported = 0;
  48         int min = 0;
  49         int nreqd = 0;
  50         int nallocd = 0;

  51 
  52         /* get supported intr types */
  53         ret = ddi_intr_get_supported_types(dev->dip, &intr_types);
  54         if (ret != DDI_SUCCESS) {
  55                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
  56                     "Failed to retrieve intr types ");
  57                 return (DDI_FAILURE);
  58         }
  59 










  60 retry_intr:

  61         if (intr_types & DDI_INTR_TYPE_MSIX) {
  62                 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;




  68                 nreqd = OCE_MIN_VECTORS;
  69                 min = OCE_MIN_VECTORS;
  70         }
  71 
  72         ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported);
  73         if (ret != DDI_SUCCESS) {
  74                 oce_log(dev, CE_WARN, MOD_CONFIG,
  75                     "Could not get nintrs:0x%d", ret);
  76                 return (DDI_FAILURE);
  77         }
  78 
  79         /* get the number of vectors available */
  80         ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail);
  81         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);

  86         }
  87 
  88         if (navail < min) {
  89                 return (DDI_FAILURE);
  90         }
  91 
  92         /* if the requested number is more than available reset reqd */
  93         if (navail < nreqd) {
  94                 nreqd = navail;
  95         }
  96 
  97         /* allocate htable */
  98         dev->hsize  = nreqd *  sizeof (ddi_intr_handle_t);
  99         dev->htable = kmem_zalloc(dev->hsize,  KM_NOSLEEP);
 100 
 101         if (dev->htable == NULL)
 102                 return (DDI_FAILURE);
 103 
 104         nallocd = 0;
 105         /* allocate interrupt handlers */
 106         ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type,
 107             0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL);
 108 
 109         if (ret != DDI_SUCCESS) {
 110                 goto fail_intr;





 111         }
 112 
 113         dev->num_vectors = nallocd;
 114         if (nallocd < min) {
 115                 goto fail_intr;
 116         }
 117 
 118         /*
 119          * get the interrupt priority. Assumption is that all handlers have
 120          * equal priority
 121          */
 122 
 123         ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
 124 
 125         if (ret != DDI_SUCCESS) {
 126                 goto fail_intr;




 127         }



 128 
 129         (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
 130 
 131         if ((intr_types & DDI_INTR_TYPE_MSIX) && (nallocd > 1)) {
 132                 dev->rx_rings = nallocd - 1;


 133         } else {
 134                 dev->rx_rings = 1;


 135         }
 136 

 137         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 }
 150 

 151 /*
 152  * top level function to undo initialization in oce_setup_intr
 153  *
 154  * dev - software handle to the device
 155  *
 156  * return DDI_SUCCESS => success, failure otherwise
 157  */
 158 int
 159 oce_teardown_intr(struct oce_dev *dev)
 160 {
 161         int i;
 162 
 163         /* release handlers */
 164         for (i = 0; i < dev->num_vectors; i++) {
 165                 (void) ddi_intr_free(dev->htable[i]);
 166         }
 167 
 168         /* release htable */
 169         kmem_free(dev->htable, dev->hsize);
 170         dev->htable = NULL;
 171 


 172         return (DDI_SUCCESS);
 173 }
 174 
 175 /*
 176  * helper function to add ISR based on interrupt type
 177  *
 178  * dev - software handle to the device
 179  *
 180  * return DDI_SUCCESS => success, failure otherwise
 181  */
 182 int
 183 oce_setup_handlers(struct oce_dev *dev)
 184 {
 185         int i = 0;
 186         int ret;
 187         for (i = 0; i < dev->num_vectors; i++) {
 188                 ret = ddi_intr_add_handler(dev->htable[i], oce_isr,
 189                     (caddr_t)dev->eq[i], NULL);
 190                 if (ret != DDI_SUCCESS) {
 191                         oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 192                             "Failed to add interrupt handlers");

 193                         for (i--; i >= 0; i--) {
 194                                 (void) ddi_intr_remove_handler(dev->htable[i]);
 195                         }
 196                         return (DDI_FAILURE);
 197                 }
 198         }
 199         return (DDI_SUCCESS);
 200 }
 201 
 202 /*
 203  * helper function to remove ISRs added in oce_setup_handlers
 204  *
 205  * dev - software handle to the device
 206  *
 207  * return DDI_SUCCESS => success, failure otherwise
 208  */
 209 void
 210 oce_remove_handler(struct oce_dev *dev)
 211 {
 212         int nvec;


 215         }
 216 }
 217 
 218 void
 219 oce_chip_ei(struct oce_dev *dev)
 220 {
 221         uint32_t reg;
 222 
 223         reg =  OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
 224         reg |= HOSTINTR_MASK;
 225         OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
 226 }
 227 
 228 /*
 229  * function to enable interrupts
 230  *
 231  * dev - software handle to the device
 232  *
 233  * return DDI_SUCCESS => success, failure otherwise
 234  */
 235 void
 236 oce_ei(struct oce_dev *dev)
 237 {
 238         int i;
 239         int ret;
 240 
 241         if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 242                 (void) ddi_intr_block_enable(dev->htable, dev->num_vectors);





 243         } else {
 244 
 245                 for (i = 0; i < dev->num_vectors; i++) {
 246                         ret = ddi_intr_enable(dev->htable[i]);
 247                         if (ret != DDI_SUCCESS) {




 248                                 for (i--; i >= 0; i--) {
 249                                         (void) ddi_intr_disable(dev->htable[i]);
 250                                 }

 251                         }
 252                 }
 253         }
 254         oce_chip_ei(dev);

 255 } /* oce_ei */
 256 
 257 void
 258 oce_chip_di(struct oce_dev *dev)
 259 {
 260         uint32_t reg;
 261 
 262         reg =  OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
 263         reg &= ~HOSTINTR_MASK;
 264         OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
 265 }
 266 
 267 /*
 268  * function to disable interrupts
 269  *
 270  * dev - software handle to the device
 271  *
 272  * return DDI_SUCCESS => success, failure otherwise
 273  */
 274 void
 275 oce_di(struct oce_dev *dev)
 276 {
 277         int i;
 278         int ret;
 279 


 280         oce_chip_di(dev);

 281         if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 282                 (void) ddi_intr_block_disable(dev->htable, dev->num_vectors);





 283         } else {
 284                 for (i = 0; i < dev->num_vectors; i++) {
 285                         ret = ddi_intr_disable(dev->htable[i]);
 286                         if (ret != DDI_SUCCESS) {
 287                                 oce_log(dev, CE_WARN, MOD_CONFIG,
 288                                     "Failed to disable interrupts 0x%x", ret);


 289                         }
 290                 }
 291         }
 292 
 293 } /* oce_di */
 294 
 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)
 305 {
 306         struct oce_eq *eq;


































 307         struct oce_eqe *eqe;
 308         uint16_t num_eqe = 0;
 309         uint16_t cq_id;
 310         struct oce_cq *cq;
 311         struct oce_dev  *dev;
 312 
 313         _NOTE(ARGUNUSED(arg2));
 314 
 315         eq = (struct oce_eq *)(void *)(arg1);
 316 
 317         dev = eq->parent;
 318 
 319         eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
 320 
 321         while (eqe->u0.dw0) {
 322 
 323                 eqe->u0.dw0 = LE_32(eqe->u0.dw0);
 324 
 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                 /* get the cq from the eqe */
 333                 cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ;
 334                 cq = dev->cq[cq_id];
 335 
 336                 /* Call the completion handler */
 337                 (void) cq->cq_handler(cq->cb_arg);
 338 
 339                 /* clear valid bit and progress eqe */
 340                 eqe->u0.dw0 = 0;
 341                 RING_GET(eq->ring, 1);
 342                 eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
 343                 num_eqe++;
 344         } /* for all EQEs */
 345 






 346         /* ring the eq doorbell, signify that it's done processing  */
 347         oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE);
 348         if (num_eqe > 0) {






















 349                 return (DDI_INTR_CLAIMED);













 350         } else {
 351                 return (DDI_INTR_UNCLAIMED);
 352         }
 353 } /* oce_msix_handler */

























































































































































   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 
  29 /*
  30  * Source file interrupt registration
  31  * and related helper functions
  32  */
  33 
  34 #include <oce_impl.h>
  35 

  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);
  39 
  40 /*
  41  * top level function to setup interrupts
  42  *
  43  * dev - software handle to the device
  44  *
  45  * return DDI_SUCCESS => success, failure otherwise
  46  */
  47 int
  48 oce_setup_intr(struct oce_dev *dev)
  49 {
  50         int ret, i;
  51         int intr_types = 0;
  52         int navail = 0;
  53         int nsupported = 0;
  54         int min = 0;
  55         int nreqd = 0;
  56         int nallocd = 0;
  57         extern int oce_irm_enable;
  58 
  59         /* get supported intr types */
  60         ret = ddi_intr_get_supported_types(dev->dip, &intr_types);
  61         if (ret != DDI_SUCCESS) {
  62                 oce_log(dev, CE_WARN, MOD_CONFIG,
  63                     "Failed to retrieve intr types 0x%x", ret);
  64                 return (DDI_FAILURE);
  65         }
  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 
  77 retry_intr:
  78 
  79         if (intr_types & DDI_INTR_TYPE_MSIX) {
  80                 dev->intr_type = DDI_INTR_TYPE_MSIX;
  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                 }
  91                 nreqd = OCE_MIN_VECTORS;

  92         }
  93 
  94         ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported);
  95         if (ret != DDI_SUCCESS) {
  96                 oce_log(dev, CE_WARN, MOD_CONFIG,
  97                     "Could not get supported intrs:0x%x", ret);
  98                 return (DDI_FAILURE);
  99         }
 100 
 101         /* get the number of vectors available */
 102         ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail);
 103         if (ret != DDI_SUCCESS || navail < min) {
 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;
 109         }
 110 





 111         if (navail < nreqd) {
 112                 nreqd = navail;
 113         }
 114 
 115         /* allocate htable */
 116         dev->hsize  = nreqd *  sizeof (ddi_intr_handle_t);
 117         dev->htable = kmem_zalloc(dev->hsize,  KM_NOSLEEP);
 118 
 119         if (dev->htable == NULL)
 120                 return (DDI_FAILURE);
 121 
 122         /* allocate interrupt */

 123         ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type,
 124             0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL);
 125 
 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;
 133         }
 134 





 135         /*
 136          * get the interrupt priority. Assumption is that all handlers have
 137          * equal priority
 138          */
 139 
 140         ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
 141 
 142         if (ret != DDI_SUCCESS) {
 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);
 151         }
 152 
 153         (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
 154 
 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;
 159         } else {
 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);
 163         }
 164 
 165         oce_group_rings(dev);
 166         return (DDI_SUCCESS);











 167 }
 168 
 169 
 170 /*
 171  * top level function to undo initialization in oce_setup_intr
 172  *
 173  * dev - software handle to the device
 174  *
 175  * return DDI_SUCCESS => success, failure otherwise
 176  */
 177 int
 178 oce_teardown_intr(struct oce_dev *dev)
 179 {
 180         int i;
 181 
 182         /* release handlers */
 183         for (i = 0; i < dev->num_vectors; i++) {
 184                 (void) ddi_intr_free(dev->htable[i]);
 185         }
 186 
 187         /* release htable */
 188         kmem_free(dev->htable, dev->hsize);
 189         dev->htable = NULL;
 190         if (dev->attach_state & ATTACH_CB_REG) {
 191                 (void) ddi_cb_unregister(dev->cb_handle);
 192         }
 193         return (DDI_SUCCESS);
 194 }
 195 
 196 /*
 197  * helper function to add ISR based on interrupt type
 198  *
 199  * dev - software handle to the device
 200  *
 201  * return DDI_SUCCESS => success, failure otherwise
 202  */
 203 int
 204 oce_setup_handlers(struct oce_dev *dev)
 205 {
 206         int i = 0;
 207         int ret;
 208         for (i = 0; i < dev->num_vectors; i++) {
 209                 ret = ddi_intr_add_handler(dev->htable[i], oce_isr,
 210                     (caddr_t)&dev->eq[i], NULL);
 211                 if (ret != DDI_SUCCESS) {
 212                         oce_log(dev, CE_WARN, MOD_CONFIG,
 213                             "Failed to add interrupt handler %d, ret = 0x%x",
 214                             i, ret);
 215                         for (i--; i >= 0; i--) {
 216                                 (void) ddi_intr_remove_handler(dev->htable[i]);
 217                         }
 218                         return (DDI_FAILURE);
 219                 }
 220         }
 221         return (DDI_SUCCESS);
 222 }
 223 
 224 /*
 225  * helper function to remove ISRs added in oce_setup_handlers
 226  *
 227  * dev - software handle to the device
 228  *
 229  * return DDI_SUCCESS => success, failure otherwise
 230  */
 231 void
 232 oce_remove_handler(struct oce_dev *dev)
 233 {
 234         int nvec;


 237         }
 238 }
 239 
 240 void
 241 oce_chip_ei(struct oce_dev *dev)
 242 {
 243         uint32_t reg;
 244 
 245         reg =  OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
 246         reg |= HOSTINTR_MASK;
 247         OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
 248 }
 249 
 250 /*
 251  * function to enable interrupts
 252  *
 253  * dev - software handle to the device
 254  *
 255  * return DDI_SUCCESS => success, failure otherwise
 256  */
 257 int
 258 oce_ei(struct oce_dev *dev)
 259 {
 260         int i;
 261         int ret;
 262 
 263         if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 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                 }
 270         } else {

 271                 for (i = 0; i < dev->num_vectors; i++) {
 272                         ret = ddi_intr_enable(dev->htable[i]);
 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);
 278                                 for (i--; i >= 0; i--) {
 279                                         (void) ddi_intr_disable(dev->htable[i]);
 280                                 }
 281                                 return (DDI_FAILURE);
 282                         }
 283                 }
 284         }
 285 
 286         return (DDI_SUCCESS);
 287 } /* oce_ei */
 288 
 289 void
 290 oce_chip_di(struct oce_dev *dev)
 291 {
 292         uint32_t reg;
 293 
 294         reg =  OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
 295         reg &= ~HOSTINTR_MASK;
 296         OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
 297 }
 298 
 299 /*
 300  * function to disable interrupts
 301  *
 302  * dev - software handle to the device
 303  *
 304  * return DDI_SUCCESS => success, failure otherwise
 305  */
 306 int
 307 oce_di(struct oce_dev *dev)
 308 {
 309         int i;
 310         int ret;
 311 
 312         dev->state &= ~STATE_INTR_ENABLED;
 313         if (!LANCER_CHIP(dev))
 314                 oce_chip_di(dev);
 315 
 316         if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
 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                 }
 323         } else {
 324                 for (i = 0; i < dev->num_vectors; i++) {
 325                         ret = ddi_intr_disable(dev->htable[i]);
 326                         if (ret != DDI_SUCCESS) {
 327                                 oce_log(dev, CE_WARN, MOD_CONFIG,
 328                                     "Failed to disable the interrupts 0x%x",
 329                                     ret);
 330                                 return (DDI_FAILURE);
 331                         }
 332                 }
 333         }
 334         return (DDI_SUCCESS);
 335 } /* oce_di */
 336 
 337 
 338 int
 339 oce_ring_intr_enable(mac_intr_handle_t ring_handle)







 340 {
 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 {
 376         struct oce_eqe *eqe;
 377         uint16_t num_eqe = 0;
 378         uint16_t cq_id;
 379         struct oce_cq *cq;
 380         struct oce_dev  *dev;
 381 




 382         dev = eq->parent;
 383 
 384         eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
 385 
 386         if (eqe->u0.dw0) {

 387                 eqe->u0.dw0 = LE_32(eqe->u0.dw0);
 388 







 389                 /* get the cq from the eqe */
 390                 cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ;
 391                 cq = dev->cq[cq_id];
 392 



 393                 /* clear valid bit and progress eqe */
 394                 eqe->u0.dw0 = 0;
 395                 RING_GET(eq->ring, 1);

 396                 num_eqe++;

 397 
 398                 if (cq) {
 399                         /* Call the completion handler */
 400                         (void) cq->cq_handler(cq->cb_arg, 0, 0);
 401                 }
 402         }
 403 
 404         /* ring the eq doorbell, signify that it's done processing  */
 405         oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE);
 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");
 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);
 443         } else {
 444                 return (DDI_INTR_UNCLAIMED);
 445         }
 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 }