From fc89cc358fb64e2429aeae0f37906126636507ec Mon Sep 17 00:00:00 2001 From: Vishal Kulkarni Date: Wed, 30 Oct 2019 20:17:57 +0530 Subject: cxgb4: fix panic when attaching to ULD fail Release resources when attaching to ULD fail. Otherwise, data mismatch is seen between LLD and ULD later on, which lead to kernel panic when accessing resources that should not even exist in the first place. Fixes: 94cdb8bb993a ("cxgb4: Add support for dynamic allocation of resources for ULD") Signed-off-by: Shahjada Abul Husain Signed-off-by: Vishal Kulkarni Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 28 +++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index a4dead4ab0ed..86b528d8364c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -695,10 +695,10 @@ static void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld) lld->write_cmpl_support = adap->params.write_cmpl_support; } -static void uld_attach(struct adapter *adap, unsigned int uld) +static int uld_attach(struct adapter *adap, unsigned int uld) { - void *handle; struct cxgb4_lld_info lli; + void *handle; uld_init(adap, &lli); uld_queue_init(adap, uld, &lli); @@ -708,7 +708,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) dev_warn(adap->pdev_dev, "could not attach to the %s driver, error %ld\n", adap->uld[uld].name, PTR_ERR(handle)); - return; + return PTR_ERR(handle); } adap->uld[uld].handle = handle; @@ -716,22 +716,22 @@ static void uld_attach(struct adapter *adap, unsigned int uld) if (adap->flags & CXGB4_FULL_INIT_DONE) adap->uld[uld].state_change(handle, CXGB4_STATE_UP); + + return 0; } -/** - * cxgb4_register_uld - register an upper-layer driver - * @type: the ULD type - * @p: the ULD methods +/* cxgb4_register_uld - register an upper-layer driver + * @type: the ULD type + * @p: the ULD methods * - * Registers an upper-layer driver with this driver and notifies the ULD - * about any presently available devices that support its type. Returns - * %-EBUSY if a ULD of the same type is already registered. + * Registers an upper-layer driver with this driver and notifies the ULD + * about any presently available devices that support its type. */ void cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p) { - int ret = 0; struct adapter *adap; + int ret = 0; if (type >= CXGB4_ULD_MAX) return; @@ -763,8 +763,12 @@ void cxgb4_register_uld(enum cxgb4_uld type, if (ret) goto free_irq; adap->uld[type] = *p; - uld_attach(adap, type); + ret = uld_attach(adap, type); + if (ret) + goto free_txq; continue; +free_txq: + release_sge_txq_uld(adap, type); free_irq: if (adap->flags & CXGB4_FULL_INIT_DONE) quiesce_rx_uld(adap, type); -- cgit v1.2.3-59-g8ed1b From 76c3a552e80ea47b7a9e4ba3f6e6af9659b23e7f Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:05 +0530 Subject: cxgb4: rework queue config and MSI-X allocation Simplify queue configuration and MSI-X allocation logic. Use a single MSI-X information table for both NIC and ULDs. Remove hard-coded MSI-X indices for firmware event queue and non data interrupts. Instead, use the MSI-X bitmap to obtain a free MSI-X index dynamically. Save each Rxq's index into the MSI-X information table, within the Rxq structures themselves, for easier cleanup. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 24 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 437 +++++++++++++++--------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 95 ++---- drivers/net/ethernet/chelsio/cxgb4/sge.c | 13 +- 4 files changed, 323 insertions(+), 246 deletions(-) (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index f2f643be7905..dbfde3fbfce4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -712,6 +712,7 @@ struct sge_eth_rxq { /* SW Ethernet Rx queue */ struct sge_rspq rspq; struct sge_fl fl; struct sge_eth_stats stats; + struct msix_info *msix; } ____cacheline_aligned_in_smp; struct sge_ofld_stats { /* offload queue statistics */ @@ -725,6 +726,7 @@ struct sge_ofld_rxq { /* SW offload Rx queue */ struct sge_rspq rspq; struct sge_fl fl; struct sge_ofld_stats stats; + struct msix_info *msix; } ____cacheline_aligned_in_smp; struct tx_desc { @@ -789,7 +791,6 @@ struct sge_ctrl_txq { /* state for an SGE control Tx queue */ struct sge_uld_rxq_info { char name[IFNAMSIZ]; /* name of ULD driver */ struct sge_ofld_rxq *uldrxq; /* Rxq's for ULD */ - u16 *msix_tbl; /* msix_tbl for uld */ u16 *rspq_id; /* response queue id's of rxq */ u16 nrxq; /* # of ingress uld queues */ u16 nciq; /* # of completion queues */ @@ -842,6 +843,9 @@ struct sge { unsigned long *blocked_fl; struct timer_list rx_timer; /* refills starving FLs */ struct timer_list tx_timer; /* checks Tx queues */ + + int fwevtq_msix_idx; /* Index to firmware event queue MSI-X info */ + int nd_msix_idx; /* Index to non-data interrupts MSI-X info */ }; #define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++) @@ -871,13 +875,13 @@ struct hash_mac_addr { unsigned int iface_mac; }; -struct uld_msix_bmap { +struct msix_bmap { unsigned long *msix_bmap; unsigned int mapsize; spinlock_t lock; /* lock for acquiring bitmap */ }; -struct uld_msix_info { +struct msix_info { unsigned short vec; char desc[IFNAMSIZ + 10]; unsigned int idx; @@ -946,14 +950,9 @@ struct adapter { struct cxgb4_virt_res vres; unsigned int swintr; - struct msix_info { - unsigned short vec; - char desc[IFNAMSIZ + 10]; - cpumask_var_t aff_mask; - } msix_info[MAX_INGQ + 1]; - struct uld_msix_info *msix_info_ulds; /* msix info for uld's */ - struct uld_msix_bmap msix_bmap_ulds; /* msix bitmap for all uld */ - int msi_idx; + /* MSI-X Info for NIC and OFLD queues */ + struct msix_info *msix_info; + struct msix_bmap msix_bmap; struct doorbell_stats db_stats; struct sge sge; @@ -1954,5 +1953,6 @@ int cxgb4_alloc_raw_mac_filt(struct adapter *adap, int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid, int *tcam_idx, const u8 *addr, bool persistent, u8 *smt_idx); - +int cxgb4_get_msix_idx_from_bmap(struct adapter *adap); +void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, u32 msix_idx); #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 20d1687adea2..d8a1bd80b293 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -685,31 +685,6 @@ static irqreturn_t t4_nondata_intr(int irq, void *cookie) return IRQ_HANDLED; } -/* - * Name the MSI-X interrupts. - */ -static void name_msix_vecs(struct adapter *adap) -{ - int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc); - - /* non-data interrupts */ - snprintf(adap->msix_info[0].desc, n, "%s", adap->port[0]->name); - - /* FW events */ - snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", - adap->port[0]->name); - - /* Ethernet queues */ - for_each_port(adap, j) { - struct net_device *d = adap->port[j]; - const struct port_info *pi = netdev_priv(d); - - for (i = 0; i < pi->nqsets; i++, msi_idx++) - snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d", - d->name, i); - } -} - int cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec, cpumask_var_t *aff_mask, int idx) { @@ -743,15 +718,19 @@ static int request_msix_queue_irqs(struct adapter *adap) struct sge *s = &adap->sge; struct msix_info *minfo; int err, ethqidx; - int msi_index = 2; - err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0, - adap->msix_info[1].desc, &s->fw_evtq); + if (s->fwevtq_msix_idx < 0) + return -ENOMEM; + + err = request_irq(adap->msix_info[s->fwevtq_msix_idx].vec, + t4_sge_intr_msix, 0, + adap->msix_info[s->fwevtq_msix_idx].desc, + &s->fw_evtq); if (err) return err; for_each_ethrxq(s, ethqidx) { - minfo = &adap->msix_info[msi_index]; + minfo = s->ethrxq[ethqidx].msix; err = request_irq(minfo->vec, t4_sge_intr_msix, 0, minfo->desc, @@ -761,18 +740,16 @@ static int request_msix_queue_irqs(struct adapter *adap) cxgb4_set_msix_aff(adap, minfo->vec, &minfo->aff_mask, ethqidx); - msi_index++; } return 0; unwind: while (--ethqidx >= 0) { - msi_index--; - minfo = &adap->msix_info[msi_index]; + minfo = s->ethrxq[ethqidx].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); free_irq(minfo->vec, &s->ethrxq[ethqidx].rspq); } - free_irq(adap->msix_info[1].vec, &s->fw_evtq); + free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); return err; } @@ -780,11 +757,11 @@ static void free_msix_queue_irqs(struct adapter *adap) { struct sge *s = &adap->sge; struct msix_info *minfo; - int i, msi_index = 2; + int i; - free_irq(adap->msix_info[1].vec, &s->fw_evtq); + free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); for_each_ethrxq(s, i) { - minfo = &adap->msix_info[msi_index++]; + minfo = s->ethrxq[i].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); free_irq(minfo->vec, &s->ethrxq[i].rspq); } @@ -919,11 +896,14 @@ static void quiesce_rx(struct adapter *adap) /* Disable interrupt and napi handler */ static void disable_interrupts(struct adapter *adap) { + struct sge *s = &adap->sge; + if (adap->flags & CXGB4_FULL_INIT_DONE) { t4_intr_disable(adap); if (adap->flags & CXGB4_USING_MSIX) { free_msix_queue_irqs(adap); - free_irq(adap->msix_info[0].vec, adap); + free_irq(adap->msix_info[s->nd_msix_idx].vec, + adap); } else { free_irq(adap->pdev->irq, adap); } @@ -953,27 +933,58 @@ static void enable_rx(struct adapter *adap) } } +static int setup_non_data_intr(struct adapter *adap) +{ + int msix; + + adap->sge.nd_msix_idx = -1; + if (!(adap->flags & CXGB4_USING_MSIX)) + return 0; + + /* Request MSI-X vector for non-data interrupt */ + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) + return -ENOMEM; + + snprintf(adap->msix_info[msix].desc, + sizeof(adap->msix_info[msix].desc), + "%s", adap->port[0]->name); + + adap->sge.nd_msix_idx = msix; + return 0; +} static int setup_fw_sge_queues(struct adapter *adap) { struct sge *s = &adap->sge; - int err = 0; + int msix, err = 0; bitmap_zero(s->starving_fl, s->egr_sz); bitmap_zero(s->txq_maperr, s->egr_sz); - if (adap->flags & CXGB4_USING_MSIX) - adap->msi_idx = 1; /* vector 0 is for non-queue interrupts */ - else { + if (adap->flags & CXGB4_USING_MSIX) { + s->fwevtq_msix_idx = -1; + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) + return -ENOMEM; + + snprintf(adap->msix_info[msix].desc, + sizeof(adap->msix_info[msix].desc), + "%s-FWeventq", adap->port[0]->name); + } else { err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, NULL, NULL, NULL, -1); if (err) return err; - adap->msi_idx = -((int)s->intrq.abs_id + 1); + msix = -((int)s->intrq.abs_id + 1); } err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], - adap->msi_idx, NULL, fwevtq_handler, NULL, -1); + msix, NULL, fwevtq_handler, NULL, -1); + if (err && msix >= 0) + cxgb4_free_msix_idx_in_bmap(adap, msix); + + s->fwevtq_msix_idx = msix; return err; } @@ -987,14 +998,17 @@ static int setup_fw_sge_queues(struct adapter *adap) */ static int setup_sge_queues(struct adapter *adap) { - int err, i, j; - struct sge *s = &adap->sge; struct sge_uld_rxq_info *rxq_info = NULL; + struct sge *s = &adap->sge; unsigned int cmplqid = 0; + int err, i, j, msix = 0; if (is_uld(adap)) rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; + if (!(adap->flags & CXGB4_USING_MSIX)) + msix = -((int)s->intrq.abs_id + 1); + for_each_port(adap, i) { struct net_device *dev = adap->port[i]; struct port_info *pi = netdev_priv(dev); @@ -1002,10 +1016,21 @@ static int setup_sge_queues(struct adapter *adap) struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; for (j = 0; j < pi->nqsets; j++, q++) { - if (adap->msi_idx > 0) - adap->msi_idx++; + if (msix >= 0) { + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) { + err = msix; + goto freeout; + } + + snprintf(adap->msix_info[msix].desc, + sizeof(adap->msix_info[msix].desc), + "%s-Rx%d", dev->name, j); + q->msix = &adap->msix_info[msix]; + } + err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, - adap->msi_idx, &q->fl, + msix, &q->fl, t4_ethrx_handler, NULL, t4_get_tp_ch_map(adap, @@ -2372,6 +2397,7 @@ static void update_clip(const struct adapter *adap) */ static int cxgb_up(struct adapter *adap) { + struct sge *s = &adap->sge; int err; mutex_lock(&uld_mutex); @@ -2383,16 +2409,20 @@ static int cxgb_up(struct adapter *adap) goto freeq; if (adap->flags & CXGB4_USING_MSIX) { - name_msix_vecs(adap); - err = request_irq(adap->msix_info[0].vec, t4_nondata_intr, 0, - adap->msix_info[0].desc, adap); + if (s->nd_msix_idx < 0) { + err = -ENOMEM; + goto irq_err; + } + + err = request_irq(adap->msix_info[s->nd_msix_idx].vec, + t4_nondata_intr, 0, + adap->msix_info[s->nd_msix_idx].desc, adap); if (err) goto irq_err; + err = request_msix_queue_irqs(adap); - if (err) { - free_irq(adap->msix_info[0].vec, adap); - goto irq_err; - } + if (err) + goto irq_err_free_nd_msix; } else { err = request_irq(adap->pdev->irq, t4_intr_handler(adap), (adap->flags & CXGB4_USING_MSI) ? 0 @@ -2414,11 +2444,13 @@ static int cxgb_up(struct adapter *adap) #endif return err; - irq_err: +irq_err_free_nd_msix: + free_irq(adap->msix_info[s->nd_msix_idx].vec, adap); +irq_err: dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); - freeq: +freeq: t4_free_sge_resources(adap); - rel_lock: +rel_lock: mutex_unlock(&uld_mutex); return err; } @@ -5187,26 +5219,25 @@ static inline bool is_x_10g_port(const struct link_config *lc) return high_speeds != 0; } -/* - * Perform default configuration of DMA queues depending on the number and type +/* Perform default configuration of DMA queues depending on the number and type * of ports we found and the number of available CPUs. Most settings can be * modified by the admin prior to actual use. */ static int cfg_queues(struct adapter *adap) { + u32 avail_qsets, avail_eth_qsets, avail_uld_qsets; + u32 niqflint, neq, num_ulds; struct sge *s = &adap->sge; - int i, n10g = 0, qidx = 0; - int niqflint, neq, avail_eth_qsets; - int max_eth_qsets = 32; + u32 i, n10g = 0, qidx = 0; #ifndef CONFIG_CHELSIO_T4_DCB int q10g = 0; #endif - /* Reduce memory usage in kdump environment, disable all offload. - */ + /* Reduce memory usage in kdump environment, disable all offload. */ if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { adap->params.offload = 0; adap->params.crypto = 0; + adap->params.ethofld = 0; } /* Calculate the number of Ethernet Queue Sets available based on @@ -5225,14 +5256,11 @@ static int cfg_queues(struct adapter *adap) if (!(adap->flags & CXGB4_USING_MSIX)) niqflint--; neq = adap->params.pfres.neq / 2; - avail_eth_qsets = min(niqflint, neq); + avail_qsets = min(niqflint, neq); - if (avail_eth_qsets > max_eth_qsets) - avail_eth_qsets = max_eth_qsets; - - if (avail_eth_qsets < adap->params.nports) { + if (avail_qsets < adap->params.nports) { dev_err(adap->pdev_dev, "avail_eth_qsets=%d < nports=%d\n", - avail_eth_qsets, adap->params.nports); + avail_qsets, adap->params.nports); return -ENOMEM; } @@ -5240,6 +5268,7 @@ static int cfg_queues(struct adapter *adap) for_each_port(adap, i) n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); + avail_eth_qsets = min_t(u32, avail_qsets, MAX_ETH_QSETS); #ifdef CONFIG_CHELSIO_T4_DCB /* For Data Center Bridging support we need to be able to support up * to 8 Traffic Priorities; each of which will be assigned to its @@ -5259,8 +5288,7 @@ static int cfg_queues(struct adapter *adap) qidx += pi->nqsets; } #else /* !CONFIG_CHELSIO_T4_DCB */ - /* - * We default to 1 queue per non-10G port and up to # of cores queues + /* We default to 1 queue per non-10G port and up to # of cores queues * per 10G port. */ if (n10g) @@ -5282,19 +5310,27 @@ static int cfg_queues(struct adapter *adap) s->ethqsets = qidx; s->max_ethqsets = qidx; /* MSI-X may lower it later */ + avail_qsets -= qidx; if (is_uld(adap)) { - /* - * For offload we use 1 queue/channel if all ports are up to 1G, + /* For offload we use 1 queue/channel if all ports are up to 1G, * otherwise we divide all available queues amongst the channels * capped by the number of available cores. */ - if (n10g) { - i = min_t(int, MAX_OFLD_QSETS, num_online_cpus()); - s->ofldqsets = roundup(i, adap->params.nports); - } else { + num_ulds = adap->num_uld + adap->num_ofld_uld; + i = min_t(u32, MAX_OFLD_QSETS, num_online_cpus()); + avail_uld_qsets = roundup(i, adap->params.nports); + if (avail_qsets < num_ulds * adap->params.nports) { + adap->params.offload = 0; + adap->params.crypto = 0; + s->ofldqsets = 0; + } else if (avail_qsets < num_ulds * avail_uld_qsets || !n10g) { s->ofldqsets = adap->params.nports; + } else { + s->ofldqsets = avail_uld_qsets; } + + avail_qsets -= num_ulds * s->ofldqsets; } for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { @@ -5347,42 +5383,62 @@ static void reduce_ethqs(struct adapter *adap, int n) } } -static int get_msix_info(struct adapter *adap) +static int alloc_msix_info(struct adapter *adap, u32 num_vec) { - struct uld_msix_info *msix_info; - unsigned int max_ingq = 0; - - if (is_offload(adap)) - max_ingq += MAX_OFLD_QSETS * adap->num_ofld_uld; - if (is_pci_uld(adap)) - max_ingq += MAX_OFLD_QSETS * adap->num_uld; - - if (!max_ingq) - goto out; + struct msix_info *msix_info; - msix_info = kcalloc(max_ingq, sizeof(*msix_info), GFP_KERNEL); + msix_info = kcalloc(num_vec, sizeof(*msix_info), GFP_KERNEL); if (!msix_info) return -ENOMEM; - adap->msix_bmap_ulds.msix_bmap = kcalloc(BITS_TO_LONGS(max_ingq), - sizeof(long), GFP_KERNEL); - if (!adap->msix_bmap_ulds.msix_bmap) { + adap->msix_bmap.msix_bmap = kcalloc(BITS_TO_LONGS(num_vec), + sizeof(long), GFP_KERNEL); + if (!adap->msix_bmap.msix_bmap) { kfree(msix_info); return -ENOMEM; } - spin_lock_init(&adap->msix_bmap_ulds.lock); - adap->msix_info_ulds = msix_info; -out: + + spin_lock_init(&adap->msix_bmap.lock); + adap->msix_bmap.mapsize = num_vec; + + adap->msix_info = msix_info; return 0; } static void free_msix_info(struct adapter *adap) { - if (!(adap->num_uld && adap->num_ofld_uld)) - return; + kfree(adap->msix_bmap.msix_bmap); + kfree(adap->msix_info); +} + +int cxgb4_get_msix_idx_from_bmap(struct adapter *adap) +{ + struct msix_bmap *bmap = &adap->msix_bmap; + unsigned int msix_idx; + unsigned long flags; - kfree(adap->msix_info_ulds); - kfree(adap->msix_bmap_ulds.msix_bmap); + spin_lock_irqsave(&bmap->lock, flags); + msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize); + if (msix_idx < bmap->mapsize) { + __set_bit(msix_idx, bmap->msix_bmap); + } else { + spin_unlock_irqrestore(&bmap->lock, flags); + return -ENOSPC; + } + + spin_unlock_irqrestore(&bmap->lock, flags); + return msix_idx; +} + +void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, + unsigned int msix_idx) +{ + struct msix_bmap *bmap = &adap->msix_bmap; + unsigned long flags; + + spin_lock_irqsave(&bmap->lock, flags); + __clear_bit(msix_idx, bmap->msix_bmap); + spin_unlock_irqrestore(&bmap->lock, flags); } /* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ @@ -5390,88 +5446,142 @@ static void free_msix_info(struct adapter *adap) static int enable_msix(struct adapter *adap) { - int ofld_need = 0, uld_need = 0; - int i, j, want, need, allocated; + u8 num_uld = 0, nchan = adap->params.nports; + u32 ethqsets = 0, ofldqsets = 0; + u32 eth_need, uld_need = 0; + u32 i, want, need, num_vec; struct sge *s = &adap->sge; - unsigned int nchan = adap->params.nports; struct msix_entry *entries; - int max_ingq = MAX_INGQ; - - if (is_pci_uld(adap)) - max_ingq += (MAX_OFLD_QSETS * adap->num_uld); - if (is_offload(adap)) - max_ingq += (MAX_OFLD_QSETS * adap->num_ofld_uld); - entries = kmalloc_array(max_ingq + 1, sizeof(*entries), - GFP_KERNEL); - if (!entries) - return -ENOMEM; - - /* map for msix */ - if (get_msix_info(adap)) { - adap->params.offload = 0; - adap->params.crypto = 0; - } - - for (i = 0; i < max_ingq + 1; ++i) - entries[i].entry = i; + struct port_info *pi; + int allocated, ret; - want = s->max_ethqsets + EXTRA_VECS; - if (is_offload(adap)) { - want += adap->num_ofld_uld * s->ofldqsets; - ofld_need = adap->num_ofld_uld * nchan; - } - if (is_pci_uld(adap)) { - want += adap->num_uld * s->ofldqsets; - uld_need = adap->num_uld * nchan; - } + want = s->max_ethqsets; #ifdef CONFIG_CHELSIO_T4_DCB /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for * each port. */ - need = 8 * adap->params.nports + EXTRA_VECS + ofld_need + uld_need; + need = 8 * nchan; #else - need = adap->params.nports + EXTRA_VECS + ofld_need + uld_need; + need = nchan; #endif + eth_need = need; + if (is_uld(adap)) { + num_uld = adap->num_ofld_uld + adap->num_uld; + want += num_uld * s->ofldqsets; + uld_need = num_uld * nchan; + need += uld_need; + } + + want += EXTRA_VECS; + need += EXTRA_VECS; + + entries = kmalloc_array(want, sizeof(*entries), GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < want; i++) + entries[i].entry = i; + allocated = pci_enable_msix_range(adap->pdev, entries, need, want); if (allocated < 0) { - dev_info(adap->pdev_dev, "not enough MSI-X vectors left," - " not using MSI-X\n"); - kfree(entries); - return allocated; + /* Disable offload and attempt to get vectors for NIC + * only mode. + */ + want = s->max_ethqsets + EXTRA_VECS; + need = eth_need + EXTRA_VECS; + allocated = pci_enable_msix_range(adap->pdev, entries, + need, want); + if (allocated < 0) { + dev_info(adap->pdev_dev, + "Disabling MSI-X due to insufficient MSI-X vectors\n"); + ret = allocated; + goto out_free; + } + + dev_info(adap->pdev_dev, + "Disabling offload due to insufficient MSI-X vectors\n"); + adap->params.offload = 0; + adap->params.crypto = 0; + adap->params.ethofld = 0; + s->ofldqsets = 0; + uld_need = 0; } - /* Distribute available vectors to the various queue groups. - * Every group gets its minimum requirement and NIC gets top - * priority for leftovers. - */ - i = allocated - EXTRA_VECS - ofld_need - uld_need; - if (i < s->max_ethqsets) { - s->max_ethqsets = i; - if (i < s->ethqsets) - reduce_ethqs(adap, i); + num_vec = allocated; + if (num_vec < want) { + /* Distribute available vectors to the various queue groups. + * Every group gets its minimum requirement and NIC gets top + * priority for leftovers. + */ + ethqsets = eth_need; + if (is_uld(adap)) + ofldqsets = nchan; + + num_vec -= need; + while (num_vec) { + if (num_vec < eth_need || + ethqsets > s->max_ethqsets) + break; + + for_each_port(adap, i) { + pi = adap2pinfo(adap, i); + if (pi->nqsets < 2) + continue; + + ethqsets++; + num_vec--; + } + } + + if (is_uld(adap)) { + while (num_vec) { + if (num_vec < uld_need || + ofldqsets > s->ofldqsets) + break; + + ofldqsets++; + num_vec -= uld_need; + } + } + } else { + ethqsets = s->max_ethqsets; + if (is_uld(adap)) + ofldqsets = s->ofldqsets; + } + + if (ethqsets < s->max_ethqsets) { + s->max_ethqsets = ethqsets; + reduce_ethqs(adap, ethqsets); } + if (is_uld(adap)) { - if (allocated < want) - s->nqs_per_uld = nchan; - else - s->nqs_per_uld = s->ofldqsets; + s->ofldqsets = ofldqsets; + s->nqs_per_uld = s->ofldqsets; } - for (i = 0; i < (s->max_ethqsets + EXTRA_VECS); ++i) + /* map for msix */ + ret = alloc_msix_info(adap, allocated); + if (ret) + goto out_disable_msix; + + for (i = 0; i < allocated; i++) { adap->msix_info[i].vec = entries[i].vector; - if (is_uld(adap)) { - for (j = 0 ; i < allocated; ++i, j++) { - adap->msix_info_ulds[j].vec = entries[i].vector; - adap->msix_info_ulds[j].idx = i; - } - adap->msix_bmap_ulds.mapsize = j; + adap->msix_info[i].idx = i; } - dev_info(adap->pdev_dev, "%d MSI-X vectors allocated, " - "nic %d per uld %d\n", + + dev_info(adap->pdev_dev, + "%d MSI-X vectors allocated, nic %d per uld %d\n", allocated, s->max_ethqsets, s->nqs_per_uld); kfree(entries); return 0; + +out_disable_msix: + pci_disable_msix(adap->pdev); + +out_free: + kfree(entries); + return ret; } #undef EXTRA_VECS @@ -6163,6 +6273,13 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free_dev; + err = setup_non_data_intr(adapter); + if (err) { + dev_err(adapter->pdev_dev, + "Non Data interrupt allocation failed, err: %d\n", err); + goto out_free_dev; + } + err = setup_fw_sge_queues(adapter); if (err) { dev_err(adapter->pdev_dev, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 86b528d8364c..3d9401354af2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -53,35 +53,6 @@ #define for_each_uldrxq(m, i) for (i = 0; i < ((m)->nrxq + (m)->nciq); i++) -static int get_msix_idx_from_bmap(struct adapter *adap) -{ - struct uld_msix_bmap *bmap = &adap->msix_bmap_ulds; - unsigned long flags; - unsigned int msix_idx; - - spin_lock_irqsave(&bmap->lock, flags); - msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize); - if (msix_idx < bmap->mapsize) { - __set_bit(msix_idx, bmap->msix_bmap); - } else { - spin_unlock_irqrestore(&bmap->lock, flags); - return -ENOSPC; - } - - spin_unlock_irqrestore(&bmap->lock, flags); - return msix_idx; -} - -static void free_msix_idx_in_bmap(struct adapter *adap, unsigned int msix_idx) -{ - struct uld_msix_bmap *bmap = &adap->msix_bmap_ulds; - unsigned long flags; - - spin_lock_irqsave(&bmap->lock, flags); - __clear_bit(msix_idx, bmap->msix_bmap); - spin_unlock_irqrestore(&bmap->lock, flags); -} - /* Flush the aggregated lro sessions */ static void uldrx_flush_handler(struct sge_rspq *q) { @@ -138,9 +109,9 @@ static int alloc_uld_rxqs(struct adapter *adap, struct sge_uld_rxq_info *rxq_info, bool lro) { unsigned int nq = rxq_info->nrxq + rxq_info->nciq; - int i, err, msi_idx, que_idx = 0, bmap_idx = 0; struct sge_ofld_rxq *q = rxq_info->uldrxq; unsigned short *ids = rxq_info->rspq_id; + int i, err, msi_idx, que_idx = 0; struct sge *s = &adap->sge; unsigned int per_chan; @@ -159,12 +130,18 @@ static int alloc_uld_rxqs(struct adapter *adap, } if (msi_idx >= 0) { - bmap_idx = get_msix_idx_from_bmap(adap); - if (bmap_idx < 0) { + msi_idx = cxgb4_get_msix_idx_from_bmap(adap); + if (msi_idx < 0) { err = -ENOSPC; goto freeout; } - msi_idx = adap->msix_info_ulds[bmap_idx].idx; + + snprintf(adap->msix_info[msi_idx].desc, + sizeof(adap->msix_info[msi_idx].desc), + "%s-%s%d", + adap->port[0]->name, rxq_info->name, i); + + q->msix = &adap->msix_info[msi_idx]; } err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[que_idx++ / per_chan], @@ -175,8 +152,7 @@ static int alloc_uld_rxqs(struct adapter *adap, 0); if (err) goto freeout; - if (msi_idx >= 0) - rxq_info->msix_tbl[i] = bmap_idx; + memset(&q->stats, 0, sizeof(q->stats)); if (ids) ids[i] = q->rspq.abs_id; @@ -188,6 +164,8 @@ freeout: if (q->rspq.desc) free_rspq_fl(adap, &q->rspq, q->fl.size ? &q->fl : NULL); + if (q->msix) + cxgb4_free_msix_idx_in_bmap(adap, q->msix->idx); } return err; } @@ -198,14 +176,6 @@ setup_sge_queues_uld(struct adapter *adap, unsigned int uld_type, bool lro) struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; int i, ret = 0; - if (adap->flags & CXGB4_USING_MSIX) { - rxq_info->msix_tbl = kcalloc((rxq_info->nrxq + rxq_info->nciq), - sizeof(unsigned short), - GFP_KERNEL); - if (!rxq_info->msix_tbl) - return -ENOMEM; - } - ret = !(!alloc_uld_rxqs(adap, rxq_info, lro)); /* Tell uP to route control queue completions to rdma rspq */ @@ -261,8 +231,6 @@ static void free_sge_queues_uld(struct adapter *adap, unsigned int uld_type) t4_free_uld_rxqs(adap, rxq_info->nciq, rxq_info->uldrxq + rxq_info->nrxq); t4_free_uld_rxqs(adap, rxq_info->nrxq, rxq_info->uldrxq); - if (adap->flags & CXGB4_USING_MSIX) - kfree(rxq_info->msix_tbl); } static int cfg_queues_uld(struct adapter *adap, unsigned int uld_type, @@ -355,13 +323,12 @@ static int request_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; - struct uld_msix_info *minfo; + struct msix_info *minfo; + unsigned int idx; int err = 0; - unsigned int idx, bmap_idx; for_each_uldrxq(rxq_info, idx) { - bmap_idx = rxq_info->msix_tbl[idx]; - minfo = &adap->msix_info_ulds[bmap_idx]; + minfo = rxq_info->uldrxq[idx].msix; err = request_irq(minfo->vec, t4_sge_intr_msix, 0, minfo->desc, @@ -376,10 +343,9 @@ request_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) unwind: while (idx-- > 0) { - bmap_idx = rxq_info->msix_tbl[idx]; - minfo = &adap->msix_info_ulds[bmap_idx]; + minfo = rxq_info->uldrxq[idx].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); - free_msix_idx_in_bmap(adap, bmap_idx); + cxgb4_free_msix_idx_in_bmap(adap, minfo->idx); free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq); } return err; @@ -389,33 +355,17 @@ static void free_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; - struct uld_msix_info *minfo; - unsigned int idx, bmap_idx; + struct msix_info *minfo; + unsigned int idx; for_each_uldrxq(rxq_info, idx) { - bmap_idx = rxq_info->msix_tbl[idx]; - minfo = &adap->msix_info_ulds[bmap_idx]; - + minfo = rxq_info->uldrxq[idx].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); - free_msix_idx_in_bmap(adap, bmap_idx); + cxgb4_free_msix_idx_in_bmap(adap, minfo->idx); free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq); } } -static void name_msix_vecs_uld(struct adapter *adap, unsigned int uld_type) -{ - struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; - int n = sizeof(adap->msix_info_ulds[0].desc); - unsigned int idx, bmap_idx; - - for_each_uldrxq(rxq_info, idx) { - bmap_idx = rxq_info->msix_tbl[idx]; - - snprintf(adap->msix_info_ulds[bmap_idx].desc, n, "%s-%s%d", - adap->port[0]->name, rxq_info->name, idx); - } -} - static void enable_rx(struct adapter *adap, struct sge_rspq *q) { if (!q) @@ -750,7 +700,6 @@ void cxgb4_register_uld(enum cxgb4_uld type, if (ret) goto free_queues; if (adap->flags & CXGB4_USING_MSIX) { - name_msix_vecs_uld(adap, type); ret = request_msix_queue_irqs_uld(adap, type); if (ret) goto free_rxq; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 928bfea5457b..82d8e13fc7d2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -4060,6 +4060,10 @@ void t4_free_sge_resources(struct adapter *adap) if (eq->rspq.desc) free_rspq_fl(adap, &eq->rspq, eq->fl.size ? &eq->fl : NULL); + if (eq->msix) { + cxgb4_free_msix_idx_in_bmap(adap, eq->msix->idx); + eq->msix = NULL; + } etq = &adap->sge.ethtxq[i]; if (etq->q.desc) { @@ -4086,8 +4090,15 @@ void t4_free_sge_resources(struct adapter *adap) } } - if (adap->sge.fw_evtq.desc) + if (adap->sge.fw_evtq.desc) { free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); + if (adap->sge.fwevtq_msix_idx >= 0) + cxgb4_free_msix_idx_in_bmap(adap, + adap->sge.fwevtq_msix_idx); + } + + if (adap->sge.nd_msix_idx >= 0) + cxgb4_free_msix_idx_in_bmap(adap, adap->sge.nd_msix_idx); if (adap->sge.intrq.desc) free_rspq_fl(adap, &adap->sge.intrq, NULL); -- cgit v1.2.3-59-g8ed1b From 2d0cb84dd9731d5d0e1326f0e10be893cb2fe698 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:07 +0530 Subject: cxgb4: add ETHOFLD hardware queue support Add support for configuring and managing ETHOFLD hardware queues. Keep the queue count and MSI-X allocation scheme same as NIC queues. ETHOFLD hardware queues are dynamically allocated/destroyed as TC-MQPRIO Qdisc offload is enabled/disabled on the corresponding interface, respectively. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 3 + drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 21 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 20 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 53 ++++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 72 +++++++-- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 168 +++++++++++++++++++++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h | 10 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 40 ++--- drivers/net/ethernet/chelsio/cxgb4/sge.c | 95 +++++++++--- 9 files changed, 419 insertions(+), 63 deletions(-) (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h index 69746696a929..f5be3ee1bdb4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h @@ -325,6 +325,9 @@ enum cudbg_qdesc_qtype { CUDBG_QTYPE_CRYPTO_FLQ, CUDBG_QTYPE_TLS_RXQ, CUDBG_QTYPE_TLS_FLQ, + CUDBG_QTYPE_ETHOFLD_TXQ, + CUDBG_QTYPE_ETHOFLD_RXQ, + CUDBG_QTYPE_ETHOFLD_FLQ, CUDBG_QTYPE_MAX, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index c2e92786608b..c9d3dea4413e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -2930,6 +2930,10 @@ void cudbg_fill_qdesc_num_and_size(const struct adapter *padap, tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * SGE_MAX_IQ_SIZE * MAX_RXQ_DESC_SIZE; + /* ETHOFLD TXQ, RXQ, and FLQ */ + tot_entries += MAX_OFLD_QSETS * 3; + tot_size += MAX_OFLD_QSETS * MAX_TXQ_ENTRIES * MAX_TXQ_DESC_SIZE; + tot_size += sizeof(struct cudbg_ver_hdr) + sizeof(struct cudbg_qdesc_info) + sizeof(struct cudbg_qdesc_entry) * tot_entries; @@ -3087,6 +3091,23 @@ int cudbg_collect_qdesc(struct cudbg_init *pdbg_init, } } + /* ETHOFLD TXQ */ + if (s->eohw_txq) + for (i = 0; i < s->eoqsets; i++) + QDESC_GET_TXQ(&s->eohw_txq[i].q, + CUDBG_QTYPE_ETHOFLD_TXQ, out); + + /* ETHOFLD RXQ and FLQ */ + if (s->eohw_rxq) { + for (i = 0; i < s->eoqsets; i++) + QDESC_GET_RXQ(&s->eohw_rxq[i].rspq, + CUDBG_QTYPE_ETHOFLD_RXQ, out); + + for (i = 0; i < s->eoqsets; i++) + QDESC_GET_FLQ(&s->eohw_rxq[i].fl, + CUDBG_QTYPE_ETHOFLD_FLQ, out); + } + out_unlock: mutex_unlock(&uld_mutex); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 04a81276e9c8..d9d92dc0d0c5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -835,6 +835,16 @@ struct sge_eosw_txq { struct tasklet_struct qresume_tsk; /* Restarts the queue */ }; +struct sge_eohw_txq { + spinlock_t lock; /* Per queue lock */ + struct sge_txq q; /* HW Txq */ + struct adapter *adap; /* Backpointer to adapter */ + unsigned long tso; /* # of TSO requests */ + unsigned long tx_cso; /* # of Tx checksum offloads */ + unsigned long vlan_ins; /* # of Tx VLAN insertions */ + unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ +}; + struct sge { struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; struct sge_eth_txq ptptxq; @@ -848,11 +858,16 @@ struct sge { struct sge_rspq intrq ____cacheline_aligned_in_smp; spinlock_t intrq_lock; + struct sge_eohw_txq *eohw_txq; + struct sge_ofld_rxq *eohw_rxq; + u16 max_ethqsets; /* # of available Ethernet queue sets */ u16 ethqsets; /* # of active Ethernet queue sets */ u16 ethtxq_rover; /* Tx queue to clean up next */ u16 ofldqsets; /* # of active ofld queue sets */ u16 nqs_per_uld; /* # of Rx queues per ULD */ + u16 eoqsets; /* # of ETHOFLD queues */ + u16 timer_val[SGE_NTIMERS]; u8 counter_val[SGE_NCOUNTERS]; u16 dbqtimer_tick; @@ -1466,6 +1481,9 @@ int t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid, int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, struct net_device *dev, unsigned int iqid, unsigned int uld_type); +int t4_sge_alloc_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq, + struct net_device *dev, u32 iqid); +void t4_sge_free_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq); irqreturn_t t4_sge_intr_msix(int irq, void *cookie); int t4_sge_init(struct adapter *adap); void t4_sge_start(struct adapter *adap); @@ -1995,4 +2013,6 @@ int cxgb4_get_msix_idx_from_bmap(struct adapter *adap); void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, u32 msix_idx); int cxgb_open(struct net_device *dev); int cxgb_close(struct net_device *dev); +void cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q); +void cxgb4_quiesce_rx(struct sge_rspq *q); #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index ae6a47dd7dc9..a13b03f771cc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2658,6 +2658,7 @@ static int sge_qinfo_uld_ciq_entries(const struct adapter *adap, int uld) static int sge_qinfo_show(struct seq_file *seq, void *v) { + int eth_entries, ctrl_entries, eo_entries = 0; int uld_rxq_entries[CXGB4_ULD_MAX] = { 0 }; int uld_ciq_entries[CXGB4_ULD_MAX] = { 0 }; int uld_txq_entries[CXGB4_TX_MAX] = { 0 }; @@ -2665,11 +2666,12 @@ static int sge_qinfo_show(struct seq_file *seq, void *v) const struct sge_uld_rxq_info *urxq_info; struct adapter *adap = seq->private; int i, n, r = (uintptr_t)v - 1; - int eth_entries, ctrl_entries; struct sge *s = &adap->sge; eth_entries = DIV_ROUND_UP(adap->sge.ethqsets, 4); ctrl_entries = DIV_ROUND_UP(MAX_CTRL_QUEUES, 4); + if (adap->sge.eohw_txq) + eo_entries = DIV_ROUND_UP(adap->sge.eoqsets, 4); mutex_lock(&uld_mutex); if (s->uld_txq_info) @@ -2761,6 +2763,54 @@ do { \ } r -= eth_entries; + if (r < eo_entries) { + int base_qset = r * 4; + const struct sge_ofld_rxq *rx = &s->eohw_rxq[base_qset]; + const struct sge_eohw_txq *tx = &s->eohw_txq[base_qset]; + + n = min(4, s->eoqsets - 4 * r); + + S("QType:", "ETHOFLD"); + S("Interface:", + rx[i].rspq.netdev ? rx[i].rspq.netdev->name : "N/A"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", s->counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + S3("u", "FL size:", rx->fl.size ? rx->fl.size - 8 : 0); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + RL("RxPackets:", stats.pkts); + RL("RxImm:", stats.imm); + RL("RxAN", stats.an); + RL("RxNoMem", stats.nomem); + TL("TSO:", tso); + TL("TxCSO:", tx_cso); + TL("VLANins:", vlan_ins); + TL("TxQFull:", q.stops); + TL("TxQRestarts:", q.restarts); + TL("TxMapErr:", mapping_err); + RL("FLAllocErr:", fl.alloc_failed); + RL("FLLrgAlcErr:", fl.large_alloc_failed); + RL("FLMapErr:", fl.mapping_err); + RL("FLLow:", fl.low); + RL("FLStarving:", fl.starving); + + goto unlock; + } + + r -= eo_entries; if (r < uld_txq_entries[CXGB4_TX_OFLD]) { const struct sge_uld_txq *tx; @@ -3007,6 +3057,7 @@ static int sge_queue_entries(const struct adapter *adap) mutex_unlock(&uld_mutex); return DIV_ROUND_UP(adap->sge.ethqsets, 4) + + (adap->sge.eohw_txq ? DIV_ROUND_UP(adap->sge.eoqsets, 4) : 0) + tot_uld_entries + DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index fe3ea60843c3..b5148c57e8bf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -880,6 +880,12 @@ static unsigned int rxq_to_chan(const struct sge *p, unsigned int qid) return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan; } +void cxgb4_quiesce_rx(struct sge_rspq *q) +{ + if (q->handler) + napi_disable(&q->napi); +} + /* * Wait until all NAPI handlers are descheduled. */ @@ -890,8 +896,10 @@ static void quiesce_rx(struct adapter *adap) for (i = 0; i < adap->sge.ingr_sz; i++) { struct sge_rspq *q = adap->sge.ingr_map[i]; - if (q && q->handler) - napi_disable(&q->napi); + if (!q) + continue; + + cxgb4_quiesce_rx(q); } } @@ -913,6 +921,17 @@ static void disable_interrupts(struct adapter *adap) } } +void cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q) +{ + if (q->handler) + napi_enable(&q->napi); + + /* 0-increment GTS to start the timer and enable interrupts */ + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), + SEINTARM_V(q->intr_params) | + INGRESSQID_V(q->cntxt_id)); +} + /* * Enable NAPI scheduling and interrupt generation for all Rx queues. */ @@ -925,13 +944,8 @@ static void enable_rx(struct adapter *adap) if (!q) continue; - if (q->handler) - napi_enable(&q->napi); - /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), - SEINTARM_V(q->intr_params) | - INGRESSQID_V(q->cntxt_id)); + cxgb4_enable_rx(adap, q); } } @@ -5360,6 +5374,19 @@ static int cfg_queues(struct adapter *adap) avail_qsets -= num_ulds * s->ofldqsets; } + /* ETHOFLD Queues used for QoS offload should follow same + * allocation scheme as normal Ethernet Queues. + */ + if (is_ethofld(adap)) { + if (avail_qsets < s->max_ethqsets) { + adap->params.ethofld = 0; + s->eoqsets = 0; + } else { + s->eoqsets = s->max_ethqsets; + } + avail_qsets -= s->eoqsets; + } + for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { struct sge_eth_rxq *r = &s->ethrxq[i]; @@ -5473,9 +5500,9 @@ void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, static int enable_msix(struct adapter *adap) { + u32 eth_need, uld_need = 0, ethofld_need = 0; + u32 ethqsets = 0, ofldqsets = 0, eoqsets = 0; u8 num_uld = 0, nchan = adap->params.nports; - u32 ethqsets = 0, ofldqsets = 0; - u32 eth_need, uld_need = 0; u32 i, want, need, num_vec; struct sge *s = &adap->sge; struct msix_entry *entries; @@ -5499,6 +5526,12 @@ static int enable_msix(struct adapter *adap) need += uld_need; } + if (is_ethofld(adap)) { + want += s->eoqsets; + ethofld_need = eth_need; + need += ethofld_need; + } + want += EXTRA_VECS; need += EXTRA_VECS; @@ -5531,7 +5564,9 @@ static int enable_msix(struct adapter *adap) adap->params.crypto = 0; adap->params.ethofld = 0; s->ofldqsets = 0; + s->eoqsets = 0; uld_need = 0; + ethofld_need = 0; } num_vec = allocated; @@ -5543,10 +5578,12 @@ static int enable_msix(struct adapter *adap) ethqsets = eth_need; if (is_uld(adap)) ofldqsets = nchan; + if (is_ethofld(adap)) + eoqsets = ethofld_need; num_vec -= need; while (num_vec) { - if (num_vec < eth_need || + if (num_vec < eth_need + ethofld_need || ethqsets > s->max_ethqsets) break; @@ -5557,6 +5594,10 @@ static int enable_msix(struct adapter *adap) ethqsets++; num_vec--; + if (ethofld_need) { + eoqsets++; + num_vec--; + } } } @@ -5574,6 +5615,8 @@ static int enable_msix(struct adapter *adap) ethqsets = s->max_ethqsets; if (is_uld(adap)) ofldqsets = s->ofldqsets; + if (is_ethofld(adap)) + eoqsets = s->eoqsets; } if (ethqsets < s->max_ethqsets) { @@ -5586,6 +5629,9 @@ static int enable_msix(struct adapter *adap) s->nqs_per_uld = s->ofldqsets; } + if (is_ethofld(adap)) + s->eoqsets = eoqsets; + /* map for msix */ ret = alloc_msix_info(adap, allocated); if (ret) @@ -5597,8 +5643,8 @@ static int enable_msix(struct adapter *adap) } dev_info(adap->pdev_dev, - "%d MSI-X vectors allocated, nic %d per uld %d\n", - allocated, s->max_ethqsets, s->nqs_per_uld); + "%d MSI-X vectors allocated, nic %d eoqsets %d per uld %d\n", + allocated, s->max_ethqsets, s->eoqsets, s->nqs_per_uld); kfree(entries); return 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index 8cdf3dc1da16..66503ea259e7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -120,6 +120,166 @@ static void cxgb4_free_eosw_txq(struct net_device *dev, tasklet_kill(&eosw_txq->qresume_tsk); } +static int cxgb4_mqprio_alloc_hw_resources(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_ofld_rxq *eorxq; + struct sge_eohw_txq *eotxq; + int ret, msix = 0; + u32 i; + + /* Allocate ETHOFLD hardware queue structures if not done already */ + if (!refcount_read(&adap->tc_mqprio->refcnt)) { + adap->sge.eohw_rxq = kcalloc(adap->sge.eoqsets, + sizeof(struct sge_ofld_rxq), + GFP_KERNEL); + if (!adap->sge.eohw_rxq) + return -ENOMEM; + + adap->sge.eohw_txq = kcalloc(adap->sge.eoqsets, + sizeof(struct sge_eohw_txq), + GFP_KERNEL); + if (!adap->sge.eohw_txq) { + kfree(adap->sge.eohw_rxq); + return -ENOMEM; + } + } + + if (!(adap->flags & CXGB4_USING_MSIX)) + msix = -((int)adap->sge.intrq.abs_id + 1); + + for (i = 0; i < pi->nqsets; i++) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + eotxq = &adap->sge.eohw_txq[pi->first_qset + i]; + + /* Allocate Rxqs for receiving ETHOFLD Tx completions */ + if (msix >= 0) { + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) + goto out_free_queues; + + eorxq->msix = &adap->msix_info[msix]; + snprintf(eorxq->msix->desc, + sizeof(eorxq->msix->desc), + "%s-eorxq%d", dev->name, i); + } + + init_rspq(adap, &eorxq->rspq, + CXGB4_EOHW_RXQ_DEFAULT_INTR_USEC, + CXGB4_EOHW_RXQ_DEFAULT_PKT_CNT, + CXGB4_EOHW_RXQ_DEFAULT_DESC_NUM, + CXGB4_EOHW_RXQ_DEFAULT_DESC_SIZE); + + eorxq->fl.size = CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM; + + ret = t4_sge_alloc_rxq(adap, &eorxq->rspq, false, + dev, msix, &eorxq->fl, NULL, + NULL, 0); + if (ret) + goto out_free_queues; + + /* Allocate ETHOFLD hardware Txqs */ + eotxq->q.size = CXGB4_EOHW_TXQ_DEFAULT_DESC_NUM; + ret = t4_sge_alloc_ethofld_txq(adap, eotxq, dev, + eorxq->rspq.cntxt_id); + if (ret) + goto out_free_queues; + + /* Allocate IRQs, set IRQ affinity, and start Rx */ + if (adap->flags & CXGB4_USING_MSIX) { + ret = request_irq(eorxq->msix->vec, t4_sge_intr_msix, 0, + eorxq->msix->desc, &eorxq->rspq); + if (ret) + goto out_free_msix; + + cxgb4_set_msix_aff(adap, eorxq->msix->vec, + &eorxq->msix->aff_mask, i); + } + + if (adap->flags & CXGB4_FULL_INIT_DONE) + cxgb4_enable_rx(adap, &eorxq->rspq); + } + + refcount_inc(&adap->tc_mqprio->refcnt); + return 0; + +out_free_msix: + while (i-- > 0) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + + if (adap->flags & CXGB4_FULL_INIT_DONE) + cxgb4_quiesce_rx(&eorxq->rspq); + + if (adap->flags & CXGB4_USING_MSIX) { + cxgb4_clear_msix_aff(eorxq->msix->vec, + eorxq->msix->aff_mask); + free_irq(eorxq->msix->vec, &eorxq->rspq); + } + } + +out_free_queues: + for (i = 0; i < pi->nqsets; i++) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + eotxq = &adap->sge.eohw_txq[pi->first_qset + i]; + + if (eorxq->rspq.desc) + free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl); + if (eorxq->msix) + cxgb4_free_msix_idx_in_bmap(adap, eorxq->msix->idx); + t4_sge_free_ethofld_txq(adap, eotxq); + } + + kfree(adap->sge.eohw_txq); + kfree(adap->sge.eohw_rxq); + + return ret; +} + +void cxgb4_mqprio_free_hw_resources(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_ofld_rxq *eorxq; + struct sge_eohw_txq *eotxq; + u32 i; + + /* Return if no ETHOFLD structures have been allocated yet */ + if (!refcount_read(&adap->tc_mqprio->refcnt)) + return; + + /* Return if no hardware queues have been allocated */ + if (!adap->sge.eohw_rxq[pi->first_qset].rspq.desc) + return; + + for (i = 0; i < pi->nqsets; i++) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + eotxq = &adap->sge.eohw_txq[pi->first_qset + i]; + + /* Device removal path will already disable NAPI + * before unregistering netdevice. So, only disable + * NAPI if we're not in device removal path + */ + if (!(adap->flags & CXGB4_SHUTTING_DOWN)) + cxgb4_quiesce_rx(&eorxq->rspq); + + if (adap->flags & CXGB4_USING_MSIX) { + cxgb4_clear_msix_aff(eorxq->msix->vec, + eorxq->msix->aff_mask); + free_irq(eorxq->msix->vec, &eorxq->rspq); + } + + free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl); + t4_sge_free_ethofld_txq(adap, eotxq); + } + + /* Free up ETHOFLD structures if there are no users */ + if (refcount_dec_and_test(&adap->tc_mqprio->refcnt)) { + kfree(adap->sge.eohw_txq); + kfree(adap->sge.eohw_rxq); + } +} + static int cxgb4_mqprio_enable_offload(struct net_device *dev, struct tc_mqprio_qopt_offload *mqprio) { @@ -131,6 +291,10 @@ static int cxgb4_mqprio_enable_offload(struct net_device *dev, int eotid, ret; u16 i, j; + ret = cxgb4_mqprio_alloc_hw_resources(dev); + if (ret) + return -ENOMEM; + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; for (i = 0; i < mqprio->qopt.num_tc; i++) { qoffset = mqprio->qopt.offset[i]; @@ -206,6 +370,7 @@ out_free_eotids: } } + cxgb4_mqprio_free_hw_resources(dev); return ret; } @@ -235,6 +400,8 @@ static void cxgb4_mqprio_disable_offload(struct net_device *dev) } } + cxgb4_mqprio_free_hw_resources(dev); + memset(&tc_port_mqprio->mqprio, 0, sizeof(struct tc_mqprio_qopt_offload)); @@ -310,6 +477,7 @@ int cxgb4_init_tc_mqprio(struct adapter *adap) } adap->tc_mqprio = tc_mqprio; + refcount_set(&adap->tc_mqprio->refcnt, 0); return 0; out_free_ports: diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h index 125664b82236..6491ef91c8a9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h @@ -8,6 +8,15 @@ #define CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM 128 +#define CXGB4_EOHW_TXQ_DEFAULT_DESC_NUM 1024 + +#define CXGB4_EOHW_RXQ_DEFAULT_DESC_NUM 1024 +#define CXGB4_EOHW_RXQ_DEFAULT_DESC_SIZE 64 +#define CXGB4_EOHW_RXQ_DEFAULT_INTR_USEC 5 +#define CXGB4_EOHW_RXQ_DEFAULT_PKT_CNT 8 + +#define CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM 72 + enum cxgb4_mqprio_state { CXGB4_MQPRIO_STATE_DISABLED = 0, CXGB4_MQPRIO_STATE_ACTIVE, @@ -20,6 +29,7 @@ struct cxgb4_tc_port_mqprio { }; struct cxgb4_tc_mqprio { + refcount_t refcnt; /* Refcount for adapter-wide resources */ struct cxgb4_tc_port_mqprio *port_mqprio; /* Per port MQPRIO info */ }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 3d9401354af2..cce33d279094 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -366,33 +366,19 @@ free_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) } } -static void enable_rx(struct adapter *adap, struct sge_rspq *q) -{ - if (!q) - return; - - if (q->handler) - napi_enable(&q->napi); - - /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), - SEINTARM_V(q->intr_params) | - INGRESSQID_V(q->cntxt_id)); -} - -static void quiesce_rx(struct adapter *adap, struct sge_rspq *q) -{ - if (q && q->handler) - napi_disable(&q->napi); -} - static void enable_rx_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; int idx; - for_each_uldrxq(rxq_info, idx) - enable_rx(adap, &rxq_info->uldrxq[idx].rspq); + for_each_uldrxq(rxq_info, idx) { + struct sge_rspq *q = &rxq_info->uldrxq[idx].rspq; + + if (!q) + continue; + + cxgb4_enable_rx(adap, q); + } } static void quiesce_rx_uld(struct adapter *adap, unsigned int uld_type) @@ -400,8 +386,14 @@ static void quiesce_rx_uld(struct adapter *adap, unsigned int uld_type) struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; int idx; - for_each_uldrxq(rxq_info, idx) - quiesce_rx(adap, &rxq_info->uldrxq[idx].rspq); + for_each_uldrxq(rxq_info, idx) { + struct sge_rspq *q = &rxq_info->uldrxq[idx].rspq; + + if (!q) + continue; + + cxgb4_quiesce_rx(q); + } } static void diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ed1418d2364f..3ea2eccde262 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -3982,30 +3982,30 @@ int t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid, return t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); } -int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, - struct net_device *dev, unsigned int iqid, - unsigned int uld_type) +static int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_txq *q, + struct net_device *dev, u32 cmd, u32 iqid) { unsigned int chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); - int ret, nentries; - struct fw_eq_ofld_cmd c; - struct sge *s = &adap->sge; struct port_info *pi = netdev_priv(dev); - int cmd = FW_EQ_OFLD_CMD; + struct sge *s = &adap->sge; + struct fw_eq_ofld_cmd c; + u32 fb_min, nentries; + int ret; /* Add status entries */ - nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc); - - txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, - sizeof(struct tx_desc), sizeof(struct tx_sw_desc), - &txq->q.phys_addr, &txq->q.sdesc, s->stat_len, - NUMA_NO_NODE); - if (!txq->q.desc) + nentries = q->size + s->stat_len / sizeof(struct tx_desc); + q->desc = alloc_ring(adap->pdev_dev, q->size, sizeof(struct tx_desc), + sizeof(struct tx_sw_desc), &q->phys_addr, + &q->sdesc, s->stat_len, NUMA_NO_NODE); + if (!q->desc) return -ENOMEM; + if (chip_ver <= CHELSIO_T5) + fb_min = FETCHBURSTMIN_64B_X; + else + fb_min = FETCHBURSTMIN_64B_T6_X; + memset(&c, 0, sizeof(c)); - if (unlikely(uld_type == CXGB4_TX_CRYPTO)) - cmd = FW_EQ_CTRL_CMD; c.op_to_vfn = htonl(FW_CMD_OP_V(cmd) | FW_CMD_REQUEST_F | FW_CMD_WRITE_F | FW_CMD_EXEC_F | FW_EQ_OFLD_CMD_PFN_V(adap->pf) | @@ -4017,27 +4017,42 @@ int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, FW_EQ_OFLD_CMD_PCIECHN_V(pi->tx_chan) | FW_EQ_OFLD_CMD_FETCHRO_F | FW_EQ_OFLD_CMD_IQID_V(iqid)); c.dcaen_to_eqsize = - htonl(FW_EQ_OFLD_CMD_FBMIN_V(chip_ver <= CHELSIO_T5 - ? FETCHBURSTMIN_64B_X - : FETCHBURSTMIN_64B_T6_X) | + htonl(FW_EQ_OFLD_CMD_FBMIN_V(fb_min) | FW_EQ_OFLD_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) | FW_EQ_OFLD_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) | FW_EQ_OFLD_CMD_EQSIZE_V(nentries)); - c.eqaddr = cpu_to_be64(txq->q.phys_addr); + c.eqaddr = cpu_to_be64(q->phys_addr); ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); if (ret) { - kfree(txq->q.sdesc); - txq->q.sdesc = NULL; + kfree(q->sdesc); + q->sdesc = NULL; dma_free_coherent(adap->pdev_dev, nentries * sizeof(struct tx_desc), - txq->q.desc, txq->q.phys_addr); - txq->q.desc = NULL; + q->desc, q->phys_addr); + q->desc = NULL; return ret; } + init_txq(adap, q, FW_EQ_OFLD_CMD_EQID_G(ntohl(c.eqid_pkd))); + return 0; +} + +int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, + struct net_device *dev, unsigned int iqid, + unsigned int uld_type) +{ + u32 cmd = FW_EQ_OFLD_CMD; + int ret; + + if (unlikely(uld_type == CXGB4_TX_CRYPTO)) + cmd = FW_EQ_CTRL_CMD; + + ret = t4_sge_alloc_ofld_txq(adap, &txq->q, dev, cmd, iqid); + if (ret) + return ret; + txq->q.q_type = CXGB4_TXQ_ULD; - init_txq(adap, &txq->q, FW_EQ_OFLD_CMD_EQID_G(ntohl(c.eqid_pkd))); txq->adap = adap; skb_queue_head_init(&txq->sendq); tasklet_init(&txq->qresume_tsk, restart_ofldq, (unsigned long)txq); @@ -4046,6 +4061,25 @@ int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, return 0; } +int t4_sge_alloc_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq, + struct net_device *dev, u32 iqid) +{ + int ret; + + ret = t4_sge_alloc_ofld_txq(adap, &txq->q, dev, FW_EQ_OFLD_CMD, iqid); + if (ret) + return ret; + + txq->q.q_type = CXGB4_TXQ_ULD; + spin_lock_init(&txq->lock); + txq->adap = adap; + txq->tso = 0; + txq->tx_cso = 0; + txq->vlan_ins = 0; + txq->mapping_err = 0; + return 0; +} + void free_txq(struct adapter *adap, struct sge_txq *q) { struct sge *s = &adap->sge; @@ -4101,6 +4135,17 @@ void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q) q->fl.size ? &q->fl : NULL); } +void t4_sge_free_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq) +{ + if (txq->q.desc) { + t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0, + txq->q.cntxt_id); + free_tx_desc(adap, &txq->q, txq->q.in_use, false); + kfree(txq->q.sdesc); + free_txq(adap, &txq->q); + } +} + /** * t4_free_sge_resources - free SGE resources * @adap: the adapter -- cgit v1.2.3-59-g8ed1b