Mercurial > illumos > wpa
changeset 13032:1b6086d6d5a1
6941306 oce driver performance is <3G on certain sparc platforms
line wrap: on
line diff
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_buf.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_buf.c Thu Aug 05 11:14:15 2010 -0600 @@ -64,7 +64,7 @@ */ oce_dma_buf_t * oce_alloc_dma_buffer(struct oce_dev *dev, - uint32_t size, uint32_t flags) + uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags) { oce_dma_buf_t *dbuf; ddi_dma_cookie_t cookie; @@ -73,6 +73,10 @@ int ret = 0; ASSERT(size > 0); + /* if NULL use default */ + if (dma_attr == NULL) { + dma_attr = &oce_dma_buf_attr; + } dbuf = kmem_zalloc(sizeof (oce_dma_buf_t), KM_NOSLEEP); if (dbuf == NULL) { @@ -80,12 +84,12 @@ } /* allocate dma handle */ - ret = ddi_dma_alloc_handle(dev->dip, &oce_dma_buf_attr, + ret = ddi_dma_alloc_handle(dev->dip, dma_attr, DDI_DMA_DONTWAIT, NULL, &dbuf->dma_handle); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "Failed to allocate DMA handle"); - goto alloc_fail; + goto handle_fail; } /* allocate the DMA-able memory */ ret = ddi_dma_mem_alloc(dbuf->dma_handle, size, &oce_dma_buf_accattr, @@ -105,7 +109,7 @@ if (ret != DDI_DMA_MAPPED) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "Failed to bind dma handle"); - goto alloc_fail; + goto bind_fail; } bzero(dbuf->base, actual_len); dbuf->addr = cookie.dmac_laddress; @@ -114,8 +118,13 @@ dbuf->len = size; dbuf->num_pages = OCE_NUM_PAGES(size); return (dbuf); + +bind_fail: + ddi_dma_mem_free(&dbuf->acc_handle); alloc_fail: - oce_free_dma_buffer(dev, dbuf); + ddi_dma_free_handle(&dbuf->dma_handle); +handle_fail: + kmem_free(dbuf, sizeof (oce_dma_buf_t)); return (NULL); } /* oce_dma_alloc_buffer */ @@ -172,7 +181,7 @@ /* get the dbuf defining the ring */ size = num_items * item_size; - ring->dbuf = oce_alloc_dma_buffer(dev, size, flags); + ring->dbuf = oce_alloc_dma_buffer(dev, size, NULL, flags); if (ring->dbuf == NULL) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "Ring buffer allocation failed");
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_gld.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_gld.c Thu Aug 05 11:14:15 2010 -0600 @@ -41,8 +41,9 @@ NULL }; +extern int pow10[]; + /* ---[ static function declarations ]----------------------------------- */ -static int oce_power10(int power); static int oce_set_priv_prop(struct oce_dev *dev, const char *name, uint_t size, const void *val); @@ -103,35 +104,25 @@ oce_start(struct oce_dev *dev) { int qidx = 0; - int ret; + struct link_status link = {0}; - ret = oce_alloc_intr(dev); - if (ret != DDI_SUCCESS) - goto start_fail; - ret = oce_setup_handlers(dev); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "Interrupt handler setup failed with %d", ret); - (void) oce_teardown_intr(dev); - goto start_fail; - } /* get link status */ - (void) oce_get_link_status(dev, &dev->link); + (void) oce_get_link_status(dev, &link); + + dev->link_status = (link.logical_link_status == NTWK_LOGICAL_LINK_UP) ? + LINK_STATE_UP : LINK_STATE_DOWN; - if (dev->link.mac_speed == PHY_LINK_SPEED_ZERO) { - oce_log(dev, CE_NOTE, MOD_CONFIG, - "LINK_DOWN: 0x%x", dev->link.mac_speed); - mac_link_update(dev->mac_handle, LINK_STATE_DOWN); - } else { - oce_log(dev, CE_NOTE, MOD_CONFIG, - "(f,s,d,pp)=(0x%x, 0x%x, 0x%x, 0x%x)", - dev->link.mac_fault, dev->link.mac_speed, - dev->link.mac_duplex, dev->link.physical_port); - mac_link_update(dev->mac_handle, LINK_STATE_UP); + dev->link_speed = link.qos_link_speed ? link.qos_link_speed * 10 : + pow10[link.mac_speed]; + + mac_link_update(dev->mac_handle, dev->link_status); + + for (qidx = 0; qidx < dev->nwqs; qidx++) { + (void) oce_start_wq(dev->wq[qidx]); } - - (void) oce_start_wq(dev->wq[0]); - (void) oce_start_rq(dev->rq[0]); + for (qidx = 0; qidx < dev->nrqs; qidx++) { + (void) oce_start_rq(dev->rq[qidx]); + } (void) oce_start_mq(dev->mq); /* enable interrupts */ oce_ei(dev); @@ -139,11 +130,8 @@ for (qidx = 0; qidx < dev->neqs; qidx++) { oce_arm_eq(dev, dev->eq[qidx]->eq_id, 0, B_TRUE, B_FALSE); } - - /* update state */ + /* TODO update state */ return (DDI_SUCCESS); -start_fail: - return (DDI_FAILURE); } /* oce_start */ @@ -168,19 +156,24 @@ void oce_stop(struct oce_dev *dev) { + int qidx; /* disable interrupts */ oce_di(dev); - oce_remove_handler(dev); - (void) oce_teardown_intr(dev); - mutex_enter(&dev->wq[0]->tx_lock); - mutex_enter(&dev->rq[0]->rx_lock); + for (qidx = 0; qidx < dev->nwqs; qidx++) { + mutex_enter(&dev->wq[qidx]->tx_lock); + } mutex_enter(&dev->mq->lock); /* complete the pending Tx */ - oce_clean_wq(dev->wq[0]); + for (qidx = 0; qidx < dev->nwqs; qidx++) + oce_clean_wq(dev->wq[qidx]); /* Release all the locks */ mutex_exit(&dev->mq->lock); - mutex_exit(&dev->rq[0]->rx_lock); - mutex_exit(&dev->wq[0]->tx_lock); + for (qidx = 0; qidx < dev->nwqs; qidx++) + mutex_exit(&dev->wq[qidx]->tx_lock); + if (dev->link_status == LINK_STATE_UP) { + dev->link_status = LINK_STATE_UNKNOWN; + mac_link_update(dev->mac_handle, dev->link_status); + } } /* oce_stop */ @@ -191,7 +184,7 @@ struct oce_dev *dev = (struct oce_dev *)arg; struct ether_addr *mca_drv_list; struct ether_addr mca_hw_list[OCE_MAX_MCA]; - uint16_t new_mcnt = 0; + uint16_t new_mcnt = dev->num_mca; int ret; int i; @@ -206,7 +199,7 @@ DEV_LOCK(dev); if (add) { /* check if we exceeded hw max supported */ - if (dev->num_mca <= OCE_MAX_MCA) { + if (new_mcnt < OCE_MAX_MCA) { /* copy entire dev mca to the mbx */ bcopy((void*)mca_drv_list, (void*)mca_hw_list, @@ -215,7 +208,7 @@ bcopy(mca, &mca_hw_list[dev->num_mca], sizeof (struct ether_addr)); } - new_mcnt = dev->num_mca + 1; + new_mcnt++; } else { struct ether_addr *hwlistp = &mca_hw_list[0]; for (i = 0; i < dev->num_mca; i++) { @@ -224,16 +217,18 @@ bcopy(mca_drv_list + i, hwlistp, ETHERADDRL); hwlistp++; + } else { + new_mcnt--; } } - new_mcnt = dev->num_mca - 1; } if (dev->suspended) { goto finish; } - if (new_mcnt == 0 || new_mcnt > OCE_MAX_MCA) { - ret = oce_set_multicast_table(dev, dev->if_id, NULL, 0, B_TRUE); + if (new_mcnt > OCE_MAX_MCA) { + ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0], + OCE_MAX_MCA, B_TRUE); } else { ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0], new_mcnt, B_FALSE); @@ -249,8 +244,9 @@ if (new_mcnt && new_mcnt <= OCE_MAX_MCA) { bcopy(mca_hw_list, mca_drv_list, new_mcnt * sizeof (struct ether_addr)); + + dev->num_mca = (uint16_t)new_mcnt; } - dev->num_mca = (uint16_t)new_mcnt; DEV_UNLOCK(dev); return (0); } /* oce_m_multicast */ @@ -274,6 +270,7 @@ DEV_UNLOCK(dev); return (EIO); } + bzero(dev->unicast_addr, ETHERADDRL); /* Set the New MAC addr earlier is no longer valid */ ret = oce_add_mac(dev, dev->if_id, uca, &dev->pmac_id); @@ -281,10 +278,15 @@ DEV_UNLOCK(dev); return (EIO); } + bcopy(uca, dev->unicast_addr, ETHERADDRL); DEV_UNLOCK(dev); return (ret); } /* oce_m_unicast */ +/* + * Hashing policy for load balancing over the set of TX rings + * available to the driver. + */ mblk_t * oce_m_send(void *arg, mblk_t *mp) { @@ -300,7 +302,10 @@ return (NULL); } DEV_UNLOCK(dev); - wq = dev->wq[0]; + /* + * Hash to pick a wq + */ + wq = oce_get_wq(dev, mp); while (mp != NULL) { /* Save the Pointer since mp will be freed in case of copy */ @@ -469,12 +474,20 @@ case MAC_PROP_SPEED: { uint64_t *speed = (uint64_t *)val; + struct link_status link = {0}; ASSERT(size >= sizeof (uint64_t)); *speed = 0; - if ((dev->state & STATE_MAC_STARTED) && - (dev->link.mac_speed != 0)) { - *speed = 1000000ull * oce_power10(dev->link.mac_speed); + + if (dev->state & STATE_MAC_STARTED) { + if (dev->link_speed < 0) { + (void) oce_get_link_status(dev, &link); + dev->link_speed = link.qos_link_speed ? + link.qos_link_speed * 10 : + pow10[link.mac_speed]; + } + + *speed = dev->link_speed * 1000000ull; } break; } @@ -631,18 +644,6 @@ return (ret); } /* oce_m_promiscuous */ -static int -oce_power10(int power) -{ - int ret = 1; - - while (power) { - ret *= 10; - power--; - } - return (ret); -} - /* * function to set a private property. * Called from the set_prop GLD entry point
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_hw.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_hw.c Thu Aug 05 11:14:15 2010 -0600 @@ -158,6 +158,7 @@ ret = oce_map_regs(dev); if (ret != DDI_SUCCESS) { + pci_config_teardown(&dev->pci_cfg_handle); return (DDI_FAILURE); } dev->fn = OCE_PCI_FUNC(dev); @@ -335,9 +336,16 @@ oce_create_nw_interface(struct oce_dev *dev) { int ret; + uint32_t capab_flags = OCE_CAPAB_FLAGS; + uint32_t capab_en_flags = OCE_CAPAB_ENABLE; + + if (dev->rss_enable) { + capab_flags |= MBX_RX_IFACE_FLAGS_RSS; + capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS; + } /* create an interface for the device with out mac */ - ret = oce_if_create(dev, OCE_DEFAULT_IF_CAP, OCE_DEFAULT_IF_CAP_EN, + ret = oce_if_create(dev, capab_flags, capab_en_flags, 0, &dev->mac_addr[0], (uint32_t *)&dev->if_id); if (ret != 0) { oce_log(dev, CE_WARN, MOD_CONFIG, @@ -346,7 +354,7 @@ } atomic_inc_32(&dev->nifs); - dev->if_cap_flags = OCE_DEFAULT_IF_CAP_EN; + dev->if_cap_flags = capab_en_flags; /* Enable VLAN Promisc on HW */ ret = oce_config_vlan(dev, (uint8_t)dev->if_id, NULL, 0, @@ -371,17 +379,6 @@ oce_log(dev, CE_NOTE, MOD_CONFIG, "Set Promisc failed: %d", ret); } -#if 0 - /* this could happen if the driver is resuming after suspend */ - if (dev->num_mca > 0) { - ret = oce_set_multicast_table(dev, dev->multi_cast, - dev->num_mca); - if (ret != 0) { - oce_log(dev, CE_NOTE, MOD_CONFIG, - "Set Multicast failed: %d", ret); - } - } -#endif return (0); } @@ -396,11 +393,28 @@ } } +static void +oce_create_itbl(struct oce_dev *dev, char *itbl) +{ + int i; + struct oce_rq **rss_queuep = &dev->rq[1]; + int nrss = dev->nrqs - 1; + /* fill the indirection table rq 0 is default queue */ + for (i = 0; i < OCE_ITBL_SIZE; i++) { + itbl[i] = rss_queuep[i % nrss]->rss_cpuid; + } +} int oce_setup_adapter(struct oce_dev *dev) { int ret; + char itbl[OCE_ITBL_SIZE]; + char hkey[OCE_HKEY_SIZE]; + + /* disable the interrupts here and enable in start */ + oce_chip_di(dev); + ret = oce_create_nw_interface(dev); if (ret != DDI_SUCCESS) { return (DDI_FAILURE); @@ -410,12 +424,47 @@ oce_delete_nw_interface(dev); return (DDI_FAILURE); } + if (dev->rss_enable) { + (void) oce_create_itbl(dev, itbl); + (void) oce_gen_hkey(hkey, OCE_HKEY_SIZE); + ret = oce_config_rss(dev, dev->if_id, hkey, itbl, OCE_ITBL_SIZE, + OCE_DEFAULT_RSS_TYPE, B_TRUE); + if (ret != DDI_SUCCESS) { + oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", + "Failed to Configure RSS"); + oce_delete_queues(dev); + oce_delete_nw_interface(dev); + return (ret); + } + } + ret = oce_setup_handlers(dev); + if (ret != DDI_SUCCESS) { + oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", + "Failed to Setup handlers"); + oce_delete_queues(dev); + oce_delete_nw_interface(dev); + return (ret); + } return (DDI_SUCCESS); } void oce_unsetup_adapter(struct oce_dev *dev) { + oce_remove_handler(dev); + if (dev->rss_enable) { + char itbl[OCE_ITBL_SIZE] = {0}; + char hkey[OCE_HKEY_SIZE] = {0}; + int ret = 0; + + ret = oce_config_rss(dev, dev->if_id, hkey, itbl, OCE_ITBL_SIZE, + RSS_ENABLE_NONE, B_TRUE); + + if (ret != DDI_SUCCESS) { + oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", + "Failed to Disable RSS"); + } + } oce_delete_queues(dev); oce_delete_nw_interface(dev); } @@ -435,7 +484,7 @@ } /* create bootstrap mailbox */ dev->bmbx = oce_alloc_dma_buffer(dev, - sizeof (struct oce_bmbx), DDI_DMA_CONSISTENT); + sizeof (struct oce_bmbx), NULL, DDI_DMA_CONSISTENT); if (dev->bmbx == NULL) { oce_log(dev, CE_WARN, MOD_CONFIG, "Failed to allocate bmbx: size = %u",
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_intr.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_intr.c Thu Aug 05 11:14:15 2010 -0600 @@ -31,17 +31,8 @@ #include <oce_impl.h> -static int oce_setup_msix(struct oce_dev *dev); -static int oce_teardown_msix(struct oce_dev *dev); -static int oce_add_msix_handlers(struct oce_dev *dev); -static void oce_del_msix_handlers(struct oce_dev *dev); static uint_t oce_isr(caddr_t arg1, caddr_t arg2); -static int oce_setup_intx(struct oce_dev *dev); -static int oce_teardown_intx(struct oce_dev *dev); -static int oce_add_intx_handlers(struct oce_dev *dev); -static void oce_del_intx_handlers(struct oce_dev *dev); - /* * top level function to setup interrupts * @@ -54,6 +45,11 @@ { 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); @@ -63,30 +59,94 @@ return (DDI_FAILURE); } +retry_intr: if (intr_types & DDI_INTR_TYPE_MSIX) { - dev->intr_types = DDI_INTR_TYPE_MSIX; - dev->num_vectors = 2; - return (DDI_SUCCESS); + 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; } - if (intr_types & DDI_INTR_TYPE_FIXED) { - dev->intr_types = DDI_INTR_TYPE_FIXED; - dev->num_vectors = 1; - return (DDI_SUCCESS); - } - return (DDI_FAILURE); -} + /* allocate htable */ + dev->hsize = nreqd * sizeof (ddi_intr_handle_t); + dev->htable = kmem_zalloc(dev->hsize, KM_NOSLEEP); + + if (dev->htable == NULL) + return (DDI_FAILURE); -int -oce_alloc_intr(struct oce_dev *dev) -{ - if (dev->intr_types == DDI_INTR_TYPE_MSIX) { - return (oce_setup_msix(dev)); + 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; } - if (dev->intr_types == DDI_INTR_TYPE_FIXED) { - return (oce_setup_intx(dev)); + + 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); } @@ -100,15 +160,18 @@ int oce_teardown_intr(struct oce_dev *dev) { - if (dev->intr_types == DDI_INTR_TYPE_MSIX) { - return (oce_teardown_msix(dev)); + int i; + + /* release handlers */ + for (i = 0; i < dev->num_vectors; i++) { + (void) ddi_intr_free(dev->htable[i]); } - if (dev->intr_types == DDI_INTR_TYPE_FIXED) { - return (oce_teardown_intx(dev)); - } + /* release htable */ + kmem_free(dev->htable, dev->hsize); + dev->htable = NULL; - return (DDI_FAILURE); + return (DDI_SUCCESS); } /* @@ -121,15 +184,21 @@ int oce_setup_handlers(struct oce_dev *dev) { - if (dev->intr_types == DDI_INTR_TYPE_MSIX) { - return (oce_add_msix_handlers(dev)); + 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); + } } - - if (dev->intr_types == DDI_INTR_TYPE_FIXED) { - return (oce_add_intx_handlers(dev)); - } - - return (DDI_FAILURE); + return (DDI_SUCCESS); } /* @@ -142,12 +211,9 @@ void oce_remove_handler(struct oce_dev *dev) { - if (dev->intr_types == DDI_INTR_TYPE_MSIX) { - oce_del_msix_handlers(dev); - } - - if (dev->intr_types == DDI_INTR_TYPE_FIXED) { - oce_del_intx_handlers(dev); + int nvec; + for (nvec = 0; nvec < dev->num_vectors; nvec++) { + (void) ddi_intr_remove_handler(dev->htable[nvec]); } } @@ -225,6 +291,7 @@ 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 { @@ -236,160 +303,9 @@ } } } - oce_chip_di(dev); } /* oce_di */ /* - * function to setup the MSIX vectors - * - * dev - software handle to the device - * - * return 0=>success, failure otherwise - */ -static int -oce_setup_msix(struct oce_dev *dev) -{ - int navail = 0; - int ret = 0; - - ret = ddi_intr_get_nintrs(dev->dip, DDI_INTR_TYPE_MSIX, &navail); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "Could not get nintrs:0x%x %d", - navail, ret); - return (DDI_FAILURE); - } - - /* get the number of vectors available */ - ret = ddi_intr_get_navail(dev->dip, DDI_INTR_TYPE_MSIX, &navail); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "Could not get msix vectors:0x%x", - navail); - return (DDI_FAILURE); - } - - if (navail < dev->num_vectors) - return (DDI_FAILURE); - - /* allocate htable */ - dev->htable = kmem_zalloc(dev->num_vectors * - sizeof (ddi_intr_handle_t), KM_NOSLEEP); - - if (dev->htable == NULL) - return (DDI_FAILURE); - - /* allocate interrupt handlers */ - ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_MSIX, - 0, dev->num_vectors, &navail, DDI_INTR_ALLOC_NORMAL); - - if (ret != DDI_SUCCESS || navail < dev->num_vectors) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "Alloc intr failed: %d %d", - navail, ret); - kmem_free(dev->htable, - dev->num_vectors * sizeof (ddi_intr_handle_t)); - return (DDI_FAILURE); - } - - /* update the actual number of interrupts allocated */ - dev->num_vectors = navail; - - /* - * 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) { - int i; - oce_log(dev, CE_WARN, MOD_CONFIG, - "Unable to get intr priority: 0x%x", - dev->intr_pri); - for (i = 0; i < dev->num_vectors; i++) { - (void) ddi_intr_free(dev->htable[i]); - } - kmem_free(dev->htable, - dev->num_vectors * sizeof (ddi_intr_handle_t)); - return (DDI_FAILURE); - } - - (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap); - return (DDI_SUCCESS); -} /* oce_setup_msix */ - -/* - * helper function to teardown MSIX interrupts - * - * dev - software handle to the device - * - * return 0 => success, failure otherwise - */ -static int -oce_teardown_msix(struct oce_dev *dev) -{ - int i; - - /* release handlers */ - for (i = 0; i < dev->num_vectors; i++) { - (void) ddi_intr_free(dev->htable[i]); - } - - /* release htable */ - kmem_free(dev->htable, - dev->num_vectors * sizeof (ddi_intr_handle_t)); - - return (DDI_SUCCESS); -} /* oce_teardown_msix */ - -/* - * function to add MSIX handlers to vectors - * - * dev - software handle to the device - * - * return DDI_SUCCESS => success, failure otherwise - */ -static int -oce_add_msix_handlers(struct oce_dev *dev) -{ - int ret; - int i; - - for (i = 0; i < dev->neqs; 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); - } - } - - return (DDI_SUCCESS); -} /* oce_add_msix_handlers */ - -/* - * function to disassociate msix handlers added in oce_add_msix_handlers - * - * dev - software handle to the device - * - * return DDI_SUCCESS => success, failure otherwise - */ -static void -oce_del_msix_handlers(struct oce_dev *dev) -{ - int nvec; - - for (nvec = 0; nvec < dev->num_vectors; nvec++) { - (void) ddi_intr_remove_handler(dev->htable[nvec]); - } -} /* oce_del_msix_handlers */ - -/* * command interrupt handler routine added to all vectors * * arg1 = callback data @@ -411,22 +327,8 @@ eq = (struct oce_eq *)(void *)(arg1); - if (eq == NULL) { - return (DDI_INTR_UNCLAIMED); - } dev = eq->parent; - /* If device is getting suspended or closing, then return */ - if ((dev == NULL) || - (dev->state & STATE_MAC_STOPPING) || - !(dev->state & STATE_MAC_STARTED) || - dev->suspended) { - return (DDI_INTR_UNCLAIMED); - } - - (void) ddi_dma_sync(eq->ring->dbuf->dma_handle, 0, 0, - DDI_DMA_SYNC_FORKERNEL); - eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); while (eqe->u0.dw0) { @@ -441,7 +343,7 @@ } /* get the cq from the eqe */ - cq_id = eqe->u0.s.resource_id; + cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ; cq = dev->cq[cq_id]; /* Call the completion handler */ @@ -455,119 +357,10 @@ } /* 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) { - oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE); return (DDI_INTR_CLAIMED); } else { return (DDI_INTR_UNCLAIMED); } } /* oce_msix_handler */ - -static int -oce_setup_intx(struct oce_dev *dev) -{ - int navail = 0; - int nintr = 0; - int ret = 0; - - ret = ddi_intr_get_nintrs(dev->dip, DDI_INTR_TYPE_FIXED, &nintr); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "could not get nintrs:0x%x %d", - navail, ret); - return (DDI_FAILURE); - } - - /* get the number of vectors available */ - ret = ddi_intr_get_navail(dev->dip, DDI_INTR_TYPE_FIXED, &navail); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "could not get intx vectors:0x%x", - navail); - return (DDI_FAILURE); - } - - /* always 1 */ - if (navail != nintr) - return (DDI_FAILURE); - - dev->num_vectors = navail; - - /* allocate htable */ - dev->htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_NOSLEEP); - if (dev->htable == NULL) { - return (DDI_FAILURE); - } - - /* allocate interrupt handlers */ - ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_FIXED, - 0, dev->num_vectors, &navail, DDI_INTR_ALLOC_NORMAL); - - if (ret != DDI_SUCCESS || navail != 1) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "alloc intr failed: %d %d", - navail, ret); - kmem_free(dev->htable, sizeof (ddi_intr_handle_t)); - return (DDI_FAILURE); - } - - /* update the actual number of interrupts allocated */ - dev->num_vectors = navail; - - /* - * 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) { - int i; - oce_log(dev, CE_WARN, MOD_CONFIG, - "Unable to get intr priority: 0x%x", - dev->intr_pri); - for (i = 0; i < dev->num_vectors; i++) { - (void) ddi_intr_free(dev->htable[i]); - } - kmem_free(dev->htable, sizeof (ddi_intr_handle_t)); - return (DDI_FAILURE); - } - - (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap); - return (DDI_SUCCESS); -} /* oce_setup_intx */ - -static int -oce_teardown_intx(struct oce_dev *dev) -{ - /* release handlers */ - (void) ddi_intr_free(dev->htable[0]); - - /* release htable */ - kmem_free(dev->htable, sizeof (ddi_intr_handle_t)); - - return (DDI_FAILURE); -} /* oce_teardown_intx */ - -static int -oce_add_intx_handlers(struct oce_dev *dev) -{ - int ret; - - ret = ddi_intr_add_handler(dev->htable[0], oce_isr, - (caddr_t)dev->eq[0], NULL); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", - "failed to add intr handlers"); - (void) ddi_intr_remove_handler(dev->htable[0]); - return (DDI_FAILURE); - } - - return (DDI_SUCCESS); -} /* oce_add_intx_handlers */ - -static void -oce_del_intx_handlers(struct oce_dev *dev) -{ - (void) ddi_intr_remove_handler(dev->htable[0]); -} /* oce_del_intx_handlers */
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_main.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_main.c Thu Aug 05 11:14:15 2010 -0600 @@ -40,6 +40,7 @@ #define ATTACH_HW_INIT 0x10 #define ATTACH_SETUP_TXRX 0x20 #define ATTACH_SETUP_ADAP 0x40 +#define ATTACH_SETUP_INTR 0x80 #define ATTACH_STAT_INIT 0x100 #define ATTACH_MAC_REG 0x200 @@ -47,16 +48,21 @@ const char oce_ident_string[] = OCE_IDENT_STRING; const char oce_mod_name[] = OCE_MOD_NAME; -char oce_version[] = OCE_REVISION; - /* driver properties */ -static const char mtu_prop_name[] = "oce_default_mtu"; -static const char tx_ring_size_name[] = "oce_tx_ring_size"; -static const char tx_bcopy_limit_name[] = "oce_tx_bcopy_limit"; -static const char rx_bcopy_limit_name[] = "oce_rx_bcopy_limit"; -static const char fm_cap_name[] = "oce_fm_capability"; -static const char log_level_name[] = "oce_log_level"; -static const char lso_capable_name[] = "oce_lso_capable"; +static const char flow_control[] = "flow_control"; +static const char mtu_prop_name[] = "oce_default_mtu"; +static const char tx_ring_size_name[] = "tx_ring_size"; +static const char tx_bcopy_limit_name[] = "tx_bcopy_limit"; +static const char rx_bcopy_limit_name[] = "rx_bcopy_limit"; +static const char rx_frag_size_name[] = "rx_frag_size"; +static const char rx_max_bufs_name[] = "rx_max_bufs"; +static const char fm_cap_name[] = "oce_fm_capability"; +static const char log_level_name[] = "oce_log_level"; +static const char lso_capable_name[] = "lso_capable"; +static const char rx_pkt_per_intr_name[] = "rx_pkts_per_intr"; +static const char tx_reclaim_threshold_name[] = "tx_reclaim_threshold"; +static const char rx_rings_name[] = "max_rx_rings"; +static const char tx_rings_name[] = "max_tx_rings"; /* --[ static function prototypes here ]------------------------------- */ static int oce_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd); @@ -68,6 +74,8 @@ static void oce_init_locks(struct oce_dev *dev); static void oce_destroy_locks(struct oce_dev *dev); static void oce_get_params(struct oce_dev *dev); +static int oce_get_prop(struct oce_dev *dev, char *propname, int minval, + int maxval, int defval, uint32_t *values); static struct cb_ops oce_cb_ops = { nulldev, /* cb_open */ @@ -196,10 +204,7 @@ } /* allocate dev */ - dev = kmem_zalloc(sizeof (struct oce_dev), KM_NOSLEEP); - if (dev == NULL) { - return (DDI_FAILURE); - } + dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP); /* populate the dev structure */ dev->dip = dip; @@ -219,17 +224,6 @@ oce_fm_init(dev); dev->attach_state |= ATTACH_FM_INIT; - ret = oce_setup_intr(dev); - if (ret != DDI_SUCCESS) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "Interrupt setup failed with %d", ret); - goto attach_fail; - - } - - /* initialize locks */ - oce_init_locks(dev); - dev->attach_state |= ATTACH_LOCK_INIT; /* setup PCI bars */ ret = oce_pci_init(dev); @@ -240,6 +234,20 @@ } dev->attach_state |= ATTACH_PCI_INIT; + ret = oce_setup_intr(dev); + if (ret != DDI_SUCCESS) { + oce_log(dev, CE_WARN, MOD_CONFIG, + "Interrupt setup failed with %d", ret); + goto attach_fail; + + } + dev->attach_state |= ATTACH_SETUP_INTR; + + /* initialize locks */ + oce_init_locks(dev); + dev->attach_state |= ATTACH_LOCK_INIT; + + /* HW init */ ret = oce_hw_init(dev); if (ret != DDI_SUCCESS) { @@ -312,7 +320,8 @@ } /* correct link status only after start */ - mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN); + dev->link_status = LINK_STATE_UNKNOWN; + mac_link_update(dev->mac_handle, dev->link_status); dev->attach_state |= ATTACH_MAC_REG; dev->state |= STATE_INIT; @@ -332,6 +341,7 @@ { struct oce_dev *dev; int pcnt = 0; + int qid; dev = ddi_get_driver_private(dip); if (dev == NULL) { @@ -353,7 +363,6 @@ if (mac_unregister(dev->mac_handle) != 0) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "Failed to unregister MAC "); - return (DDI_FAILURE); } dev->attach_state &= ~ATTACH_MAC_REG; @@ -369,10 +378,13 @@ /* * Wait for Packets sent up to be freed */ - if ((pcnt = oce_rx_pending(dev)) != 0) { - oce_log(dev, CE_WARN, MOD_CONFIG, - "%d Pending Buffers Detach failed", pcnt); - return (DDI_FAILURE); + for (qid = 0; qid < dev->rx_rings; qid++) { + pcnt = oce_rx_pending(dev, dev->rq[qid], DEFAULT_DRAIN_TIME); + if (pcnt != 0) { + oce_log(dev, CE_WARN, MOD_CONFIG, + "%d Pending Buffers Detach failed", pcnt); + return (DDI_FAILURE); + } } oce_unconfigure(dev); @@ -430,7 +442,7 @@ mutex_exit(&dev->dev_lock); return (DDI_SUCCESS); } - if (dev->state & STATE_MAC_STARTED) { + if (!(dev->state & STATE_MAC_STARTED)) { ret = oce_setup_adapter(dev); if (ret != DDI_SUCCESS) { mutex_exit(&dev->dev_lock); @@ -487,12 +499,16 @@ if (state & ATTACH_HW_INIT) { oce_hw_fini(dev); } + if (state & ATTACH_LOCK_INIT) { + oce_destroy_locks(dev); + } + + if (state & ATTACH_SETUP_INTR) { + (void) oce_teardown_intr(dev); + } if (state & ATTACH_PCI_INIT) { oce_pci_fini(dev); } - if (state & ATTACH_LOCK_INIT) { - oce_destroy_locks(dev); - } if (state & ATTACH_FM_INIT) { oce_fm_fini(dev); } @@ -508,39 +524,77 @@ uint32_t log_level; uint16_t mod_mask; uint16_t severity; + /* + * Allowed values for the driver parameters. If all values in a range + * is allowed, the the array has only one value. + */ + uint32_t fc_values[] = {OCE_FC_NONE, OCE_FC_TX, OCE_FC_RX, + OCE_DEFAULT_FLOW_CONTROL, END}; + uint32_t mtu_values[] = {OCE_MIN_MTU, OCE_MAX_MTU, END}; + uint32_t tx_rs_values[] = {SIZE_256, SIZE_512, SIZE_1K, SIZE_2K, END}; + uint32_t tx_bcl_values[] = {SIZE_128, SIZE_256, SIZE_512, SIZE_1K, + SIZE_2K, END}; + uint32_t rx_bcl_values[] = {SIZE_128, SIZE_256, SIZE_512, SIZE_1K, + SIZE_2K, END}; + uint32_t rq_fs_values[] = {SIZE_2K, SIZE_4K, SIZE_8K, END}; + uint32_t rq_mb_values[] = {SIZE_2K, SIZE_4K, SIZE_8K, END}; + uint32_t lso_capable_values[] = {0, 1, END}; + uint32_t fm_caps_values[] = {DDI_FM_NOT_CAPABLE, OCE_FM_CAPABILITY, + END}; + uint32_t tx_rt_values[] = {END}; + uint32_t rx_ppi_values[] = {END}; + uint32_t rx_rings_values[] = {END}; + uint32_t tx_rings_values[] = {END}; + uint32_t log_level_values[] = {END}; /* non tunables */ dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE; - dev->flow_control = OCE_DEFAULT_FLOW_CONTROL; /* configurable parameters */ + dev->flow_control = oce_get_prop(dev, (char *)flow_control, OCE_FC_NONE, + OCE_DEFAULT_FLOW_CONTROL, OCE_DEFAULT_FLOW_CONTROL, fc_values); - /* restrict MTU to 1500 and 9000 only */ - dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU); - if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU) - dev->mtu = OCE_MIN_MTU; + dev->mtu = oce_get_prop(dev, (char *)mtu_prop_name, OCE_MIN_MTU, + OCE_MAX_MTU, OCE_MIN_MTU, mtu_values); + + dev->tx_ring_size = oce_get_prop(dev, (char *)tx_ring_size_name, + SIZE_256, SIZE_2K, OCE_DEFAULT_TX_RING_SIZE, tx_rs_values); + + dev->tx_bcopy_limit = oce_get_prop(dev, (char *)tx_bcopy_limit_name, + SIZE_128, SIZE_2K, OCE_DEFAULT_TX_BCOPY_LIMIT, tx_bcl_values); - dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)tx_ring_size_name, - OCE_DEFAULT_TX_RING_SIZE); + dev->rx_bcopy_limit = oce_get_prop(dev, (char *)rx_bcopy_limit_name, + SIZE_128, SIZE_2K, OCE_DEFAULT_RX_BCOPY_LIMIT, rx_bcl_values); + + dev->rq_frag_size = oce_get_prop(dev, (char *)rx_frag_size_name, + SIZE_2K, SIZE_8K, OCE_RQ_BUF_SIZE, rq_fs_values); + + dev->rq_max_bufs = oce_get_prop(dev, (char *)rx_max_bufs_name, SIZE_2K, + SIZE_8K, OCE_RQ_NUM_BUFFERS, rq_mb_values); - dev->tx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)tx_bcopy_limit_name, - OCE_DEFAULT_TX_BCOPY_LIMIT); - dev->rx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)rx_bcopy_limit_name, - OCE_DEFAULT_RX_BCOPY_LIMIT); + dev->lso_capable = oce_get_prop(dev, (char *)lso_capable_name, 0, + 1, 1, lso_capable_values); + + dev->fm_caps = oce_get_prop(dev, (char *)fm_cap_name, + DDI_FM_NOT_CAPABLE, OCE_FM_CAPABILITY, OCE_FM_CAPABILITY, + fm_caps_values); + + dev->tx_reclaim_threshold = oce_get_prop(dev, + (char *)tx_reclaim_threshold_name, 0, dev->tx_ring_size/2, + OCE_DEFAULT_TX_RECLAIM_THRESHOLD, tx_rt_values); - dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)lso_capable_name, 1); + dev->rx_pkt_per_intr = oce_get_prop(dev, (char *)rx_pkt_per_intr_name, + 0, dev->rx_ring_size/2, OCE_DEFAULT_RX_PKT_PER_INTR, rx_ppi_values); + + dev->rx_rings = oce_get_prop(dev, (char *)rx_rings_name, + OCE_DEFAULT_RQS, OCE_MAX_RQS, OCE_DEFAULT_RQS, rx_rings_values); - dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY); + dev->tx_rings = oce_get_prop(dev, (char *)tx_rings_name, + OCE_DEFAULT_WQS, OCE_DEFAULT_WQS, OCE_DEFAULT_WQS, tx_rings_values); - log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, - DDI_PROP_DONTPASS, (char *)log_level_name, - OCE_DEFAULT_LOG_SETTINGS); + log_level = oce_get_prop(dev, (char *)log_level_name, 0, + OCE_MAX_LOG_SETTINGS, OCE_DEFAULT_LOG_SETTINGS, log_level_values); + severity = (uint16_t)(log_level & 0xffff); mod_mask = (uint16_t)(log_level >> 16); if (mod_mask > MOD_ISR) { @@ -553,3 +607,33 @@ dev->mod_mask = mod_mask; dev->severity = severity; } /* oce_get_params */ + +static int +oce_get_prop(struct oce_dev *dev, char *propname, int minval, int maxval, + int defval, uint32_t *values) +{ + int value = 0; + int i = 0; + + value = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, + DDI_PROP_DONTPASS, propname, defval); + + if (value > maxval) + value = maxval; + + if (value < minval) + value = minval; + + while (values[i] != 0xdeadface) { + if (values[i] == value) { + break; + } + i++; + } + + if ((i != 0) && (values[i] == 0xdeadface)) { + value = defval; + } + + return (value); +}
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mbx.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mbx.c Thu Aug 05 11:14:15 2010 -0600 @@ -79,6 +79,7 @@ hdr->u0.req.timeout = timeout; hdr->u0.req.request_length = pyld_len - sizeof (struct mbx_hdr); + hdr->u0.req.rsvd0 = 0; } /* mbx_common_req_hdr_init */ /* @@ -615,7 +616,10 @@ } /* interpret response */ - bcopy(&fwcmd->params.rsp, link, 8); + bcopy(&fwcmd->params.rsp, link, sizeof (struct link_status)); + link->logical_link_status = LE_32(link->logical_link_status); + link->qos_link_speed = LE_16(link->qos_link_speed); + return (0); } /* oce_get_link_status */ @@ -750,6 +754,15 @@ dev->port_id = fwcmd->params.rsp.port_id; dev->function_mode = fwcmd->params.rsp.function_mode; + /* get the max rings alloted for this function */ + if (fwcmd->params.rsp.ulp[0].mode & ULP_NIC_MODE) { + dev->max_tx_rings = fwcmd->params.rsp.ulp[0].wq_count; + dev->max_rx_rings = fwcmd->params.rsp.ulp[0].rq_count; + } else { + dev->max_tx_rings = fwcmd->params.rsp.ulp[1].wq_count; + dev->max_rx_rings = fwcmd->params.rsp.ulp[1].rq_count; + } + dev->function_caps = fwcmd->params.rsp.function_caps; return (0); } /* oce_get_fw_config */ @@ -1162,6 +1175,50 @@ return (ret); } /* oce_config_link */ +int +oce_config_rss(struct oce_dev *dev, uint16_t if_id, char *hkey, char *itbl, + int tbl_sz, uint16_t rss_type, uint8_t flush) +{ + struct oce_mbx mbx; + struct mbx_config_nic_rss *fwcmd; + int i; + int ret = 0; + + bzero(&mbx, sizeof (struct oce_mbx)); + fwcmd = (struct mbx_config_nic_rss *)&mbx.payload; + + /* initialize the ioctl header */ + mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0, + MBX_SUBSYSTEM_NIC, + OPCODE_CONFIG_NIC_RSS, + MBX_TIMEOUT_SEC, + sizeof (struct mbx_config_nic_rss)); + fwcmd->params.req.enable_rss = LE_16(rss_type); + fwcmd->params.req.flush = flush; + fwcmd->params.req.if_id = LE_32(if_id); + + if (hkey != NULL) { + bcopy(hkey, fwcmd->params.req.hash, OCE_HKEY_SIZE); + } + + + /* Fill the indirection table */ + for (i = 0; i < tbl_sz; i++) { + fwcmd->params.req.cputable[i] = itbl[i]; + } + + fwcmd->params.req.cpu_tbl_sz_log2 = LE_16(OCE_LOG2(tbl_sz)); + + /* fill rest of mbx */ + mbx.u0.s.embedded = B_TRUE; + mbx.payload_length = sizeof (struct mbx_config_nic_rss); + DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ)); + + /* post the command */ + ret = oce_mbox_post(dev, &mbx, NULL); + + return (ret); +} /* * function called from the gld ioctl entry point to send a mbx to fw
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mq.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mq.c Thu Aug 05 11:14:15 2010 -0600 @@ -62,9 +62,18 @@ acqe = (struct oce_async_cqe_link_state *)cqe; if (acqe->u0.s.event_code == ASYNC_EVENT_CODE_LINK_STATE) { - link_status = (acqe->u0.s.link_status)? - LINK_STATE_UP : LINK_STATE_DOWN; + /* + * don't care logical or not, + * just check up down + */ + + link_status = ((acqe->u0.s.link_status & + ~ASYNC_EVENT_LOGICAL) == + ASYNC_EVENT_LINK_UP) ? + LINK_STATE_UP: LINK_STATE_DOWN; mac_link_update(dev->mac_handle, link_status); + dev->link_status = link_status; + dev->link_speed = -1; } } cqe->u0.dw[3] = 0;
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_queue.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_queue.c Thu Aug 05 11:14:15 2010 -0600 @@ -278,7 +278,7 @@ cq->cq_cfg.nodelay = (uint8_t)nodelay; /* interpret the response */ cq->cq_id = LE_16(fwcmd->params.rsp.cq_id); - dev->cq[cq->cq_id] = cq; + dev->cq[cq->cq_id % OCE_MAX_CQ] = cq; atomic_inc_32(&eq->ref_count); return (cq); } /* oce_cq_create */ @@ -311,7 +311,7 @@ /* Reset the handler */ cq->cq_handler = NULL; - dev->cq[cq->cq_id] = NULL; + dev->cq[cq->cq_id % OCE_MAX_CQ] = NULL; atomic_dec_32(&cq->eq->ref_count); mutex_destroy(&cq->lock); @@ -359,7 +359,7 @@ /* create the ring buffer for this queue */ mq->ring = create_ring_buffer(dev, q_len, - sizeof (struct oce_mbx), DDI_DMA_CONSISTENT); + sizeof (struct oce_mbx), DDI_DMA_CONSISTENT | DDI_DMA_RDWR); if (mq->ring == NULL) { oce_log(dev, CE_WARN, MOD_CONFIG, "MQ ring alloc failed:0x%p", @@ -462,6 +462,7 @@ struct oce_wq *wq; char str[MAX_POOL_NAME]; int ret; + static int wq_id = 0; ASSERT(dev != NULL); /* q_len must be min 256 and max 2k */ @@ -486,12 +487,13 @@ wq->cfg.eqd = OCE_DEFAULT_WQ_EQD; wq->cfg.nbufs = 2 * wq->cfg.q_len; wq->cfg.nhdl = 2 * wq->cfg.q_len; + wq->cfg.buf_size = dev->tx_bcopy_limit; /* assign parent */ wq->parent = (void *)dev; /* Create the WQ Buffer pool */ - ret = oce_wqb_cache_create(wq, dev->tx_bcopy_limit); + ret = oce_wqb_cache_create(wq, wq->cfg.buf_size); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "WQ Buffer Pool create failed "); @@ -506,10 +508,10 @@ goto wqm_fail; } - (void) snprintf(str, MAX_POOL_NAME, "%s%d", "oce_wqed_", dev->dev_id); + (void) snprintf(str, MAX_POOL_NAME, "%s%d%s%d", "oce_wqed_", + dev->dev_id, "_", wq_id++); wq->wqed_cache = kmem_cache_create(str, sizeof (oce_wqe_desc_t), - 0, oce_wqe_desc_ctor, - oce_wqe_desc_dtor, NULL, NULL, NULL, 0); + 0, NULL, NULL, NULL, NULL, NULL, 0); if (wq->wqed_cache == NULL) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "WQ Packet Desc Pool create failed "); @@ -518,7 +520,7 @@ /* create the ring buffer */ wq->ring = create_ring_buffer(dev, q_len, - NIC_WQE_SIZE, DDI_DMA_CONSISTENT); + NIC_WQE_SIZE, DDI_DMA_CONSISTENT | DDI_DMA_RDWR); if (wq->ring == NULL) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "Failed to create WQ ring "); @@ -690,7 +692,6 @@ * * return pointer to the RQ created. NULL on failure */ -/* ARGSUSED */ static struct oce_rq * oce_rq_init(struct oce_dev *dev, uint32_t q_len, uint32_t frag_size, uint32_t mtu, @@ -718,13 +719,37 @@ rq->cfg.frag_size = frag_size; rq->cfg.mtu = mtu; rq->cfg.eqd = 0; - rq->cfg.nbufs = 8 * 1024; + rq->cfg.nbufs = dev->rq_max_bufs; + rq->cfg.is_rss_queue = rss; /* assign parent */ rq->parent = (void *)dev; - /* create the cache */ - ret = oce_rqb_cache_create(rq, OCE_RQ_BUF_SIZE + + rq->rq_bdesc_array = + kmem_zalloc((sizeof (oce_rq_bdesc_t) * rq->cfg.nbufs), KM_NOSLEEP); + if (rq->rq_bdesc_array == NULL) { + oce_log(dev, CE_WARN, MOD_CONFIG, "%s", + "RQ bdesc alloc failed"); + goto rqbd_alloc_fail; + } + /* create the rq buffer descriptor ring */ + rq->shadow_ring = + kmem_zalloc((rq->cfg.q_len * sizeof (oce_rq_bdesc_t *)), + KM_NOSLEEP); + if (rq->shadow_ring == NULL) { + oce_log(dev, CE_WARN, MOD_CONFIG, "%s", + "RQ shadow ring alloc failed "); + goto rq_shdw_fail; + } + + /* allocate the free list array */ + rq->rqb_freelist = + kmem_zalloc(rq->cfg.nbufs * sizeof (oce_rq_bdesc_t *), KM_NOSLEEP); + if (rq->rqb_freelist == NULL) { + goto rqb_free_list_fail; + } + /* create the buffer pool */ + ret = oce_rqb_cache_create(rq, dev->rq_frag_size + OCE_RQE_BUF_HEADROOM); if (ret != DDI_SUCCESS) { goto rqb_fail; @@ -732,17 +757,13 @@ /* create the ring buffer */ rq->ring = create_ring_buffer(dev, q_len, - sizeof (struct oce_nic_rqe), DDI_DMA_CONSISTENT); + sizeof (struct oce_nic_rqe), DDI_DMA_CONSISTENT | DDI_DMA_RDWR); if (rq->ring == NULL) { oce_log(dev, CE_WARN, MOD_CONFIG, "%s", "RQ ring create failed "); goto rq_ringfail; } - /* allocate mbx */ - rq->shadow_ring = kmem_zalloc(sizeof (struct rq_shadow_entry) * - q_len, KM_SLEEP); - /* Initialize the RQ lock */ mutex_init(&rq->rx_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(dev->intr_pri)); @@ -752,13 +773,18 @@ atomic_inc_32(&dev->nrqs); return (rq); -rqcq_fail: - kmem_free(rq->shadow_ring, - sizeof (struct rq_shadow_entry) * q_len); - destroy_ring_buffer(dev, rq->ring); rq_ringfail: oce_rqb_cache_destroy(rq); rqb_fail: + kmem_free(rq->shadow_ring, + (rq->cfg.q_len * sizeof (oce_rq_bdesc_t *))); +rqb_free_list_fail: + kmem_free(rq->rqb_freelist, + (rq->cfg.nbufs * sizeof (oce_rq_bdesc_t *))); +rq_shdw_fail: + kmem_free(rq->rq_bdesc_array, + (sizeof (oce_rq_bdesc_t) * rq->cfg.q_len)); +rqbd_alloc_fail: kmem_free(rq, sizeof (struct oce_rq)); return (NULL); } /* oce_rq_create */ @@ -779,8 +805,14 @@ destroy_ring_buffer(dev, rq->ring); rq->ring = NULL; kmem_free(rq->shadow_ring, - sizeof (struct rq_shadow_entry) * rq->cfg.q_len); + sizeof (oce_rq_bdesc_t *) * rq->cfg.q_len); rq->shadow_ring = NULL; + kmem_free(rq->rq_bdesc_array, + (sizeof (oce_rq_bdesc_t) * rq->cfg.nbufs)); + rq->rq_bdesc_array = NULL; + kmem_free(rq->rqb_freelist, + (rq->cfg.nbufs * sizeof (oce_rq_bdesc_t *))); + rq->rqb_freelist = NULL; mutex_destroy(&rq->rx_lock); mutex_destroy(&rq->rc_lock); kmem_free(rq, sizeof (struct oce_rq)); @@ -838,7 +870,7 @@ /* interpret the response */ rq->rq_id = LE_16(fwcmd->params.rsp.u0.s.rq_id); - /* rq->rss_cpuid = fwcmd->params.rsp.u0.bits.rss_cpuid; */ + rq->rss_cpuid = fwcmd->params.rsp.u0.s.rss_cpuid; rq->cfg.if_id = if_id; rq->qstate = QCREATED; rq->cq = cq; @@ -885,7 +917,7 @@ oce_cq_del(dev, rq->cq); rq->cq = NULL; /* free up the posted buffers */ - oce_rq_discharge(dev->rq[0]); + oce_rq_discharge(rq); } } /* oce_rq_del */ @@ -913,9 +945,6 @@ eq_db.bits.clrint = clearint; eq_db.bits.qid = qid; OCE_DB_WRITE32(dev, PD_EQ_DB, eq_db.dw0); - if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) { - ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); - } } /* @@ -938,9 +967,6 @@ cq_db.bits.event = 0; cq_db.bits.qid = qid; OCE_DB_WRITE32(dev, PD_CQ_DB, cq_db.dw0); - if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) { - ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); - } } @@ -1106,17 +1132,36 @@ int oce_init_txrx(struct oce_dev *dev) { - dev->wq[0] = oce_wq_init(dev, dev->tx_ring_size, NIC_WQ_TYPE_STANDARD); + int qid = 0; + + /* enable RSS if rx queues > 1 */ + dev->rss_enable = (dev->rx_rings > 1) ? B_TRUE : B_FALSE; - if (dev->wq[0] == NULL) { + for (qid = 0; qid < dev->tx_rings; qid++) { + dev->wq[qid] = oce_wq_init(dev, dev->tx_ring_size, + NIC_WQ_TYPE_STANDARD); + if (dev->wq[qid] == NULL) { + goto queue_fail; + } + } + + /* Now create the Rx Queues */ + /* qid 0 is always default non rss queue for rss */ + dev->rq[0] = oce_rq_init(dev, dev->rx_ring_size, dev->rq_frag_size, + OCE_MAX_JUMBO_FRAME_SIZE, B_FALSE); + if (dev->rq[0] == NULL) { goto queue_fail; } - dev->rq[0] = oce_rq_init(dev, dev->rx_ring_size, OCE_RQ_BUF_SIZE, - OCE_RQ_MAX_FRAME_SZ, B_FALSE); - if (dev->rq[0] == NULL) { - goto queue_fail; + for (qid = 1; qid < dev->rx_rings; qid++) { + dev->rq[qid] = oce_rq_init(dev, dev->rx_ring_size, + dev->rq_frag_size, OCE_MAX_JUMBO_FRAME_SIZE, + dev->rss_enable); + if (dev->rq[qid] == NULL) { + goto queue_fail; + } } + return (DDI_SUCCESS); queue_fail: oce_fini_txrx(dev); @@ -1125,16 +1170,26 @@ void oce_fini_txrx(struct oce_dev *dev) { - if (dev->wq[0] != NULL) { - oce_wq_fini(dev, dev->wq[0]); - dev->wq[0] = NULL; + int qid; + int nqs; + + /* free all the tx rings */ + /* nwqs is decremented in fini so copy count first */ + nqs = dev->nwqs; + for (qid = 0; qid < nqs; qid++) { + if (dev->wq[qid] != NULL) { + oce_wq_fini(dev, dev->wq[qid]); + dev->wq[qid] = NULL; + } } - if (dev->rq[0] != NULL) { - oce_rq_fini(dev, dev->rq[0]); - dev->rq[0] = NULL; + /* free all the rx rings */ + nqs = dev->nrqs; + for (qid = 0; qid < nqs; qid++) { + if (dev->rq[qid] != NULL) { + oce_rq_fini(dev, dev->rq[qid]); + dev->rq[qid] = NULL; + } } - return; - } int @@ -1152,11 +1207,16 @@ } dev->eq[i] = eq; } - if (oce_wq_create(dev->wq[0], dev->eq[0]) != 0) - goto rings_fail; - if (oce_rq_create(dev->rq[0], dev->if_id, - dev->neqs > 1 ? dev->eq[1] : dev->eq[0]) != 0) - goto rings_fail; + for (i = 0; i < dev->nwqs; i++) { + if (oce_wq_create(dev->wq[i], dev->eq[0]) != 0) + goto rings_fail; + } + + for (i = 0; i < dev->nrqs; i++) { + if (oce_rq_create(dev->rq[i], dev->if_id, + dev->neqs > 1 ? dev->eq[1 + i] : dev->eq[0]) != 0) + goto rings_fail; + } mq = oce_mq_create(dev, dev->eq[0], 64); if (mq == NULL) goto rings_fail; @@ -1172,6 +1232,7 @@ oce_delete_queues(struct oce_dev *dev) { int i; + int neqs = dev->neqs; if (dev->mq != NULL) { oce_mq_del(dev, dev->mq); dev->mq = NULL; @@ -1183,8 +1244,8 @@ for (i = 0; i < dev->nwqs; i++) { oce_wq_del(dev, dev->wq[i]); } - /* create as many eqs as the number of vectors */ - for (i = 0; i < dev->num_vectors; i++) { + /* delete as many eqs as the number of vectors */ + for (i = 0; i < neqs; i++) { oce_eq_del(dev, dev->eq[i]); dev->eq[i] = NULL; }
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_rx.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_rx.c Thu Aug 05 11:14:15 2010 -0600 @@ -31,23 +31,48 @@ #include <oce_impl.h> -static void rx_pool_free(char *arg); +void oce_rx_pool_free(char *arg); +static void oce_rqb_dtor(oce_rq_bdesc_t *rqbd); +static int oce_rqb_ctor(oce_rq_bdesc_t *rqbd, struct oce_rq *rq, + size_t size, int flags); + static inline mblk_t *oce_rx(struct oce_dev *dev, struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); static inline mblk_t *oce_rx_bcopy(struct oce_dev *dev, struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); -static int oce_rq_charge(struct oce_dev *dev, struct oce_rq *rq, - uint32_t nbufs); -static oce_rq_bdesc_t *oce_rqb_alloc(struct oce_rq *rq); -static void oce_rqb_free(struct oce_rq *rq, oce_rq_bdesc_t *rqbd); -static void oce_rqb_dtor(oce_rq_bdesc_t *rqbd); -static int oce_rqb_ctor(oce_rq_bdesc_t *rqbd, struct oce_rq *rq, - size_t size, int flags); +static int oce_rq_charge(struct oce_rq *rq, uint32_t nbufs, boolean_t repost); static void oce_rx_insert_tag(mblk_t *mp, uint16_t vtag); static void oce_set_rx_oflags(mblk_t *mp, struct oce_nic_rx_cqe *cqe); static inline void oce_rx_drop_pkt(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); +static oce_rq_bdesc_t *oce_rqb_alloc(struct oce_rq *rq); +static void oce_rqb_free(struct oce_rq *rq, oce_rq_bdesc_t *rqbd); +static void oce_rq_post_buffer(struct oce_rq *rq, int nbufs); +#pragma inline(oce_rx) +#pragma inline(oce_rx_bcopy) +#pragma inline(oce_rq_charge) +#pragma inline(oce_rx_insert_tag) +#pragma inline(oce_set_rx_oflags) +#pragma inline(oce_rx_drop_pkt) +#pragma inline(oce_rqb_alloc) +#pragma inline(oce_rqb_free) +#pragma inline(oce_rq_post_buffer) + +static ddi_dma_attr_t oce_rx_buf_attr = { + DMA_ATTR_V0, /* version number */ + 0x0000000000000000ull, /* low address */ + 0xFFFFFFFFFFFFFFFFull, /* high address */ + 0x00000000FFFFFFFFull, /* dma counter max */ + OCE_DMA_ALIGNMENT, /* alignment */ + 0x000007FF, /* burst sizes */ + 0x00000001, /* minimum transfer size */ + 0x00000000FFFFFFFFull, /* maximum transfer size */ + 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */ + 1, /* scatter/gather list length */ + 0x00000001, /* granularity */ + DDI_DMA_FLAGERR|DDI_DMA_RELAXED_ORDERING /* DMA flags */ +}; /* * function to create a DMA buffer pool for RQ @@ -61,31 +86,25 @@ int oce_rqb_cache_create(struct oce_rq *rq, size_t buf_size) { - struct oce_dev *dev = rq->parent; int size; int cnt; int ret; - int nitems; + oce_rq_bdesc_t *rqbd; - nitems = rq->cfg.nbufs; - size = nitems * sizeof (oce_rq_bdesc_t); - rq->rq_bdesc_array = kmem_zalloc(size, KM_NOSLEEP); - if (rq->rq_bdesc_array == NULL) { - return (DDI_FAILURE); - } - - /* Create the free buffer list */ - OCE_LIST_CREATE(&rq->rq_buf_list, DDI_INTR_PRI(dev->intr_pri)); - - for (cnt = 0; cnt < nitems; cnt++) { - ret = oce_rqb_ctor(&rq->rq_bdesc_array[cnt], - rq, buf_size, DDI_DMA_STREAMING); + _NOTE(ARGUNUSED(buf_size)); + rqbd = rq->rq_bdesc_array; + size = rq->cfg.frag_size + OCE_RQE_BUF_HEADROOM; + for (cnt = 0; cnt < rq->cfg.nbufs; cnt++, rqbd++) { + rq->rqb_freelist[cnt] = rqbd; + ret = oce_rqb_ctor(rqbd, rq, + size, (DDI_DMA_RDWR|DDI_DMA_STREAMING)); if (ret != DDI_SUCCESS) { goto rqb_fail; } - OCE_LIST_INSERT_TAIL(&rq->rq_buf_list, - &(rq->rq_bdesc_array[cnt].link)); } + rq->rqb_free = rq->cfg.nbufs; + rq->rqb_rc_head = 0; + rq->rqb_next_free = 0; return (DDI_SUCCESS); rqb_fail: @@ -104,14 +123,12 @@ oce_rqb_cache_destroy(struct oce_rq *rq) { oce_rq_bdesc_t *rqbd = NULL; + int cnt; - while ((rqbd = (oce_rq_bdesc_t *)OCE_LIST_REM_HEAD(&rq->rq_buf_list)) - != NULL) { + rqbd = rq->rq_bdesc_array; + for (cnt = 0; cnt < rq->cfg.nbufs; cnt++, rqbd++) { oce_rqb_dtor(rqbd); } - kmem_free(rq->rq_bdesc_array, - rq->cfg.nbufs * sizeof (oce_rq_bdesc_t)); - OCE_LIST_DESTROY(&rq->rq_buf_list); } /* oce_rqb_cache_destroy */ /* @@ -127,12 +144,12 @@ if ((rqbd == NULL) || (rqbd->rq == NULL)) { return; } + if (rqbd->mp != NULL) { + rqbd->fr_rtn.free_arg = NULL; + freemsg(rqbd->mp); + rqbd->mp = NULL; + } oce_free_dma_buffer(rqbd->rq->parent, rqbd->rqb); - if (rqbd->mp != NULL) { - /* Buffer is already free */ - rqbd->fr_rtn.free_arg = NULL; - freeb(rqbd->mp); - } } /* oce_rqb_dtor */ /* @@ -153,20 +170,24 @@ dev = rq->parent; - dbuf = oce_alloc_dma_buffer(dev, size, flags); + dbuf = oce_alloc_dma_buffer(dev, size, &oce_rx_buf_attr, flags); if (dbuf == NULL) { return (DDI_FAILURE); } - /* override usable length */ + /* Set the call back function parameters */ + rqbd->fr_rtn.free_func = (void (*)())oce_rx_pool_free; + rqbd->fr_rtn.free_arg = (caddr_t)(void *)rqbd; + rqbd->mp = desballoc((uchar_t *)(dbuf->base), + dbuf->size, 0, &rqbd->fr_rtn); + if (rqbd->mp == NULL) { + oce_free_dma_buffer(dev, dbuf); + return (DDI_FAILURE); + } rqbd->rqb = dbuf; rqbd->rq = rq; rqbd->frag_addr.dw.addr_lo = ADDR_LO(dbuf->addr + OCE_RQE_BUF_HEADROOM); rqbd->frag_addr.dw.addr_hi = ADDR_HI(dbuf->addr + OCE_RQE_BUF_HEADROOM); - rqbd->fr_rtn.free_func = (void (*)())rx_pool_free; - rqbd->fr_rtn.free_arg = (caddr_t)(void *)rqbd; - rqbd->mp = desballoc((uchar_t *)(rqbd->rqb->base), - rqbd->rqb->size, 0, &rqbd->fr_rtn); rqbd->mp->b_rptr = (uchar_t *)rqbd->rqb->base + OCE_RQE_BUF_HEADROOM; return (DDI_SUCCESS); @@ -183,7 +204,11 @@ oce_rqb_alloc(struct oce_rq *rq) { oce_rq_bdesc_t *rqbd; - rqbd = OCE_LIST_REM_HEAD(&rq->rq_buf_list); + uint32_t free_index; + free_index = rq->rqb_next_free; + rqbd = rq->rqb_freelist[free_index]; + rq->rqb_freelist[free_index] = NULL; + rq->rqb_next_free = GET_Q_NEXT(free_index, 1, rq->cfg.nbufs); return (rqbd); } /* oce_rqb_alloc */ @@ -198,10 +223,40 @@ static inline void oce_rqb_free(struct oce_rq *rq, oce_rq_bdesc_t *rqbd) { - OCE_LIST_INSERT_TAIL(&rq->rq_buf_list, rqbd); + uint32_t free_index; + mutex_enter(&rq->rc_lock); + free_index = rq->rqb_rc_head; + rq->rqb_freelist[free_index] = rqbd; + rq->rqb_rc_head = GET_Q_NEXT(free_index, 1, rq->cfg.nbufs); + mutex_exit(&rq->rc_lock); + atomic_add_32(&rq->rqb_free, 1); } /* oce_rqb_free */ + + +static void oce_rq_post_buffer(struct oce_rq *rq, int nbufs) +{ + pd_rxulp_db_t rxdb_reg; + int count; + struct oce_dev *dev = rq->parent; + + + rxdb_reg.dw0 = 0; + rxdb_reg.bits.qid = rq->rq_id & DB_RQ_ID_MASK; + + for (count = nbufs/OCE_MAX_RQ_POSTS; count > 0; count--) { + rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS; + OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0); + rq->buf_avail += OCE_MAX_RQ_POSTS; + nbufs -= OCE_MAX_RQ_POSTS; + } + if (nbufs > 0) { + rxdb_reg.bits.num_posted = nbufs; + OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0); + rq->buf_avail += nbufs; + } +} /* * function to charge a given rq with buffers from a pool's free list * @@ -212,89 +267,38 @@ * return number of rqe's charges. */ static inline int -oce_rq_charge(struct oce_dev *dev, - struct oce_rq *rq, uint32_t nbufs) +oce_rq_charge(struct oce_rq *rq, uint32_t nbufs, boolean_t repost) { struct oce_nic_rqe *rqe; oce_rq_bdesc_t *rqbd; - struct rq_shadow_entry *shadow_rq; - int32_t num_bufs = 0; - int32_t total_bufs = 0; - pd_rxulp_db_t rxdb_reg; - uint32_t cnt; + oce_rq_bdesc_t **shadow_rq; + int cnt; + int cur_index; + oce_ring_buffer_t *ring; shadow_rq = rq->shadow_ring; - /* check number of slots free and recharge */ - nbufs = ((rq->buf_avail + nbufs) > rq->cfg.q_len) ? - (rq->cfg.q_len - rq->buf_avail) : nbufs; + ring = rq->ring; + cur_index = ring->cidx; + for (cnt = 0; cnt < nbufs; cnt++) { - rqbd = oce_rqb_alloc(rq); - if (rqbd == NULL) { - oce_log(dev, CE_NOTE, MOD_RX, "%s %x", - "rqb pool empty @ ticks", - (uint32_t)ddi_get_lbolt()); - break; + if (!repost) { + rqbd = oce_rqb_alloc(rq); + } else { + /* just repost the buffers from shadow ring */ + rqbd = shadow_rq[cur_index]; + cur_index = GET_Q_NEXT(cur_index, 1, ring->num_items); } - if (rqbd->mp == NULL) { - rqbd->mp = desballoc((uchar_t *)(rqbd->rqb->base), - rqbd->rqb->size, 0, &rqbd->fr_rtn); - if (rqbd->mp != NULL) { - rqbd->mp->b_rptr = - (uchar_t *)rqbd->rqb->base + - OCE_RQE_BUF_HEADROOM; - } - - /* - * Failed again put back the buffer and continue - * loops for nbufs so its a finite loop - */ - - if (rqbd->mp == NULL) { - oce_rqb_free(rq, rqbd); - continue; - } - } - /* fill the rqes */ rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); rqe->u0.s.frag_pa_lo = rqbd->frag_addr.dw.addr_lo; rqe->u0.s.frag_pa_hi = rqbd->frag_addr.dw.addr_hi; - shadow_rq[rq->ring->pidx].rqbd = rqbd; + shadow_rq[rq->ring->pidx] = rqbd; DW_SWAP(u32ptr(rqe), sizeof (struct oce_nic_rqe)); RING_PUT(rq->ring, 1); - - /* if we have reached the max allowed posts, post */ - if (cnt && !(cnt % OCE_MAX_RQ_POSTS)) { - rxdb_reg.dw0 = 0; - rxdb_reg.bits.num_posted = num_bufs; - rxdb_reg.bits.qid = rq->rq_id & DB_RQ_ID_MASK; - OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0); - if (oce_fm_check_acc_handle(dev, dev->db_handle) != - DDI_FM_OK) { - ddi_fm_service_impact(dev->dip, - DDI_SERVICE_DEGRADED); - } - num_bufs = 0; - } - num_bufs++; - total_bufs++; } - /* post pending bufs */ - if (num_bufs) { - rxdb_reg.dw0 = 0; - rxdb_reg.bits.num_posted = num_bufs; - rxdb_reg.bits.qid = rq->rq_id & DB_RQ_ID_MASK; - OCE_DB_WRITE32(dev, PD_RXULP_DB, rxdb_reg.dw0); - if (oce_fm_check_acc_handle(dev, dev->db_handle) != - DDI_FM_OK) { - ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); - } - } - atomic_add_32(&rq->buf_avail, total_bufs); - - return (total_bufs); + return (cnt); } /* oce_rq_charge */ /* @@ -308,12 +312,12 @@ oce_rq_discharge(struct oce_rq *rq) { oce_rq_bdesc_t *rqbd; - struct rq_shadow_entry *shadow_rq; + oce_rq_bdesc_t **shadow_rq; shadow_rq = rq->shadow_ring; /* Free the posted buffer since RQ is destroyed already */ while ((int32_t)rq->buf_avail > 0) { - rqbd = shadow_rq[rq->ring->cidx].rqbd; + rqbd = shadow_rq[rq->ring->cidx]; oce_rqb_free(rq, rqbd); RING_GET(rq->ring, 1); rq->buf_avail--; @@ -334,48 +338,60 @@ mblk_t *mp; int pkt_len; int32_t frag_cnt = 0; - mblk_t *mblk_prev = NULL; - mblk_t *mblk_head = NULL; + mblk_t **mblk_tail; + mblk_t *mblk_head; int frag_size; - struct rq_shadow_entry *shadow_rq; - struct rq_shadow_entry *shadow_rqe; oce_rq_bdesc_t *rqbd; + uint16_t cur_index; + oce_ring_buffer_t *ring; + int i; + + frag_cnt = cqe->u0.s.num_fragments & 0x7; + mblk_head = NULL; + mblk_tail = &mblk_head; + + ring = rq->ring; + cur_index = ring->cidx; /* Get the relevant Queue pointers */ - shadow_rq = rq->shadow_ring; pkt_len = cqe->u0.s.pkt_size; - for (; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) { - shadow_rqe = &shadow_rq[rq->ring->cidx]; - rqbd = shadow_rqe->rqbd; + for (i = 0; i < frag_cnt; i++) { + rqbd = rq->shadow_ring[cur_index]; + if (rqbd->mp == NULL) { + rqbd->mp = desballoc((uchar_t *)rqbd->rqb->base, + rqbd->rqb->size, 0, &rqbd->fr_rtn); + if (rqbd->mp == NULL) { + return (NULL); + } + + rqbd->mp->b_rptr = + (uchar_t *)rqbd->rqb->base + OCE_RQE_BUF_HEADROOM; + } + mp = rqbd->mp; - if (mp == NULL) - return (NULL); frag_size = (pkt_len > rq->cfg.frag_size) ? rq->cfg.frag_size : pkt_len; mp->b_wptr = mp->b_rptr + frag_size; pkt_len -= frag_size; + mp->b_next = mp->b_cont = NULL; /* Chain the message mblks */ - if (mblk_head == NULL) { - mblk_head = mblk_prev = mp; - } else { - mblk_prev->b_cont = mp; - mblk_prev = mp; - } - (void) ddi_dma_sync(rqbd->rqb->dma_handle, 0, frag_size, - DDI_DMA_SYNC_FORKERNEL); - RING_GET(rq->ring, 1); + *mblk_tail = mp; + mblk_tail = &mp->b_cont; + (void) DBUF_SYNC(rqbd->rqb, DDI_DMA_SYNC_FORCPU); + cur_index = GET_Q_NEXT(cur_index, 1, ring->num_items); } if (mblk_head == NULL) { oce_log(dev, CE_WARN, MOD_RX, "%s", "oce_rx:no frags?"); return (NULL); } - atomic_add_32(&rq->pending, (cqe->u0.s.num_fragments & 0x7)); - mblk_head->b_next = NULL; + + /* replace the buffer with new ones */ + (void) oce_rq_charge(rq, frag_cnt, B_FALSE); + atomic_add_32(&rq->pending, frag_cnt); return (mblk_head); } /* oce_rx */ -/* ARGSUSED */ static inline mblk_t * oce_rx_bcopy(struct oce_dev *dev, struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) { @@ -384,45 +400,42 @@ int alloc_len; int32_t frag_cnt = 0; int frag_size; - struct rq_shadow_entry *shadow_rq; - struct rq_shadow_entry *shadow_rqe; oce_rq_bdesc_t *rqbd; - boolean_t tag_present = B_FALSE; unsigned char *rptr; + uint32_t cur_index; + oce_ring_buffer_t *ring; + oce_rq_bdesc_t **shadow_rq; + int cnt = 0; + + _NOTE(ARGUNUSED(dev)); shadow_rq = rq->shadow_ring; pkt_len = cqe->u0.s.pkt_size; - alloc_len = pkt_len; + alloc_len = pkt_len + OCE_RQE_BUF_HEADROOM; + frag_cnt = cqe->u0.s.num_fragments & 0x7; - /* Hardware always Strips Vlan tag so insert it back */ - if (cqe->u0.s.vlan_tag_present) { - alloc_len += VLAN_TAGSZ; - tag_present = B_TRUE; - } mp = allocb(alloc_len, BPRI_HI); - if (mp == NULL) + if (mp == NULL) { return (NULL); - if (tag_present) { - /* offset the read pointer by 4 bytes to insert tag */ - mp->b_rptr += VLAN_TAGSZ; } + + mp->b_rptr += OCE_RQE_BUF_HEADROOM; rptr = mp->b_rptr; - mp->b_wptr = mp->b_wptr + alloc_len; + mp->b_wptr = mp->b_rptr + pkt_len; + ring = rq->ring; - for (frag_cnt = 0; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) { - shadow_rqe = &shadow_rq[rq->ring->cidx]; - rqbd = shadow_rqe->rqbd; + cur_index = ring->cidx; + for (cnt = 0; cnt < frag_cnt; cnt++) { + rqbd = shadow_rq[cur_index]; frag_size = (pkt_len > rq->cfg.frag_size) ? rq->cfg.frag_size : pkt_len; - (void) ddi_dma_sync(rqbd->rqb->dma_handle, 0, frag_size, - DDI_DMA_SYNC_FORKERNEL); - bcopy(rqbd->rqb->base + OCE_RQE_BUF_HEADROOM, - rptr, frag_size); + (void) DBUF_SYNC(rqbd->rqb, DDI_DMA_SYNC_FORCPU); + bcopy(rqbd->rqb->base + OCE_RQE_BUF_HEADROOM, rptr, frag_size); rptr += frag_size; pkt_len -= frag_size; - oce_rqb_free(rq, rqbd); - RING_GET(rq->ring, 1); + cur_index = GET_Q_NEXT(cur_index, 1, ring->num_items); } + (void) oce_rq_charge(rq, frag_cnt, B_TRUE); return (mp); } @@ -458,6 +471,19 @@ ehp->ether_tci = LE_16(vtag); } +static inline void +oce_rx_drop_pkt(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) +{ + int frag_cnt; + oce_rq_bdesc_t *rqbd; + oce_rq_bdesc_t **shadow_rq; + shadow_rq = rq->shadow_ring; + for (frag_cnt = 0; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) { + rqbd = shadow_rq[rq->ring->cidx]; + oce_rqb_free(rq, rqbd); + RING_GET(rq->ring, 1); + } +} /* @@ -473,56 +499,65 @@ struct oce_nic_rx_cqe *cqe; struct oce_rq *rq; mblk_t *mp = NULL; - mblk_t *mblk_head = NULL; - mblk_t *mblk_prev = NULL; + mblk_t *mblk_head; + mblk_t **mblk_tail; uint16_t num_cqe = 0; struct oce_cq *cq; struct oce_dev *dev; - - if (arg == NULL) - return (0); + int32_t frag_cnt; + uint32_t nbufs = 0; rq = (struct oce_rq *)arg; dev = rq->parent; cq = rq->cq; - mutex_enter(&rq->rx_lock); + mblk_head = NULL; + mblk_tail = &mblk_head; + cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); + (void) DBUF_SYNC(cq->ring->dbuf, DDI_DMA_SYNC_FORKERNEL); /* dequeue till you reach an invalid cqe */ - while (RQ_CQE_VALID(cqe) && (num_cqe < rq->cfg.q_len)) { + while (RQ_CQE_VALID(cqe)) { DW_SWAP(u32ptr(cqe), sizeof (struct oce_nic_rx_cqe)); + frag_cnt = cqe->u0.s.num_fragments & 0x7; /* if insufficient buffers to charge then do copy */ - if (cqe->u0.s.pkt_size < dev->rx_bcopy_limit || - OCE_LIST_SIZE(&rq->rq_buf_list) < cqe->u0.s.num_fragments) { + if ((cqe->u0.s.pkt_size < dev->rx_bcopy_limit) || + (oce_atomic_reserve(&rq->rqb_free, frag_cnt) < 0)) { mp = oce_rx_bcopy(dev, rq, cqe); } else { mp = oce_rx(dev, rq, cqe); + if (mp == NULL) { + atomic_add_32(&rq->rqb_free, frag_cnt); + mp = oce_rx_bcopy(dev, rq, cqe); + } } if (mp != NULL) { if (cqe->u0.s.vlan_tag_present) { oce_rx_insert_tag(mp, cqe->u0.s.vlan_tag); } oce_set_rx_oflags(mp, cqe); - if (mblk_head == NULL) { - mblk_head = mblk_prev = mp; - } else { - mblk_prev->b_next = mp; - mblk_prev = mp; - } + *mblk_tail = mp; + mblk_tail = &mp->b_next; } else { - oce_rx_drop_pkt(rq, cqe); + (void) oce_rq_charge(rq, frag_cnt, B_TRUE); } - atomic_add_32(&rq->buf_avail, -(cqe->u0.s.num_fragments & 0x7)); - (void) oce_rq_charge(dev, rq, - (cqe->u0.s.num_fragments & 0x7)); + RING_GET(rq->ring, frag_cnt); + rq->buf_avail -= frag_cnt; + nbufs += frag_cnt; + + oce_rq_post_buffer(rq, frag_cnt); RQ_CQE_INVALIDATE(cqe); RING_GET(cq->ring, 1); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); num_cqe++; + /* process max ring size */ + if (num_cqe > dev->rx_pkt_per_intr) { + break; + } } /* for all valid CQEs */ - mutex_exit(&rq->rx_lock); + if (mblk_head) { mac_rx(dev->mac_handle, NULL, mblk_head); } @@ -537,8 +572,8 @@ * * return none */ -static void -rx_pool_free(char *arg) +void +oce_rx_pool_free(char *arg) { oce_rq_bdesc_t *rqbd; struct oce_rq *rq; @@ -551,13 +586,14 @@ /* retrieve the pointers from arg */ rqbd = (oce_rq_bdesc_t *)(void *)arg; rq = rqbd->rq; - - rqbd->mp = desballoc((uchar_t *)(rqbd->rqb->base), + rqbd->mp = desballoc((uchar_t *)rqbd->rqb->base, rqbd->rqb->size, 0, &rqbd->fr_rtn); - if (rqbd->mp != NULL) { - rqbd->mp->b_rptr = (uchar_t *)rqbd->rqb->base + - OCE_RQE_BUF_HEADROOM; + + if (rqbd->mp) { + rqbd->mp->b_rptr = + (uchar_t *)rqbd->rqb->base + OCE_RQE_BUF_HEADROOM; } + oce_rqb_free(rq, rqbd); (void) atomic_add_32(&rq->pending, -1); } /* rx_pool_free */ @@ -598,14 +634,6 @@ } OCE_MSDELAY(1); } -#if 0 - if (num_cqe) { - oce_arm_cq(dev, cq->cq_id, num_cqe, B_FALSE); - } - /* Drain the Event queue now */ - oce_drain_eq(rq->cq->eq); - return (num_cqe); -#endif } /* oce_clean_rq */ /* @@ -619,41 +647,33 @@ oce_start_rq(struct oce_rq *rq) { int ret = 0; + int to_charge = 0; struct oce_dev *dev = rq->parent; - - (void) oce_rq_charge(dev, rq, rq->cfg.q_len); + to_charge = rq->cfg.q_len - rq->buf_avail; + to_charge = min(to_charge, rq->rqb_free); + atomic_add_32(&rq->rqb_free, -to_charge); + (void) oce_rq_charge(rq, to_charge, B_FALSE); + /* ok to do it here since Rx has not even started */ + oce_rq_post_buffer(rq, to_charge); oce_arm_cq(dev, rq->cq->cq_id, 0, B_TRUE); return (ret); } /* oce_start_rq */ /* Checks for pending rx buffers with Stack */ int -oce_rx_pending(struct oce_dev *dev) +oce_rx_pending(struct oce_dev *dev, struct oce_rq *rq, int32_t timeout) { int ti; + _NOTE(ARGUNUSED(dev)); - for (ti = 0; ti < 200; ti++) { - if (dev->rq[0]->pending > 0) { - OCE_MSDELAY(1); + for (ti = 0; ti < timeout; ti++) { + if (rq->pending > 0) { + OCE_MSDELAY(10); continue; } else { - dev->rq[0]->pending = 0; + rq->pending = 0; break; } } - return (dev->rq[0]->pending); + return (rq->pending); } - -static inline void -oce_rx_drop_pkt(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) -{ - int frag_cnt; - oce_rq_bdesc_t *rqbd; - struct rq_shadow_entry *shadow_rq; - shadow_rq = rq->shadow_ring; - for (frag_cnt = 0; frag_cnt < cqe->u0.s.num_fragments; frag_cnt++) { - rqbd = shadow_rq[rq->ring->cidx].rqbd; - oce_rqb_free(rq, rqbd); - RING_GET(rq->ring, 1); - } -}
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_stat.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_stat.c Thu Aug 05 11:14:15 2010 -0600 @@ -33,6 +33,14 @@ #include <oce_stat.h> #include <oce_buf.h> +int pow10[5] = { + 0, + 10, + 100, + 1000, + 10000 +}; + /* * function called by kstat to update the stats counters * @@ -176,7 +184,7 @@ /* allocate the device copy of the stats */ dev->stats_dbuf = oce_alloc_dma_buffer(dev, sizeof (struct mbx_get_nic_stats), - DDI_DMA_CONSISTENT); + NULL, DDI_DMA_CONSISTENT); if (dev->stats_dbuf == NULL) { oce_log(dev, CE_NOTE, MOD_CONFIG, "Could not allocate stats_dbuf: %p", @@ -294,11 +302,16 @@ } switch (stat) { - case MAC_STAT_IFSPEED: - if (dev->state & STATE_MAC_STARTED) - *val = 10000000000ull; - else - *val = 0; + case MAC_STAT_IFSPEED: { + struct link_status link = {0}; + if (dev->link_speed < 0) { + (void) oce_get_link_status(dev, &link); + dev->link_speed = link.qos_link_speed ? + link.qos_link_speed * 10 : + pow10[link.mac_speed]; + } + *val = dev->link_speed * 1000000ull; + } break; case MAC_STAT_RBYTES:
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_tx.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_tx.c Thu Aug 05 11:14:15 2010 -0600 @@ -33,18 +33,18 @@ static void oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed); static int oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, - mblk_t *mp); + mblk_t *mp, uint32_t pkt_len); static int oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp, uint32_t pkt_len); static void oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd); static int oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq, size_t size, int flags); -static oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq); +static inline oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq); static void oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd); -static void oce_wqmd_free(struct oce_wq *wq, oce_wqe_desc_t *wqed); +static void oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd); static void oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd); -static inline oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq); +static oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq); static int oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq); static void oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd); static void oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed); @@ -54,7 +54,7 @@ static ddi_dma_attr_t tx_map_dma_attr = { - DMA_ATTR_V0, /* version number */ + DMA_ATTR_V0, /* version number */ 0x0000000000000000ull, /* low address */ 0xFFFFFFFFFFFFFFFFull, /* high address */ 0x0000000000010000ull, /* dma counter max */ @@ -65,7 +65,23 @@ 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */ OCE_MAX_TXDMA_COOKIES, /* scatter/gather list length */ 0x00000001, /* granularity */ - 0 /* DMA flags */ + DDI_DMA_FLAGERR /* dma_attr_flags */ +}; + + +ddi_dma_attr_t oce_tx_dma_buf_attr = { + DMA_ATTR_V0, /* version number */ + 0x0000000000000000ull, /* low address */ + 0xFFFFFFFFFFFFFFFFull, /* high address */ + 0x00000000FFFFFFFFull, /* dma counter max */ + OCE_DMA_ALIGNMENT, /* alignment */ + 0x000007FF, /* burst sizes */ + 0x00000001, /* minimum transfer size */ + 0x00000000FFFFFFFFull, /* maximum transfer size */ + 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */ + 1, /* scatter/gather list length */ + 0x00000001, /* granularity */ + DDI_DMA_FLAGERR /* dma_attr_flags */ }; /* @@ -245,7 +261,9 @@ { struct oce_dev *dev; dev = wq->parent; - wqbd->wqb = oce_alloc_dma_buffer(dev, size, flags); + + wqbd->wqb = oce_alloc_dma_buffer(dev, size, &oce_tx_dma_buf_attr, + flags); if (wqbd->wqb == NULL) { return (DDI_FAILURE); } @@ -278,9 +296,7 @@ static inline oce_wq_bdesc_t * oce_wqb_alloc(struct oce_wq *wq) { - oce_wq_bdesc_t *wqbd; - wqbd = OCE_LIST_REM_HEAD(&wq->wq_buf_list); - return (wqbd); + return (OCE_LIST_REM_HEAD(&wq->wq_buf_list)); } /* @@ -307,10 +323,7 @@ static inline oce_wq_mdesc_t * oce_wqm_alloc(struct oce_wq *wq) { - oce_wq_mdesc_t *wqmd; - wqmd = OCE_LIST_REM_HEAD(&wq->wq_mdesc_list); - return (wqmd); - + return (OCE_LIST_REM_HEAD(&wq->wq_mdesc_list)); } /* oce_wqm_alloc */ /* @@ -336,19 +349,13 @@ * return none */ static void -oce_wqmd_free(struct oce_wq *wq, oce_wqe_desc_t *wqed) +oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd) { - int ndesc; - oce_wq_mdesc_t *wqmd; - - if (wqed == NULL) { + if (wqmd == NULL) { return; } - for (ndesc = 0; ndesc < wqed->nhdl; ndesc++) { - wqmd = wqed->hdesc[ndesc].hdl; - (void) ddi_dma_unbind_handle(wqmd->dma_handle); - oce_wqm_free(wq, wqmd); - } + (void) ddi_dma_unbind_handle(wqmd->dma_handle); + oce_wqm_free(wq, wqmd); } /* @@ -361,12 +368,10 @@ int oce_wqe_desc_ctor(void *buf, void *arg, int kmflags) { - oce_wqe_desc_t *wqed = (oce_wqe_desc_t *)buf; - + _NOTE(ARGUNUSED(buf)); _NOTE(ARGUNUSED(arg)); _NOTE(ARGUNUSED(kmflags)); - bzero(wqed, sizeof (oce_wqe_desc_t)); return (DDI_SUCCESS); } @@ -388,16 +393,26 @@ * function to choose a WQ given a mblk depending on priority, flowID etc. * * dev - software handle to device - * pkt - the mblk to send + * mp - the mblk to send * * return pointer to the WQ selected */ +static uint8_t oce_tx_hash_policy = 0x4; struct oce_wq * -oce_get_wq(struct oce_dev *dev, mblk_t *pkt) +oce_get_wq(struct oce_dev *dev, mblk_t *mp) { - _NOTE(ARGUNUSED(pkt)); + struct oce_wq *wq; + int qidx = 0; + if (dev->nwqs > 1) { + qidx = mac_pkt_hash(DL_ETHER, mp, oce_tx_hash_policy, B_TRUE); + qidx = qidx % dev->nwqs; + + } else { + qidx = 0; + } + wq = dev->wq[qidx]; /* for the time being hardcode */ - return (dev->wq[0]); + return (wq); } /* oce_get_wq */ /* @@ -442,6 +457,7 @@ oce_wq_bdesc_t *wqbd; caddr_t buf_va; struct oce_dev *dev = wq->parent; + int len = 0; wqbd = oce_wqb_alloc(wq); if (wqbd == NULL) { @@ -452,19 +468,17 @@ } /* create a fragment wqe for the packet */ - wqed->frag[1].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi; - wqed->frag[1].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo; + wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi; + wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo; buf_va = DBUF_VA(wqbd->wqb); /* copy pkt into buffer */ - for (; mp != NULL; mp = mp->b_cont) { + for (len = 0; mp != NULL && len < pkt_len; mp = mp->b_cont) { bcopy(mp->b_rptr, buf_va, MBLKL(mp)); buf_va += MBLKL(mp); + len += MBLKL(mp); } - wqed->frag[1].u0.s.frag_len = pkt_len; - wqed->hdesc[0].hdl = (void *)(wqbd); - (void) ddi_dma_sync(DBUF_DHDL(wqbd->wqb), 0, pkt_len, DDI_DMA_SYNC_FORDEV); @@ -474,9 +488,12 @@ oce_wqb_free(wq, wqbd); return (EIO); } - wqed->frag_cnt = 2; - wqed->nhdl = 1; - wqed->type = COPY_WQE; + wqed->frag[wqed->frag_idx].u0.s.frag_len = pkt_len; + wqed->hdesc[wqed->nhdl].hdl = (void *)(wqbd); + wqed->hdesc[wqed->nhdl].type = COPY_WQE; + wqed->frag_cnt++; + wqed->frag_idx++; + wqed->nhdl++; return (0); } /* oce_bcopy_wqe */ @@ -490,75 +507,52 @@ * return DDI_SUCCESS=>success, DDI_FAILURE=>error */ static int -oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp) +oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp, + uint32_t pkt_len) { ddi_dma_cookie_t cookie; oce_wq_mdesc_t *wqmd; - int32_t nfrag = 1; uint32_t ncookies; int ret; - uint32_t len; struct oce_dev *dev = wq->parent; - wqed->nhdl = 0; - wqed->mp = mp; - - for (; mp != NULL; mp = mp->b_cont) { - len = MBLKL(mp); - if (len == 0) { - oce_log(dev, CE_NOTE, MOD_TX, "%s", - "Zero len MBLK "); - continue; - } - - wqmd = oce_wqm_alloc(wq); - if (wqmd == NULL) { - oce_log(dev, CE_WARN, MOD_TX, "%s", - "wqm pool empty"); - ret = ENOMEM; - goto map_fail; - } + wqmd = oce_wqm_alloc(wq); + if (wqmd == NULL) { + oce_log(dev, CE_WARN, MOD_TX, "%s", + "wqm pool empty"); + return (ENOMEM); + } - ret = ddi_dma_addr_bind_handle(wqmd->dma_handle, - (struct as *)0, (caddr_t)mp->b_rptr, - len, DDI_DMA_WRITE | DDI_DMA_STREAMING, - DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies); - if (ret != DDI_DMA_MAPPED) { - oce_log(dev, CE_WARN, MOD_TX, "%s", - "Failed to Map SGL"); - /* free the last one */ - oce_wqm_free(wq, wqmd); - goto map_fail; - } + ret = ddi_dma_addr_bind_handle(wqmd->dma_handle, + (struct as *)0, (caddr_t)mp->b_rptr, + pkt_len, DDI_DMA_WRITE | DDI_DMA_STREAMING, + DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies); + if (ret != DDI_DMA_MAPPED) { + oce_log(dev, CE_WARN, MOD_TX, "MAP FAILED %d", + ret); + /* free the last one */ + oce_wqm_free(wq, wqmd); + return (ENOMEM); + } + do { + wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi = + ADDR_HI(cookie.dmac_laddress); + wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo = + ADDR_LO(cookie.dmac_laddress); + wqed->frag[wqed->frag_idx].u0.s.frag_len = + (uint32_t)cookie.dmac_size; + wqed->frag_cnt++; + wqed->frag_idx++; + if (--ncookies > 0) + ddi_dma_nextcookie(wqmd->dma_handle, + &cookie); + else break; + } while (ncookies > 0); - do { - wqed->frag[nfrag].u0.s.frag_pa_hi = - ADDR_HI(cookie.dmac_laddress); - wqed->frag[nfrag].u0.s.frag_pa_lo = - ADDR_LO(cookie.dmac_laddress); - wqed->frag[nfrag].u0.s.frag_len = - (uint32_t)cookie.dmac_size; - nfrag++; - if (--ncookies > 0) - ddi_dma_nextcookie(wqmd->dma_handle, - &cookie); - else break; - } while (ncookies > 0); - - wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd; - wqed->nhdl++; - - (void) ddi_dma_sync(wqmd->dma_handle, - 0, 0, DDI_DMA_SYNC_FORDEV); - } - wqed->frag_cnt = nfrag; - wqed->type = MAPPED_WQE; + wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd; + wqed->hdesc[wqed->nhdl].type = MAPPED_WQE; + wqed->nhdl++; return (0); - -map_fail: - wqed->mp = NULL; - oce_wqmd_free(wq, wqed); - return (ret); } /* oce_map_wqe */ static inline int @@ -703,14 +697,15 @@ uint32_t pkt_len = 0; int num_mblks = 0; int ret = 0; + uint32_t mss = 0; uint32_t flags = 0; - uint32_t mss = 0; + int len = 0; /* retrieve the adap priv struct ptr */ dev = wq->parent; /* check if we have enough free slots */ - if (wq->wq_free < wq->cfg.q_len/2) { + if (wq->wq_free < dev->tx_reclaim_threshold) { (void) oce_process_tx_compl(wq, B_FALSE); } if (wq->wq_free < OCE_MAX_TX_HDL) { @@ -723,28 +718,28 @@ num_mblks++; } - /* Retrieve LSO info */ + if (pkt_len == 0 || num_mblks == 0) { + freemsg(mp); + return (NULL); + } + + /* retrieve LSO information */ mac_lso_get(mp, &mss, &flags); /* get the offload flags */ mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &csum_flags); - /* Limit should be always less than Tx Buffer Size */ - if (pkt_len < dev->tx_bcopy_limit) { - use_copy = B_TRUE; - } else { - /* restrict the mapped segment to wat we support */ - if (num_mblks > OCE_MAX_TX_HDL) { - nmp = msgpullup(mp, -1); - if (nmp == NULL) { - atomic_inc_32(&wq->pkt_drops); - freemsg(mp); - return (NULL); - } - /* Reset it to new collapsed mp */ + /* restrict the mapped segment to wat we support */ + if (num_mblks > OCE_MAX_TX_HDL) { + nmp = msgpullup(mp, -1); + if (nmp == NULL) { + atomic_inc_32(&wq->pkt_drops); freemsg(mp); - mp = nmp; + return (NULL); } + /* Reset it to new collapsed mp */ + freemsg(mp); + mp = nmp; } /* Get the packet descriptor for Tx */ @@ -767,14 +762,34 @@ etype = ntohs(eh->ether_type); ip_offset = sizeof (struct ether_header); } - bzero(wqed, sizeof (oce_wqe_desc_t)); /* Save the WQ pointer */ wqed->wq = wq; - if (use_copy == B_TRUE) { + wqed->frag_idx = 1; /* index zero is always header */ + wqed->frag_cnt = 0; + wqed->nhdl = 0; + wqed->mp = NULL; + OCE_LIST_LINK_INIT(&wqed->link); + + /* If entire packet is less than the copy limit just do copy */ + if (pkt_len < dev->tx_bcopy_limit) { + use_copy = B_TRUE; ret = oce_bcopy_wqe(wq, wqed, mp, pkt_len); } else { - ret = oce_map_wqe(wq, wqed, mp); + /* copy or dma map the individual fragments */ + for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) { + len = MBLKL(nmp); + if (len == 0) { + continue; + } + if (len < dev->tx_bcopy_limit) { + ret = oce_bcopy_wqe(wq, wqed, nmp, len); + } else { + ret = oce_map_wqe(wq, wqed, nmp, len); + } + if (ret != 0) + break; + } } /* @@ -782,15 +797,14 @@ * drop the packet */ if (ret != 0) { - kmem_cache_free(wq->wqed_cache, wqed); - /* drop the packet */ + oce_free_wqed(wq, wqed); atomic_inc_32(&wq->pkt_drops); freemsg(mp); return (NULL); } - /* increment pending wqed to be scheduled */ wqeh = (struct oce_nic_hdr_wqe *)&wqed->frag[0]; + bzero(wqeh, sizeof (struct oce_nic_hdr_wqe)); /* fill rest of wqe header fields based on packet */ if (flags & HW_LSO) { @@ -823,12 +837,13 @@ wqeh->u0.s.crc = B_TRUE; wqeh->u0.s.total_length = pkt_len; - /* frag count + header wqe */ - num_wqes = wqed->frag_cnt; + num_wqes = wqed->frag_cnt + 1; /* h/w expects even no. of WQEs */ - if (num_wqes & 0x1) + if (num_wqes & 0x1) { + bzero(&wqed->frag[num_wqes], sizeof (struct oce_nic_frag_wqe)); num_wqes++; + } wqed->wqe_cnt = (uint16_t)num_wqes; wqeh->u0.s.num_wqe = num_wqes; DW_SWAP(u32ptr(&wqed->frag[0]), (wqed->wqe_cnt * NIC_WQE_SIZE)); @@ -840,7 +855,6 @@ goto wqe_fail; } atomic_add_32(&wq->wq_free, -num_wqes); - wqed->wq_start_idx = wq->ring->pidx; /* fill the wq for adapter */ oce_fill_ring_descs(wq, wqed); @@ -854,15 +868,16 @@ reg_value = (num_wqes << 16) | wq->wq_id; /* Ring the door bell */ OCE_DB_WRITE32(dev, PD_TXULP_DB, reg_value); + mutex_exit(&wq->tx_lock); if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) { ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); } - mutex_exit(&wq->tx_lock); /* free mp if copied or packet chain collapsed */ if (use_copy == B_TRUE) { freemsg(mp); - } + } else + wqed->mp = mp; return (NULL); wqe_fail: @@ -870,9 +885,6 @@ if (tagged) { oce_insert_vtag(mp, vlan_tag); } - - /* set it to null in case map_wqe has set it */ - wqed->mp = NULL; oce_free_wqed(wq, wqed); return (mp); } /* oce_send_packet */ @@ -889,16 +901,18 @@ static void oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed) { + int i = 0; if (wqed == NULL) { return; } - if (wqed->type == COPY_WQE) { - oce_wqb_free(wq, wqed->hdesc[0].hdl); - } else if (wqed->type == MAPPED_WQE) { - oce_wqmd_free(wq, wqed); - } else ASSERT(0); - + for (i = 0; i < wqed->nhdl; i++) { + if (wqed->hdesc[i].type == COPY_WQE) { + oce_wqb_free(wq, wqed->hdesc[i].hdl); + } else if (wqed->hdesc[i].type == MAPPED_WQE) { + oce_wqmd_free(wq, wqed->hdesc[i].hdl); + } + } if (wqed->mp) freemsg(wqed->mp); kmem_cache_free(wq->wqed_cache, wqed);
--- a/usr/src/uts/common/io/fibre-channel/fca/oce/oce_utils.c Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/io/fibre-channel/fca/oce/oce_utils.c Thu Aug 05 11:14:15 2010 -0600 @@ -62,6 +62,13 @@ } } /* oce_page_list */ +void +oce_list_link_init(OCE_LIST_NODE_T *list_node) +{ + list_node->next = NULL; + list_node->prev = NULL; +} + static inline void oce_list_insert_node(OCE_LIST_NODE_T *list_node, OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node) @@ -206,3 +213,35 @@ oce_list_remove(list_node); mutex_exit(&list_hdr->list_lock); } + +void +oce_gen_hkey(char *hkey, int key_size) +{ + int i; + int nkeys = key_size/sizeof (uint32_t); + for (i = 0; i < nkeys; i++) { + (void) random_get_pseudo_bytes( + (uint8_t *)&hkey[i * sizeof (uint32_t)], + sizeof (uint32_t)); + } +} + +int +oce_atomic_reserve(uint32_t *count_p, uint32_t n) +{ + uint32_t oldval; + uint32_t newval; + + /* + * ATOMICALLY + */ + do { + oldval = *count_p; + if (oldval < n) + return (-1); + newval = oldval - n; + + } while (atomic_cas_32(count_p, oldval, newval) != oldval); + + return (newval); +}
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_buf.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_buf.h Thu Aug 05 11:14:15 2010 -0600 @@ -44,10 +44,9 @@ : (((_START) + (_STEP)) - (_END))) #define OCE_MAX_TX_HDL 8 -#define OCE_MAX_TXDMA_COOKIES 16 +#define OCE_MAX_TXDMA_COOKIES 18 #define OCE_TXMAP_ALIGN 1 #define OCE_TX_MAX_FRAGS (OCE_MAX_TX_HDL * OCE_MAX_TXDMA_COOKIES) -#define OCE_TX_LO_WM OCE_TX_MAX_FRAGS /* helper structure to access OS addresses */ typedef union oce_addr_s { @@ -79,8 +78,8 @@ #define DBUF_VA(obj) (((oce_dma_buf_t *)(obj))->base) #define DBUF_DHDL(obj) (((oce_dma_buf_t *)(obj))->dma_handle) #define DBUF_AHDL(obj) (((oce_dma_buf_t *)obj))->acc_handle) -#define DBUF_SYNC(obj, flags) ddi_dma_sync(DBUF_DHDL(obj), 0,\ - ((oce_dma_buf_t *)obj)->len, (flags)) +#define DBUF_SYNC(obj, flags) (void) ddi_dma_sync(DBUF_DHDL(obj), 0,\ + 0, (flags)) typedef struct oce_ring_buffer_s { uint16_t cidx; /* Get ptr */ @@ -92,12 +91,12 @@ }oce_ring_buffer_t; typedef struct oce_rq_bdesc_s { - OCE_LIST_NODE_T link; oce_dma_buf_t *rqb; struct oce_rq *rq; oce_addr64_t frag_addr; mblk_t *mp; frtn_t fr_rtn; + uint32_t ref_cnt; }oce_rq_bdesc_t; typedef struct oce_wq_bdesc_s { @@ -119,6 +118,7 @@ }; typedef struct _oce_handle_s { + enum entry_type type; void *hdl; /* opaque handle */ }oce_handle_t; @@ -128,13 +128,10 @@ struct oce_nic_frag_wqe frag[OCE_TX_MAX_FRAGS]; struct oce_wq *wq; mblk_t *mp; - enum entry_type type; - uint16_t wq_start_idx; - uint16_t wq_end_idx; uint16_t wqe_cnt; - uint16_t pkt_len; /* 64K MAX */ - uint32_t frag_cnt; - uint32_t nhdl; + uint16_t frag_idx; + uint16_t frag_cnt; + uint16_t nhdl; }oce_wqe_desc_t; #pragma pack(1)
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw.h Thu Aug 05 11:14:15 2010 -0600 @@ -136,6 +136,13 @@ #define ASYNC_EVENT_LINK_UP 0x1 #define ASYNC_EVENT_LINK_DOWN 0x0 +/* port link_status */ +#define ASYNC_EVENT_LOGICAL 0x02 + +/* Logical Link Status */ +#define NTWK_LOGICAL_LINK_DOWN 0 +#define NTWK_LOGICAL_LINK_UP 1 + /* Rx filter bits */ #define NTWK_RX_FILTER_IP_CKSUM 0x1 #define NTWK_RX_FILTER_TCP_CKSUM 0x2 @@ -812,17 +819,10 @@ struct mbx_hdr hdr; union { struct { -#ifdef _BIG_ENDIAN - /* dw 0 */ - uint8_t if_id; - uint8_t promiscuous; - uint16_t num_mac; -#else /* dw 0 */ uint16_t num_mac; uint8_t promiscuous; uint8_t if_id; -#endif /* dw 1-48 */ struct { uint8_t byte[6]; @@ -1254,6 +1254,36 @@ uint8_t data_buffer[4]; /* + IMAGE_TRANSFER_SIZE */ }; +/* ULP MODE SUPPORTED */ +enum { + ULP_TOE_MODE = 0x1, + ULP_NIC_MODE = 0x2, + ULP_RDMA_MODE = 0x4, + ULP_ISCSI_INI_MODE = 0x10, + ULP_ISCSI_TGT_MODE = 0x20, + ULP_FCOE_INI_MODE = 0x40, + ULP_FCOE_TGT_MODE = 0x80, + ULP_DAL_MODE = 0x100, + ULP_LRO_MODE = 0x200 +}; + +/* Function Mode Supported */ +enum { + TOE_MODE = 0x1, /* TCP offload */ + NIC_MODE = 0x2, /* Raw Ethernet */ + RDMA_MODE = 0x4, /* RDMA */ + VM_MODE = 0x8, /* VM */ + ISCSI_INI_MODE = 0x10, /* iSCSI initiator */ + ISCSI_TGT_MODE = 0x20, /* iSCSI target plus initiator */ + FCOE_INI_MODE = 0x40, /* FCoE Initiator */ + FCOE_TGT_MODE = 0x80, /* FCoE target */ + DAL_MODE = 0x100, /* DAL */ + LRO_MODE = 0x200, /* LRO */ + FLEX10_MODE = 0x400, /* FLEX-10 or VNIC */ + NCSI_MODE = 0x800, /* NCSI */ + INVALID_MODE = 0x8000 /* Invalid */ +}; + struct mbx_common_query_fw_config { struct mbx_hdr hdr; union { @@ -1266,32 +1296,23 @@ uint32_t asic_revision; uint32_t port_id; /* used for stats retrieval */ uint32_t function_mode; - uint32_t ulp0_mode; - uint32_t ulp0_nic_wqid_base; - uint32_t ulp0_nic_wq_tot; - uint32_t ulp0_toe_wqid_base; - uint32_t ulp0_toe_wq_tot; - uint32_t ulp0_toe_rqid_base; - uint32_t ulp0_toe_rqid_tot; - uint32_t ulp0_toe_defrqid_base; - uint32_t ulp0_toe_defrq_tot; - uint32_t ulp0_lro_rqid_base; - uint32_t ulp0_lro_rqid_tot; - uint32_t ulp0_iscsi_icd_base; - uint32_t ulp0_iscsi_icd_tot; - uint32_t ulp1_mode; - uint32_t ulp1_nic_wqid_base; - uint32_t ulp1_wq_tot; - uint32_t ulp1_toe_wqid_base; - uint32_t ulp1_toe_wq_tot; - uint32_t ulp1_toe_rqid_base; - uint32_t ulp1_toe_rqid_tot; - uint32_t ulp1_toe_defrqid_base; - uint32_t ulp1_toe_defrq_tot; - uint32_t ulp1_lro_rqid_base; - uint32_t ulp1_lro_rqid_tot; - uint32_t ulp1_iscsi_icd_base; - uint32_t ulp1_iscsi_icd_tot; + struct { + + uint32_t mode; + uint32_t wq_base; + uint32_t wq_count; + uint32_t sq_base; + uint32_t sq_count; + uint32_t rq_base; + uint32_t rq_count; + uint32_t dq_base; + uint32_t dq_count; + uint32_t lro_base; + uint32_t lro_count; + uint32_t icd_base; + uint32_t icd_count; + } ulp[2]; + uint32_t function_caps; }rsp; }params; };
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw_eth.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_hw_eth.h Thu Aug 05 11:14:15 2010 -0600 @@ -72,6 +72,14 @@ OPCODE_CONFIG_NIC_RSS_ADVANCED = 16 }; +enum { + RSS_ENABLE_NONE = 0x0, /* (No RSS) */ + RSS_ENABLE_IPV4 = 0x1, /* (IPV4 HASH enabled ) */ + RSS_ENABLE_TCP_IPV4 = 0x2, /* (TCP IPV4 Hash enabled) */ + RSS_ENABLE_IPV6 = 0x4, /* (IPV6 HASH enabled) */ + RSS_ENABLE_TCP_IPV6 = 0x8 /* (TCP IPV6 HASH */ + +}; /* NIC header WQE */ struct oce_nic_hdr_wqe { union { @@ -240,12 +248,12 @@ uint32_t rsvd0:1; uint32_t vlan_tag_present:1; uint32_t mac_dst:6; - uint32_t ip6_frame:1; + uint32_t ip_ver:1; uint32_t l4_cksum_pass:1; uint32_t ip_cksum_pass:1; uint32_t udpframe:1; uint32_t tcpframe:1; - uint32_t ip4_frame:1; + uint32_t ipframe:1; uint32_t rss_hp:1; uint32_t error:1; @@ -272,12 +280,12 @@ /* dw 1 */ uint32_t error:1; uint32_t rss_hp:1; - uint32_t ip4_frame:1; + uint32_t ipframe:1; uint32_t tcpframe:1; uint32_t udpframe:1; uint32_t ip_cksum_pass:1; uint32_t l4_cksum_pass:1; - uint32_t ip6_frame:1; + uint32_t ip_ver:1; uint32_t mac_dst:6; uint32_t vlan_tag_present:1; uint32_t rsvd0:1; @@ -637,6 +645,36 @@ }params; }; +/* [01] OPCODE_CONFIG_NIC_RSS */ +struct mbx_config_nic_rss { + struct mbx_hdr hdr; + union { + struct { +#ifdef _BIG_ENDIAN + uint32_t if_id; + uint16_t cpu_tbl_sz_log2; + uint16_t enable_rss; + uint32_t hash[10]; + uint8_t cputable[128]; + uint8_t rsvd[3]; + uint8_t flush; +#else + uint32_t if_id; + uint16_t enable_rss; + uint16_t cpu_tbl_sz_log2; + uint32_t hash[10]; + uint8_t cputable[128]; + uint8_t flush; + uint8_t rsvd[3]; +#endif + }req; + struct { + uint8_t rsvd[3]; + uint8_t rss_bank; + }rsp; + }params; +}; + #pragma pack() #ifdef __cplusplus
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_impl.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_impl.h Thu Aug 05 11:14:15 2010 -0600 @@ -63,6 +63,8 @@ #include <sys/fm/util.h> #include <sys/fm/io/ddi.h> #include <sys/note.h> +#include <sys/pci.h> +#include <sys/random.h> #include <oce_hw.h> #include <oce_hw_eth.h> #include <oce_io.h> @@ -70,6 +72,21 @@ #include <oce_utils.h> #include <oce_version.h> +#define SIZE_128 128 +#define SIZE_256 256 +#define SIZE_512 512 +#define SIZE_1K 1024 +#define SIZE_2K (2 * 1024) +#define SIZE_4K (4 * 1024) +#define SIZE_8K (8 * 1024) + +#define END 0xdeadface + +#define OCE_MAX_ETH_FRAME_SIZE 1500 +#define OCE_MAX_JUMBO_FRAME_SIZE 9018 +#define OCE_MIN_ETH_FRAME_SIZE 64 +#define OCE_LLC_SNAP_HDR_LEN 8 + #define OCE_MIN_MTU 1500 #define OCE_MAX_MTU 9000 #define OCE_MAX_MCA 32 @@ -78,47 +95,51 @@ #define OCE_MAX_EQ 8 #define OCE_MAX_CQ 1024 #define OCE_MAX_WQ 8 -#define OCE_WQ_NUM_BUFFERS 2048 -#define OCE_WQ_BUF_SIZE 2048 -#define OCE_LSO_MAX_SIZE (32 * 1024) -#define OCE_DEFAULT_TX_BCOPY_LIMIT 1024 +#define OCE_MAX_RQ 5 + +#define OCE_WQ_NUM_BUFFERS 2048 +#define OCE_WQ_BUF_SIZE 2048 +#define OCE_LSO_MAX_SIZE (64 * 1024) +#define OCE_DEFAULT_TX_BCOPY_LIMIT 512 #define OCE_DEFAULT_RX_BCOPY_LIMIT 128 -#define OCE_DEFAULT_WQ_EQD 16 +#define OCE_DEFAULT_WQ_EQD 16 + +#define OCE_DEFAULT_TX_RING_SIZE 2048 +#define OCE_DEFAULT_RX_RING_SIZE 1024 +#define OCE_DEFAULT_WQS 1 +#define OCE_DEFAULT_RQS 1 +#define OCE_MAX_RQS 5 -#define OCE_MAX_RQ 8 -#define OCE_MAX_RQ_POSTS 255 -#define OCE_RQ_NUM_BUFFERS 2048 -#define OCE_RQ_BUF_SIZE 2048 +#define OCE_DEFAULT_RX_PKT_PER_INTR (OCE_DEFAULT_RX_RING_SIZE / 2) +#define OCE_DEFAULT_TX_RECLAIM_THRESHOLD 1024 +#define OCE_MAX_RQ_POSTS 255 +#define OCE_RQ_NUM_BUFFERS 2048 +#define OCE_RQ_BUF_SIZE 8192 #define OCE_DEFAULT_RECHARGE_THRESHOLD OCE_MAX_RQ_POSTS -#define OCE_NUM_USED_VECTORS 2 -#define OCE_DMA_ALIGNMENT 0x1000ull +#define OCE_NUM_USED_VECTORS 2 +#define OCE_ITBL_SIZE 64 +#define OCE_HKEY_SIZE 40 +#define OCE_DMA_ALIGNMENT 0x1000ull -#define OCE_DEFAULT_TX_RING_SIZE 2048 -#define OCE_DEFAULT_RX_RING_SIZE 1024 +#define OCE_MIN_VECTORS 1 -#define OCE_INVAL_IF_ID -1 - -#define OCE_DEFAULT_IF_CAP (MBX_RX_IFACE_FLAGS_PROMISCUOUS | \ - MBX_RX_IFACE_FLAGS_BROADCAST | \ +#define OCE_CAPAB_FLAGS (MBX_RX_IFACE_FLAGS_BROADCAST | \ + MBX_RX_IFACE_FLAGS_PROMISCUOUS | \ MBX_RX_IFACE_FLAGS_UNTAGGED | \ MBX_RX_IFACE_FLAGS_MCAST_PROMISCUOUS | \ MBX_RX_IFACE_FLAGS_PASS_L3L4) -#define OCE_DEFAULT_IF_CAP_EN (MBX_RX_IFACE_FLAGS_BROADCAST | \ +#define OCE_CAPAB_ENABLE (MBX_RX_IFACE_FLAGS_BROADCAST | \ MBX_RX_IFACE_FLAGS_UNTAGGED | \ - MBX_RX_IFACE_FLAGS_MCAST_PROMISCUOUS | \ MBX_RX_IFACE_FLAGS_PASS_L3L4) -#define OCE_RX_FILTER_GLOBAL_FLAGS (NTWK_RX_FILTER_IP_CKSUM | \ - NTWK_RX_FILTER_TCP_CKSUM | \ - NTWK_RX_FILTER_UDP_CKSUM | \ - NTWK_RX_FILTER_STRIP_CRC) - - #define OCE_FM_CAPABILITY (DDI_FM_EREPORT_CAPABLE | \ DDI_FM_ACCCHK_CAPABLE | \ DDI_FM_DMACHK_CAPABLE) + +#define OCE_DEFAULT_RSS_TYPE (RSS_ENABLE_IPV4|RSS_ENABLE_TCP_IPV4) + /* flow control definitions */ #define OCE_FC_NONE 0x00000000 #define OCE_FC_TX 0x00000001 @@ -181,42 +202,41 @@ }; struct oce_dev { - uint32_t dev_id; /* device ID or instance number */ - int32_t if_id; /* IF ID */ - uint8_t fn; /* function number */ - uint8_t fw_version[32]; /* fw version string */ - enum oce_driver_state state; /* state */ - struct oce_mq *mq; /* MQ ring */ - oce_dma_buf_t *bmbx; /* Bootstrap MailBox */ - kmutex_t bmbx_lock; /* Bootstrap Lock */ - uint16_t mod_mask; /* Log Mask */ - int16_t severity; /* Log level */ + kmutex_t bmbx_lock; /* Bootstrap Lock */ + kmutex_t dev_lock; /* lock for device */ + + /* Queues relarted */ struct oce_wq *wq[OCE_MAX_WQ]; /* TXQ Array */ struct oce_rq *rq[OCE_MAX_RQ]; /* RXQ Array */ struct oce_cq *cq[OCE_MAX_CQ]; /* Completion Queues */ struct oce_eq *eq[OCE_MAX_EQ]; /* Event Queues */ + struct oce_mq *mq; /* MQ ring */ + + /* driver state machine */ + enum oce_driver_state state; /* state */ + boolean_t suspended; /* CPR */ + uint32_t attach_state; /* attach progress */ + + oce_dma_buf_t *bmbx; /* Bootstrap MailBox */ + uint32_t tx_bcopy_limit; /* TX BCOPY Limit */ uint32_t rx_bcopy_limit; /* RX BCOPY Limit */ - - uint32_t cookie; + uint32_t tx_reclaim_threshold; /* Tx reclaim */ + uint32_t rx_pkt_per_intr; /* Rx pkts processed per intr */ - clock_t stat_ticks; - uint32_t in_stats; - - /* Add implementation specific stuff here */ + /* BARS */ + int num_bars; ddi_acc_handle_t pci_cfg_handle; /* Config space handle */ - int num_bars; ddi_acc_handle_t cfg_handle; /* MMIO PCI Config Space Regs */ - caddr_t csr_addr; ddi_acc_handle_t csr_handle; /* MMIO Control Status Regs */ + caddr_t csr_addr; caddr_t db_addr; + caddr_t dev_cfg_addr; ddi_acc_handle_t db_handle; /* MMIO DoorBell Area */ - caddr_t dev_cfg_addr; - ddi_acc_handle_t dev_cfg_handle; /* MMIO CONFIG SPACE */ + ddi_acc_handle_t dev_cfg_handle; /* MMIO CONFIG SPACE */ mac_handle_t mac_handle; /* MAC HANDLE */ - /* device info structure for device tree node */ - dev_info_t *dip; + /* device stats */ kstat_t *oce_kstats; /* NIC STATS */ oce_dma_buf_t *stats_dbuf; /* STATS BUFFER */ struct mbx_get_nic_stats *hw_stats; @@ -225,53 +245,61 @@ uint32_t tx_noxmtbuf; /* link status */ - struct link_status link; - - /* flow control settings */ - uint32_t flow_control; + link_state_t link_status; + int32_t link_speed; /* Link speed in Mbps */ - /* the type of interrupts supported */ - int intr_types; - /* number of vectors used */ - int num_vectors; - /* interrupt priority */ - uint_t intr_pri; + /* OS */ + uint32_t dev_id; /* device ID or instance number */ + dev_info_t *dip; /* device info structure for device tree node */ + + /* Interrupt related */ + int intr_type; /* INTR TYPE USED */ + int num_vectors; /* number of vectors used */ + uint_t intr_pri; /* interrupt priority */ int intr_cap; - /* intr handler table */ - ddi_intr_handle_t *htable; - - /* lock for device */ - kmutex_t dev_lock; - - /* hardware mac address */ - uint8_t mac_addr[ETHERADDRL]; - - /* Current Multicast address table that we have set to h/w */ - uint16_t num_mca; - struct ether_addr multi_cast[OCE_MAX_MCA]; + ddi_intr_handle_t *htable; /* intr handler table */ + int32_t hsize; /* device configuration */ - uint32_t pmac_id; /* used to add or remove mac */ - uint8_t unicast_addr[ETHERADDRL]; - uint32_t mtu; + uint32_t rq_max_bufs; /* maximum prealloced buffers */ + uint32_t rq_frag_size; /* Rxq fragment size */ enum oce_ring_size tx_ring_size; enum oce_ring_size rx_ring_size; - boolean_t lso_capable; - boolean_t promisc; - uint32_t if_cap_flags; - int32_t fm_caps; - uint32_t attach_state; - boolean_t suspended; - uint32_t neqs; /* No of event queues */ - uint32_t nwqs; /* No of Work Queues */ - uint32_t nrqs; /* No of Receive Queues */ - uint32_t nifs; /* No of interfaces created */ + uint32_t neqs; /* No of event queues */ + uint32_t nwqs; /* No of Work Queues */ + uint32_t nrqs; /* No of Receive Queues */ + uint32_t nifs; /* No of interfaces created */ + uint32_t tx_rings; + uint32_t rx_rings; + uint32_t pmac_id; /* used to add or remove mac */ + uint8_t unicast_addr[ETHERADDRL]; + uint32_t mtu; + int32_t fm_caps; + boolean_t rss_enable; /* RSS support */ + boolean_t lso_capable; /* LSO */ + boolean_t promisc; /* PROMISC MODE */ + uint32_t if_cap_flags; /* IF CAPAB */ + uint32_t flow_control; /* flow control settings */ + uint8_t mac_addr[ETHERADDRL]; /* hardware mac address */ + uint16_t num_mca; /* MCA supported */ + struct ether_addr multi_cast[OCE_MAX_MCA]; /* MC TABLE */ + uint32_t cookie; /* used during fw download */ /* fw config: only relevant fields */ - uint32_t config_number; - uint32_t asic_revision; - uint32_t port_id; - uint32_t function_mode; + uint32_t config_number; + uint32_t asic_revision; + uint32_t port_id; + uint32_t function_mode; + uint32_t function_caps; + uint32_t max_tx_rings; /* Max Rx rings available */ + uint32_t max_rx_rings; /* Max rx rings available */ + int32_t if_id; /* IF ID */ + uint8_t fn; /* function number */ + uint8_t fw_version[32]; /* fw version string */ + + /* Logging related */ + uint16_t mod_mask; /* Log Mask */ + int16_t severity; /* Log level */ }; /* GLD handler functions */ @@ -310,7 +338,6 @@ /* Interrupt handling */ int oce_setup_intr(struct oce_dev *dev); -int oce_alloc_intr(struct oce_dev *dev); int oce_teardown_intr(struct oce_dev *dev); int oce_setup_handlers(struct oce_dev *dev); void oce_remove_handler(struct oce_dev *dev);
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_io.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_io.h Thu Aug 05 11:14:15 2010 -0600 @@ -96,22 +96,22 @@ }; struct oce_eq { - /* configuration of this eq */ - struct eq_config eq_cfg; + /* Lock for this queue */ + kmutex_t lock; /* id assigned by the hw to this eq */ uint32_t eq_id; /* handle to the creating parent dev */ void *parent; /* callback context */ void *cb_context; - /* reference count of this structure */ - uint32_t ref_count; /* ring buffer for this eq */ oce_ring_buffer_t *ring; + /* reference count of this structure */ + uint32_t ref_count; /* Queue state */ qstate_t qstate; - /* Lock for this queue */ - kmutex_t lock; + /* configuration of this eq */ + struct eq_config eq_cfg; }; enum cq_len { @@ -138,10 +138,8 @@ typedef uint16_t (*cq_handler_t)(void *arg1); struct oce_cq { - /* configuration of this cq */ - struct cq_config cq_cfg; - /* reference count of this structure */ - uint32_t ref_count; + /* lock */ + kmutex_t lock; /* id given by the hardware */ uint32_t cq_id; /* parent device to which this cq belongs */ @@ -155,8 +153,10 @@ oce_ring_buffer_t *ring; /* Queue state */ qstate_t qstate; - /* lock */ - kmutex_t lock; + /* configuration of this cq */ + struct cq_config cq_cfg; + /* reference count of this structure */ + uint32_t ref_count; }; struct mq_config { @@ -167,8 +167,8 @@ }; struct oce_mq { - /* configuration of this mq */ - struct mq_config cfg; + /* lock for the mq */ + kmutex_t lock; /* handle to the parent device */ void *parent; /* send queue */ @@ -181,8 +181,9 @@ uint32_t mq_free; /* Queue state */ qstate_t qstate; - /* lock for the mq */ - kmutex_t lock; + + /* configuration of this mq */ + struct mq_config cfg; }; @@ -201,7 +202,8 @@ struct wq_config { /* qtype */ uint8_t wq_type; - uint8_t pad[3]; + uint16_t buf_size; + uint8_t pad[1]; uint32_t q_len; /* number of wqes */ uint16_t pd_id; /* protection domain id */ uint16_t pci_fn_num; /* pci function number */ @@ -211,15 +213,15 @@ }; struct oce_wq { - struct wq_config cfg; /* q config */ + kmutex_t tx_lock; /* lock for the WQ */ + kmutex_t txc_lock; /* tx compl lock */ void *parent; /* parent of this wq */ - uint16_t wq_id; /* wq ID */ oce_ring_buffer_t *ring; /* ring buffer managing the wqes */ struct oce_cq *cq; /* cq associated with this wq */ kmem_cache_t *wqed_cache; /* packet desc cache */ - OCE_LIST_T wqe_desc_list; /* packet descriptor list */ - oce_wq_bdesc_t *wq_bdesc_array; /* buffer desc array */ - OCE_LIST_T wq_buf_list; /* buffer list */ + oce_wq_bdesc_t *wq_bdesc_array; /* buffer desc array */ + OCE_LIST_T wq_buf_list; /* buffer list */ + OCE_LIST_T wqe_desc_list; /* packet descriptor list */ OCE_LIST_T wq_mdesc_list; /* free list of memory handles */ oce_wq_mdesc_t *wq_mdesc_array; /* preallocated memory handles */ uint32_t wqm_used; /* memory handles uses */ @@ -227,11 +229,11 @@ uint32_t wq_free; /* Wqe free */ uint32_t tx_deferd; /* Wqe free */ uint32_t pkt_drops; /* drops */ + /* Queue state */ qstate_t qstate; - kmutex_t tx_lock; /* lock for the WQ */ - kmutex_t txc_lock; /* tx compl lock */ - kmutex_t resched_lock; /* tx compl lock */ + uint16_t wq_id; /* wq ID */ + struct wq_config cfg; /* q config */ }; struct rq_config { @@ -259,14 +261,15 @@ uint32_t rss_cpuid; /* ring buffer managing the RQEs */ oce_ring_buffer_t *ring; - /* RQ Buffer cache */ - /* kmem_cache_t *rqb_cache; */ - /* shadow list of mblk for rq ring */ - struct rq_shadow_entry *shadow_ring; /* cq associated with this queue */ struct oce_cq *cq; oce_rq_bdesc_t *rq_bdesc_array; - OCE_LIST_T rq_buf_list; /* Free list */ + /* shadow list of mblk for rq ring */ + oce_rq_bdesc_t **shadow_ring; + oce_rq_bdesc_t **rqb_freelist; + uint32_t rqb_free; + uint32_t rqb_next_free; /* next free slot */ + uint32_t rqb_rc_head; /* recycling head */ uint32_t buf_avail; /* buffer avaialable with hw */ uint32_t pending; /* Buffers sent up */ /* Queue state */ @@ -285,11 +288,13 @@ /* dw 1 */ uint8_t mgmt_mac_duplex; uint8_t mgmt_mac_speed; - uint16_t rsvd0; + uint16_t qos_link_speed; + /* dw2 */ + uint32_t logical_link_status; }; oce_dma_buf_t *oce_alloc_dma_buffer(struct oce_dev *dev, - uint32_t size, uint32_t flags); + uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags); void oce_free_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf); oce_ring_buffer_t *create_ring_buffer(struct oce_dev *dev, @@ -342,7 +347,7 @@ int oce_start_rq(struct oce_rq *rq); void oce_clean_rq(struct oce_rq *rq); void oce_rq_discharge(struct oce_rq *rq); -int oce_rx_pending(struct oce_dev *dev); +int oce_rx_pending(struct oce_dev *dev, struct oce_rq *rq, int32_t timeout); /* event handling */ uint16_t oce_drain_mq_cq(void *arg); @@ -385,7 +390,8 @@ uint8_t vtag_cnt, boolean_t untagged, boolean_t enable_promisc); int oce_config_link(struct oce_dev *dev, boolean_t enable); - +int oce_config_rss(struct oce_dev *dev, uint16_t if_id, char *hkey, char *itbl, + int tbl_sz, uint16_t rss_type, uint8_t flush); int oce_issue_mbox(struct oce_dev *dev, queue_t *wq, mblk_t *mp, uint32_t *payload_length);
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_utils.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_utils.h Thu Aug 05 11:14:15 2010 -0600 @@ -47,16 +47,19 @@ #define OCE_DEFAULT_LOG_SETTINGS (CE_WARN | \ ((MOD_CONFIG | MOD_TX | MOD_RX) << 16)) +#define OCE_MAX_LOG_SETTINGS (CE_IGNORE | ((MOD_CONFIG | MOD_TX | \ + MOD_RX | MOD_ISR) << 16)) + #define oce_log(dev_p, level, module, fmt, arg...) { \ if (dev_p) { \ if ((dev_p->mod_mask & module) && \ (dev_p->severity < CE_IGNORE) && \ ((uint32_t)level >= dev_p->severity)) \ - cmn_err(level, "%s[%d]: %s[%d]: " fmt, OCE_MOD_NAME, \ - dev_p->dev_id, __FILE__, __LINE__, ## arg); \ + cmn_err(level, "%s[%d]: " fmt, OCE_MOD_NAME, \ + dev_p->dev_id, ## arg); \ } else { \ - cmn_err(level, "%s[%d]: %s[%d]: " fmt, OCE_MOD_NAME, \ - 0, __FILE__, __LINE__, ## arg); \ + cmn_err(level, "%s[%d]: " fmt, OCE_MOD_NAME, \ + 0, ## arg); \ } \ } @@ -90,11 +93,13 @@ /* Utility Functions */ #define OCE_DW_SWAP(datap, length) { \ - int len; \ - for (len = ((length)/4 - 1); len >= 0; len--) { \ - *((uint32_t *)(datap) + len) = \ - LE_32(*((uint32_t *)(datap) + len)); \ - } \ + int len; \ + uint32_t *wptr = (uint32_t *)(datap); \ + len = (length) + (((length) %4) ? (4 - (4 %(length))) : 0); \ + for (len = len/4; len > 0; len--) { \ + *wptr = LE_32(*wptr); \ + wptr++; \ + } \ } @@ -110,14 +115,15 @@ }OCE_LIST_NODE_T; typedef struct { + kmutex_t list_lock; OCE_LIST_NODE_T head; int32_t nitems; - kmutex_t list_lock; - }OCE_LIST_T; /* externs for list manipulation functions */ + +void oce_list_link_init(OCE_LIST_NODE_T *list_node); void oce_list_create(OCE_LIST_T *list_hdr, void *arg); void oce_list_destroy(OCE_LIST_T *list_hdr); void oce_list_insert_tail(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node); @@ -125,6 +131,7 @@ void oce_list_remove_node(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node); boolean_t oce_list_is_empty(OCE_LIST_T *list_hdr); int32_t oce_list_items_avail(OCE_LIST_T *list_hdr); +int oce_atomic_reserve(uint32_t *count_p, uint32_t n); #define OCE_LIST_CREATE(_LH, _LCK_PRI) oce_list_create((_LH), (_LCK_PRI)) #define OCE_LIST_DESTROY(_LH) oce_list_destroy((_LH)) @@ -135,6 +142,9 @@ #define OCE_LIST_REMOVE(_LH, _N) \ oce_list_remove_node((_LH), (void *)(_N)) #define OCE_LIST_SIZE(_LH) oce_list_items_avail((_LH)) +#define OCE_LIST_LINK_INIT(_N) oce_list_link_init(_N) + +void oce_gen_hkey(char *hkey, int key_size); #ifdef __cplusplus }
--- a/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_version.h Thu Aug 05 09:40:41 2010 -0700 +++ b/usr/src/uts/common/sys/fibre-channel/fca/oce/oce_version.h Thu Aug 05 11:14:15 2010 -0600 @@ -38,7 +38,7 @@ #define OCE_MAJOR_VERSION "1" #define OCE_MINOR_VERSION "1" #define OCE_RELEASE_NUM "0" -#define OCE_PROTO_LEVEL "f2" +#define OCE_PROTO_LEVEL "s" #define OCE_VERSION OCE_MAJOR_VERSION "." \ OCE_MINOR_VERSION \