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

*** 17,37 **** * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ ! /* Copyright © 2003-2011 Emulex. All rights reserved. */ /* * Source file interrupt registration * and related helper functions */ #include <oce_impl.h> - static uint_t oce_isr(caddr_t arg1, caddr_t arg2); /* * top level function to setup interrupts * * dev - software handle to the device --- 17,43 ---- * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ ! /* ! * Copyright (c) 2009-2012 Emulex. All rights reserved. ! * Use is subject to license terms. ! */ + + /* * Source file interrupt registration * and related helper functions */ #include <oce_impl.h> static uint_t oce_isr(caddr_t arg1, caddr_t arg2); + static int + oce_adjust_intrs(struct oce_dev *dev, ddi_cb_action_t action, int count); /* * top level function to setup interrupts * * dev - software handle to the device
*** 39,97 **** * return DDI_SUCCESS => success, failure otherwise */ int oce_setup_intr(struct oce_dev *dev) { ! int ret; int intr_types = 0; int navail = 0; int nsupported = 0; int min = 0; int nreqd = 0; int nallocd = 0; /* get supported intr types */ ret = ddi_intr_get_supported_types(dev->dip, &intr_types); if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, "%s", ! "Failed to retrieve intr types "); return (DDI_FAILURE); } retry_intr: if (intr_types & DDI_INTR_TYPE_MSIX) { dev->intr_type = DDI_INTR_TYPE_MSIX; ! /* one vector is shared by MCC and Tx */ ! nreqd = dev->rx_rings + 1; ! min = OCE_MIN_VECTORS; ! } else if (intr_types & DDI_INTR_TYPE_FIXED) { dev->intr_type = DDI_INTR_TYPE_FIXED; nreqd = OCE_MIN_VECTORS; - min = OCE_MIN_VECTORS; } ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, ! "Could not get nintrs:0x%d", ret); return (DDI_FAILURE); } /* get the number of vectors available */ ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail); if (ret != DDI_SUCCESS || navail < min) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Could not get msix vectors:0x%x", ! navail); ! return (DDI_FAILURE); } - if (navail < min) { - return (DDI_FAILURE); - } - - /* if the requested number is more than available reset reqd */ if (navail < nreqd) { nreqd = navail; } /* allocate htable */ --- 45,115 ---- * return DDI_SUCCESS => success, failure otherwise */ int oce_setup_intr(struct oce_dev *dev) { ! int ret, i; int intr_types = 0; int navail = 0; int nsupported = 0; int min = 0; int nreqd = 0; int nallocd = 0; + extern int oce_irm_enable; /* get supported intr types */ ret = ddi_intr_get_supported_types(dev->dip, &intr_types); if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Failed to retrieve intr types 0x%x", ret); return (DDI_FAILURE); } + dev->rx_rings = min(dev->rx_rings, ncpus + dev->rss_cnt); + dev->tx_rings = min(dev->tx_rings, ncpus); + #ifdef __sparc + nreqd = min(dev->tx_rings + dev->rx_rings - dev->rss_cnt, ncpus); + dev->rx_group[0].eq_idx = dev->tx_rings; + #else + nreqd = max(dev->tx_rings, dev->rx_rings - dev->rss_cnt); + #endif + min = OCE_MIN_VECTORS; + retry_intr: + if (intr_types & DDI_INTR_TYPE_MSIX) { dev->intr_type = DDI_INTR_TYPE_MSIX; ! } else { ! oce_log(dev, CE_WARN, MOD_CONFIG, "%s", ! "MSIX not available"); ! ! if (intr_types & DDI_INTR_TYPE_FIXED) { dev->intr_type = DDI_INTR_TYPE_FIXED; + dev->rx_rings = dev->tx_rings = min; + } else { + return (DDI_FAILURE); + } nreqd = OCE_MIN_VECTORS; } ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, ! "Could not get supported intrs:0x%x", ret); return (DDI_FAILURE); } /* get the number of vectors available */ ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail); if (ret != DDI_SUCCESS || navail < min) { ! oce_log(dev, CE_NOTE, MOD_CONFIG, ! "Vectors: supported:0x%x, available:0x%x, ret:0x%x", ! nsupported, navail, ret); ! intr_types &= ~dev->intr_type; ! goto retry_intr; } if (navail < nreqd) { nreqd = navail; } /* allocate htable */
*** 99,155 **** dev->htable = kmem_zalloc(dev->hsize, KM_NOSLEEP); if (dev->htable == NULL) return (DDI_FAILURE); ! nallocd = 0; ! /* allocate interrupt handlers */ ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type, 0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL); ! if (ret != DDI_SUCCESS) { ! goto fail_intr; } - dev->num_vectors = nallocd; - if (nallocd < min) { - goto fail_intr; - } - /* * get the interrupt priority. Assumption is that all handlers have * equal priority */ ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri); if (ret != DDI_SUCCESS) { ! goto fail_intr; } (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap); ! if ((intr_types & DDI_INTR_TYPE_MSIX) && (nallocd > 1)) { ! dev->rx_rings = nallocd - 1; } else { ! dev->rx_rings = 1; } return (DDI_SUCCESS); - - fail_intr: - (void) oce_teardown_intr(dev); - if ((dev->intr_type == DDI_INTR_TYPE_MSIX) && - (intr_types & DDI_INTR_TYPE_FIXED)) { - intr_types &= ~DDI_INTR_TYPE_MSIX; - oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", - "Could not get MSIX vectors, trying for FIXED vectors"); - goto retry_intr; - } - return (DDI_FAILURE); } /* * top level function to undo initialization in oce_setup_intr * * dev - software handle to the device * --- 117,174 ---- dev->htable = kmem_zalloc(dev->hsize, KM_NOSLEEP); if (dev->htable == NULL) return (DDI_FAILURE); ! /* allocate interrupt */ ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type, 0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL); ! if (ret != DDI_SUCCESS || nallocd < min) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Alloc intr failed: %d %d", ! navail, ret); ! kmem_free(dev->htable, nreqd * sizeof (ddi_intr_handle_t)); ! intr_types &= ~dev->intr_type; ! goto retry_intr; } /* * get the interrupt priority. Assumption is that all handlers have * equal priority */ ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri); if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Unable to get intr priority: 0x%x", ret); ! ! for (i = 0; i < dev->num_vectors; i++) { ! (void) ddi_intr_free(dev->htable[i]); } + kmem_free(dev->htable, nreqd * sizeof (ddi_intr_handle_t)); + return (DDI_FAILURE); + } (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap); ! /* update the actual number of interrupts allocated */ ! dev->num_vectors = nallocd; ! if (oce_irm_enable && dev->intr_type == DDI_INTR_TYPE_MSIX) { ! dev->max_vectors = nreqd; } else { ! dev->max_vectors = nallocd; ! dev->tx_rings = min(dev->tx_rings, nallocd); ! dev->rx_rings = min(dev->rx_rings, nallocd + dev->rss_cnt); } + oce_group_rings(dev); return (DDI_SUCCESS); } + /* * top level function to undo initialization in oce_setup_intr * * dev - software handle to the device *
*** 166,176 **** } /* release htable */ kmem_free(dev->htable, dev->hsize); dev->htable = NULL; ! return (DDI_SUCCESS); } /* * helper function to add ISR based on interrupt type --- 185,197 ---- } /* release htable */ kmem_free(dev->htable, dev->hsize); dev->htable = NULL; ! if (dev->attach_state & ATTACH_CB_REG) { ! (void) ddi_cb_unregister(dev->cb_handle); ! } return (DDI_SUCCESS); } /* * helper function to add ISR based on interrupt type
*** 184,197 **** { int i = 0; int ret; for (i = 0; i < dev->num_vectors; i++) { ret = ddi_intr_add_handler(dev->htable[i], oce_isr, ! (caddr_t)dev->eq[i], NULL); if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, "%s", ! "Failed to add interrupt handlers"); for (i--; i >= 0; i--) { (void) ddi_intr_remove_handler(dev->htable[i]); } return (DDI_FAILURE); } --- 205,219 ---- { int i = 0; int ret; for (i = 0; i < dev->num_vectors; i++) { ret = ddi_intr_add_handler(dev->htable[i], oce_isr, ! (caddr_t)&dev->eq[i], NULL); if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Failed to add interrupt handler %d, ret = 0x%x", ! i, ret); for (i--; i >= 0; i--) { (void) ddi_intr_remove_handler(dev->htable[i]); } return (DDI_FAILURE); }
*** 230,259 **** * * dev - software handle to the device * * return DDI_SUCCESS => success, failure otherwise */ ! void oce_ei(struct oce_dev *dev) { int i; int ret; if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) { ! (void) ddi_intr_block_enable(dev->htable, dev->num_vectors); } else { - for (i = 0; i < dev->num_vectors; i++) { ret = ddi_intr_enable(dev->htable[i]); if (ret != DDI_SUCCESS) { for (i--; i >= 0; i--) { (void) ddi_intr_disable(dev->htable[i]); } } } } ! oce_chip_ei(dev); } /* oce_ei */ void oce_chip_di(struct oce_dev *dev) { --- 252,291 ---- * * dev - software handle to the device * * return DDI_SUCCESS => success, failure otherwise */ ! int oce_ei(struct oce_dev *dev) { int i; int ret; if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) { ! ret = ddi_intr_block_enable(dev->htable, dev->num_vectors); ! if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Interrupts block enable failed :%d\n", ret); ! return (DDI_FAILURE); ! } } else { for (i = 0; i < dev->num_vectors; i++) { ret = ddi_intr_enable(dev->htable[i]); if (ret != DDI_SUCCESS) { + oce_log(dev, CE_WARN, MOD_CONFIG, + "Failed to enable, ret %d, interrupt %d," + " type %d, cnt %d ", + ret, i, dev->intr_type, dev->num_vectors); for (i--; i >= 0; i--) { (void) ddi_intr_disable(dev->htable[i]); } + return (DDI_FAILURE); } } } ! ! return (DDI_SUCCESS); } /* oce_ei */ void oce_chip_di(struct oce_dev *dev) {
*** 269,353 **** * * dev - software handle to the device * * return DDI_SUCCESS => success, failure otherwise */ ! void oce_di(struct oce_dev *dev) { int i; int ret; oce_chip_di(dev); if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) { ! (void) ddi_intr_block_disable(dev->htable, dev->num_vectors); } else { for (i = 0; i < dev->num_vectors; i++) { ret = ddi_intr_disable(dev->htable[i]); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, ! "Failed to disable interrupts 0x%x", ret); } } } ! } /* oce_di */ ! /* ! * command interrupt handler routine added to all vectors ! * ! * arg1 = callback data ! * arg2 - callback data ! * ! * return DDI_INTR_CLAIMED => interrupt was claimed by the ISR ! */ ! static uint_t ! oce_isr(caddr_t arg1, caddr_t arg2) { ! struct oce_eq *eq; struct oce_eqe *eqe; uint16_t num_eqe = 0; uint16_t cq_id; struct oce_cq *cq; struct oce_dev *dev; - _NOTE(ARGUNUSED(arg2)); - - eq = (struct oce_eq *)(void *)(arg1); - dev = eq->parent; eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); ! while (eqe->u0.dw0) { ! eqe->u0.dw0 = LE_32(eqe->u0.dw0); - /* if not CQ then continue else flag an error */ - if (EQ_MAJOR_CODE_COMPLETION != eqe->u0.s.major_code) { - oce_log(dev, CE_WARN, MOD_ISR, - "NOT a CQ event. 0x%x", - eqe->u0.s.major_code); - } - /* get the cq from the eqe */ cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ; cq = dev->cq[cq_id]; - /* Call the completion handler */ - (void) cq->cq_handler(cq->cb_arg); - /* clear valid bit and progress eqe */ eqe->u0.dw0 = 0; RING_GET(eq->ring, 1); - eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); num_eqe++; - } /* for all EQEs */ /* ring the eq doorbell, signify that it's done processing */ oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE); ! if (num_eqe > 0) { return (DDI_INTR_CLAIMED); } else { return (DDI_INTR_UNCLAIMED); } ! } /* oce_msix_handler */ --- 301,597 ---- * * dev - software handle to the device * * return DDI_SUCCESS => success, failure otherwise */ ! int oce_di(struct oce_dev *dev) { int i; int ret; + dev->state &= ~STATE_INTR_ENABLED; + if (!LANCER_CHIP(dev)) oce_chip_di(dev); + if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) { ! ret = ddi_intr_block_disable(dev->htable, dev->num_vectors); ! if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "Interrupt block disable failed :%d\n", ret); ! return (DDI_FAILURE); ! } } else { for (i = 0; i < dev->num_vectors; i++) { ret = ddi_intr_disable(dev->htable[i]); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, ! "Failed to disable the interrupts 0x%x", ! ret); ! return (DDI_FAILURE); } } } ! return (DDI_SUCCESS); } /* oce_di */ ! ! int ! oce_ring_intr_enable(mac_intr_handle_t ring_handle) { ! struct oce_rq *rx_ring = (struct oce_rq *)ring_handle; ! struct oce_dev *dev; ! dev = rx_ring->parent; ! oce_group_t *grp = rx_ring->grp; ! mutex_enter(&grp->grp_lock); ! if (grp->state & GROUP_SUSPEND) { ! mutex_exit(&grp->grp_lock); ! return (DDI_SUCCESS); ! } ! mutex_enter(&rx_ring->rx_lock); ! oce_arm_cq(dev, rx_ring->cq->cq_id, 0, B_TRUE); ! rx_ring->qmode = OCE_MODE_INTR; ! mutex_exit(&rx_ring->rx_lock); ! mutex_exit(&grp->grp_lock); ! return (DDI_SUCCESS); ! } ! ! ! int ! oce_ring_intr_disable(mac_intr_handle_t ring_handle) ! { ! struct oce_rq *rx_ring = (struct oce_rq *)ring_handle; ! struct oce_dev *dev; ! ! dev = rx_ring->parent; ! mutex_enter(&rx_ring->rx_lock); ! oce_arm_cq(dev, rx_ring->cq->cq_id, 0, B_FALSE); ! rx_ring->qmode = OCE_MODE_POLL; ! mutex_exit(&rx_ring->rx_lock); ! return (DDI_SUCCESS); ! } ! ! uint_t ! oce_ring_common_drain(struct oce_eq *eq) ! { struct oce_eqe *eqe; uint16_t num_eqe = 0; uint16_t cq_id; struct oce_cq *cq; struct oce_dev *dev; dev = eq->parent; eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); ! if (eqe->u0.dw0) { eqe->u0.dw0 = LE_32(eqe->u0.dw0); /* get the cq from the eqe */ cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ; cq = dev->cq[cq_id]; /* clear valid bit and progress eqe */ eqe->u0.dw0 = 0; RING_GET(eq->ring, 1); num_eqe++; + if (cq) { + /* Call the completion handler */ + (void) cq->cq_handler(cq->cb_arg, 0, 0); + } + } + /* ring the eq doorbell, signify that it's done processing */ oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE); ! ! return (num_eqe); ! ! } /* oce_ring_common_drain */ ! ! ! /* MSI/INTX handler: common vector for TX/RX/MQ */ ! uint_t ! oce_isr(caddr_t arg1, caddr_t arg2) ! { ! struct oce_eq *eq; ! struct oce_dev *dev; ! uint16_t num_eqe = 0; ! ! _NOTE(ARGUNUSED(arg2)); ! ! eq = (struct oce_eq *)(void *)(arg1); ! dev = eq->parent; ! ! if ((dev == NULL) || ! !(dev->state & STATE_INTR_ENABLED)) { ! oce_log(dev, CE_WARN, MOD_CONFIG, "%s", ! "Dummy interrupt received"); return (DDI_INTR_CLAIMED); + } + + mutex_enter(&eq->lock); + if (eq->qstate != QSTARTED) { + mutex_exit(&eq->lock); + oce_log(dev, CE_WARN, MOD_CONFIG, "%s", + "oce_isr EQ Not started"); + return (DDI_INTR_CLAIMED); + } + num_eqe = oce_ring_common_drain(eq); + mutex_exit(&eq->lock); + if (num_eqe) { + return (DDI_INTR_CLAIMED); } else { return (DDI_INTR_UNCLAIMED); } ! } ! ! /* ! * IRM callback routine ! */ ! int ! oce_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg, ! void *arg1, void *arg2) ! { ! struct oce_dev *dev = (struct oce_dev *)arg1; ! int count = (int)(uintptr_t)cbarg, ret = DDI_ENOTSUP; ! ! _NOTE(ARGUNUSED(dip)); ! _NOTE(ARGUNUSED(arg2)); ! ! switch (cbaction) { ! case DDI_CB_INTR_ADD: ! case DDI_CB_INTR_REMOVE: ! ! oce_log(dev, CE_NOTE, MOD_CONFIG, ! "IRM cbaction %d count %d vectors %d max_vectors %d", ! cbaction, count, dev->num_vectors, dev->max_vectors); ! ret = oce_adjust_intrs(dev, cbaction, count); ! if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", ! "IRM: Failed to adjust interrupts"); ! return (ret); ! } ! break; ! ! default: ! return (ret); ! } ! return (ret); ! } ! ! ! static int ! oce_adjust_intrs(struct oce_dev *dev, ddi_cb_action_t action, int count) ! { ! int i, nallocd, ret; ! ! if (count == 0) ! return (DDI_SUCCESS); ! ! if ((action == DDI_CB_INTR_ADD && ! dev->num_vectors + count > dev->max_vectors) || ! (action == DDI_CB_INTR_REMOVE && ! dev->num_vectors - count < OCE_MIN_VECTORS)) { ! return (DDI_FAILURE); ! } ! ! if (!(dev->state & STATE_MAC_STARTED)) { ! return (DDI_FAILURE); ! } ! ! mutex_enter(&dev->dev_lock); ! dev->state |= STATE_INTR_ADJUST; ! dev->suspended = B_TRUE; ! ! /* stop the groups */ ! for (i = 0; i < dev->num_rx_groups; i++) { ! mutex_enter(&dev->rx_group[i].grp_lock); ! oce_suspend_group_rings(&dev->rx_group[i]); ! oce_stop_group(&dev->rx_group[i], B_FALSE); ! mutex_exit(&dev->rx_group[i].grp_lock); ! } ! ! oce_stop(dev); ! oce_remove_handler(dev); ! if (action == DDI_CB_INTR_ADD) { ! /* allocate additional vectors */ ! ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_MSIX, ! dev->num_vectors, count, &nallocd, DDI_INTR_ALLOC_NORMAL); ! ! if (ret != DDI_SUCCESS) { ! goto irm_fail; ! } ! ! /* update actual count of available interrupts */ ! dev->num_vectors += nallocd; ! oce_log(dev, CE_NOTE, MOD_CONFIG, ! "IRM: INTR_ADD - count=0x%x allocated=0x%x vectors=0x%x", ! count, nallocd, dev->num_vectors); ! } else { ! /* free interrupt vectors */ ! for (i = dev->num_vectors - count; ! i < dev->num_vectors; i++) { ! ret = ddi_intr_free(dev->htable[i]); ! if (ret != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, ! "IRM: can't free vectors ret 0x%x", ret); ! goto irm_fail; ! } ! dev->htable[i] = NULL; ! } ! ! /* update actual count of available interrupts */ ! dev->num_vectors -= count; ! oce_log(dev, CE_NOTE, MOD_CONFIG, ! "IRM: INTR_REMOVE - count = 0x%x vectors = 0x%x", ! count, dev->num_vectors); ! } ! ! if (oce_setup_handlers(dev) != DDI_SUCCESS) { ! oce_log(dev, CE_WARN, MOD_CONFIG, "%s", ! "Failed to Setup handlers during IRM"); ! goto irm_fail; ! } ! ! /* re-start the device instance */ ! if (oce_start(dev) != DDI_SUCCESS) { ! goto irm_fail; ! } ! ! ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri); ! ! if (ret != DDI_SUCCESS) { ! goto irm_fail; ! } ! ! (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap); ! ! /* re-start the groups */ ! for (i = 0; i < dev->num_rx_groups; i++) { ! mutex_enter(&dev->rx_group[i].grp_lock); ! ret = oce_start_group(&dev->rx_group[i], B_FALSE); ! if (ret == DDI_SUCCESS) { ! ret = oce_resume_group_rings(&dev->rx_group[i]); ! } ! mutex_exit(&dev->rx_group[i].grp_lock); ! if (ret != DDI_SUCCESS) { ! goto irm_fail; ! } ! } ! dev->state &= ~STATE_INTR_ADJUST; ! dev->suspended = B_FALSE; ! mutex_exit(&dev->dev_lock); ! ! /* Wakeup all Tx rings */ ! for (i = 0; i < dev->tx_rings; i++) { ! mac_tx_ring_update(dev->mac_handle, ! dev->default_tx_rings[i].tx->handle); ! } ! ! return (DDI_SUCCESS); ! ! irm_fail: ! ddi_fm_service_impact(dev->dip, DDI_SERVICE_LOST); ! mutex_exit(&dev->dev_lock); ! return (DDI_FAILURE); ! }