diff options
author | Tony Lindgren <tony@atomide.com> | 2016-03-30 10:36:06 -0700 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2016-03-30 10:36:06 -0700 |
commit | 1809de7e7d37c585e01a1bcc583ea92b78fc759d (patch) | |
tree | 76c5b35c2b04eafce86a1a729c02ab705eba44bc /drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |
parent | ebf24414809200915b9ddf7f109bba7c278c8210 (diff) | |
parent | 3ca4a238106dedc285193ee47f494a6584b6fd2f (diff) | |
download | talos-op-linux-1809de7e7d37c585e01a1bcc583ea92b78fc759d.tar.gz talos-op-linux-1809de7e7d37c585e01a1bcc583ea92b78fc759d.zip |
Merge tag 'for-v4.6-rc/omap-fixes-a' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into omap-for-v4.6/fixes
ARM: OMAP2+: first hwmod fix for v4.6-rc
Fix a longstanding bug in the hwmod code that could cause
hardware SYSCONFIG register values to not match the kernel's
idea of what they should be, and that could result in lower
performance during IP block idle entry.
Basic build, boot, and PM test logs are available here:
http://www.pwsan.com/omap/testlogs/omap-hwmod-fixes-a-for-v4.6-rc/20160326231727/
Diffstat (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c')
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 235 |
1 files changed, 165 insertions, 70 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index b8a5fb0c32d4..d1e3f0997d6b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -227,7 +227,7 @@ static DEFINE_MUTEX(uld_mutex); static LIST_HEAD(adap_rcu_list); static DEFINE_SPINLOCK(adap_rcu_lock); static struct cxgb4_uld_info ulds[CXGB4_ULD_MAX]; -static const char *uld_str[] = { "RDMA", "iSCSI" }; +static const char *const uld_str[] = { "RDMA", "iSCSI", "iSCSIT" }; static void link_report(struct net_device *dev) { @@ -338,84 +338,108 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id) netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); } +int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */ +module_param(dbfifo_int_thresh, int, 0644); +MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold"); + /* - * Configure the exact and hash address filters to handle a port's multicast - * and secondary unicast MAC addresses. + * usecs to sleep while draining the dbfifo */ -static int set_addr_filters(const struct net_device *dev, bool sleep) +static int dbfifo_drain_delay = 1000; +module_param(dbfifo_drain_delay, int, 0644); +MODULE_PARM_DESC(dbfifo_drain_delay, + "usecs to sleep while draining the dbfifo"); + +static inline int cxgb4_set_addr_hash(struct port_info *pi) { + struct adapter *adap = pi->adapter; + u64 vec = 0; + bool ucast = false; + struct hash_mac_addr *entry; + + /* Calculate the hash vector for the updated list and program it */ + list_for_each_entry(entry, &adap->mac_hlist, list) { + ucast |= is_unicast_ether_addr(entry->addr); + vec |= (1ULL << hash_mac_addr(entry->addr)); + } + return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast, + vec, false); +} + +static int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr) +{ + struct port_info *pi = netdev_priv(netdev); + struct adapter *adap = pi->adapter; + int ret; u64 mhash = 0; u64 uhash = 0; - bool free = true; - u16 filt_idx[7]; - const u8 *addr[7]; - int ret, naddr = 0; - const struct netdev_hw_addr *ha; - int uc_cnt = netdev_uc_count(dev); - int mc_cnt = netdev_mc_count(dev); - const struct port_info *pi = netdev_priv(dev); - unsigned int mb = pi->adapter->pf; + bool free = false; + bool ucast = is_unicast_ether_addr(mac_addr); + const u8 *maclist[1] = {mac_addr}; + struct hash_mac_addr *new_entry; - /* first do the secondary unicast addresses */ - netdev_for_each_uc_addr(ha, dev) { - addr[naddr++] = ha->addr; - if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { - ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free, - naddr, addr, filt_idx, &uhash, sleep); - if (ret < 0) - return ret; - - free = false; - naddr = 0; - } + ret = t4_alloc_mac_filt(adap, adap->mbox, pi->viid, free, 1, maclist, + NULL, ucast ? &uhash : &mhash, false); + if (ret < 0) + goto out; + /* if hash != 0, then add the addr to hash addr list + * so on the end we will calculate the hash for the + * list and program it + */ + if (uhash || mhash) { + new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC); + if (!new_entry) + return -ENOMEM; + ether_addr_copy(new_entry->addr, mac_addr); + list_add_tail(&new_entry->list, &adap->mac_hlist); + ret = cxgb4_set_addr_hash(pi); } +out: + return ret < 0 ? ret : 0; +} - /* next set up the multicast addresses */ - netdev_for_each_mc_addr(ha, dev) { - addr[naddr++] = ha->addr; - if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { - ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free, - naddr, addr, filt_idx, &mhash, sleep); - if (ret < 0) - return ret; +static int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr) +{ + struct port_info *pi = netdev_priv(netdev); + struct adapter *adap = pi->adapter; + int ret; + const u8 *maclist[1] = {mac_addr}; + struct hash_mac_addr *entry, *tmp; - free = false; - naddr = 0; + /* If the MAC address to be removed is in the hash addr + * list, delete it from the list and update hash vector + */ + list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) { + if (ether_addr_equal(entry->addr, mac_addr)) { + list_del(&entry->list); + kfree(entry); + return cxgb4_set_addr_hash(pi); } } - return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0, - uhash | mhash, sleep); + ret = t4_free_mac_filt(adap, adap->mbox, pi->viid, 1, maclist, false); + return ret < 0 ? -EINVAL : 0; } -int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */ -module_param(dbfifo_int_thresh, int, 0644); -MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold"); - -/* - * usecs to sleep while draining the dbfifo - */ -static int dbfifo_drain_delay = 1000; -module_param(dbfifo_drain_delay, int, 0644); -MODULE_PARM_DESC(dbfifo_drain_delay, - "usecs to sleep while draining the dbfifo"); - /* * Set Rx properties of a port, such as promiscruity, address filters, and MTU. * If @mtu is -1 it is left unchanged. */ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) { - int ret; struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; - ret = set_addr_filters(dev, sleep_ok); - if (ret == 0) - ret = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, mtu, - (dev->flags & IFF_PROMISC) ? 1 : 0, - (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, - sleep_ok); - return ret; + if (!(dev->flags & IFF_PROMISC)) { + __dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync); + if (!(dev->flags & IFF_ALLMULTI)) + __dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync); + } + + return t4_set_rxmode(adapter, adapter->mbox, pi->viid, mtu, + (dev->flags & IFF_PROMISC) ? 1 : 0, + (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, + sleep_ok); } /** @@ -640,6 +664,13 @@ out: return 0; } +/* Flush the aggregated lro sessions */ +static void uldrx_flush_handler(struct sge_rspq *q) +{ + if (ulds[q->uld].lro_flush) + ulds[q->uld].lro_flush(&q->lro_mgr); +} + /** * uldrx_handler - response queue handler for ULD queues * @q: the response queue that received the packet @@ -653,6 +684,7 @@ static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, const struct pkt_gl *gl) { struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq); + int ret; /* FW can send CPLs encapsulated in a CPL_FW4_MSG. */ @@ -660,10 +692,19 @@ static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, ((const struct cpl_fw4_msg *)(rsp + 1))->type == FW_TYPE_RSSCPL) rsp += 2; - if (ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], rsp, gl)) { + if (q->flush_handler) + ret = ulds[q->uld].lro_rx_handler(q->adap->uld_handle[q->uld], + rsp, gl, &q->lro_mgr, + &q->napi); + else + ret = ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], + rsp, gl); + + if (ret) { rxq->stats.nomem++; return -1; } + if (gl == NULL) rxq->stats.imm++; else if (gl == CXGB4_MSG_AN) @@ -730,6 +771,10 @@ static void name_msix_vecs(struct adapter *adap) snprintf(adap->msix_info[msi_idx++].desc, n, "%s-iscsi%d", adap->port[0]->name, i); + for_each_iscsitrxq(&adap->sge, i) + snprintf(adap->msix_info[msi_idx++].desc, n, "%s-iSCSIT%d", + adap->port[0]->name, i); + for_each_rdmarxq(&adap->sge, i) snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d", adap->port[0]->name, i); @@ -743,6 +788,7 @@ static int request_msix_queue_irqs(struct adapter *adap) { struct sge *s = &adap->sge; int err, ethqidx, iscsiqidx = 0, rdmaqidx = 0, rdmaciqqidx = 0; + int iscsitqidx = 0; int msi_index = 2; err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0, @@ -768,6 +814,15 @@ static int request_msix_queue_irqs(struct adapter *adap) goto unwind; msi_index++; } + for_each_iscsitrxq(s, iscsitqidx) { + err = request_irq(adap->msix_info[msi_index].vec, + t4_sge_intr_msix, 0, + adap->msix_info[msi_index].desc, + &s->iscsitrxq[iscsitqidx].rspq); + if (err) + goto unwind; + msi_index++; + } for_each_rdmarxq(s, rdmaqidx) { err = request_irq(adap->msix_info[msi_index].vec, t4_sge_intr_msix, 0, @@ -795,6 +850,9 @@ unwind: while (--rdmaqidx >= 0) free_irq(adap->msix_info[--msi_index].vec, &s->rdmarxq[rdmaqidx].rspq); + while (--iscsitqidx >= 0) + free_irq(adap->msix_info[--msi_index].vec, + &s->iscsitrxq[iscsitqidx].rspq); while (--iscsiqidx >= 0) free_irq(adap->msix_info[--msi_index].vec, &s->iscsirxq[iscsiqidx].rspq); @@ -816,6 +874,9 @@ static void free_msix_queue_irqs(struct adapter *adap) for_each_iscsirxq(s, i) free_irq(adap->msix_info[msi_index++].vec, &s->iscsirxq[i].rspq); + for_each_iscsitrxq(s, i) + free_irq(adap->msix_info[msi_index++].vec, + &s->iscsitrxq[i].rspq); for_each_rdmarxq(s, i) free_irq(adap->msix_info[msi_index++].vec, &s->rdmarxq[i].rspq); for_each_rdmaciq(s, i) @@ -960,7 +1021,7 @@ static void enable_rx(struct adapter *adap) static int alloc_ofld_rxqs(struct adapter *adap, struct sge_ofld_rxq *q, unsigned int nq, unsigned int per_chan, int msi_idx, - u16 *ids) + u16 *ids, bool lro) { int i, err; @@ -970,7 +1031,9 @@ static int alloc_ofld_rxqs(struct adapter *adap, struct sge_ofld_rxq *q, err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[i / per_chan], msi_idx, q->fl.size ? &q->fl : NULL, - uldrx_handler, 0); + uldrx_handler, + lro ? uldrx_flush_handler : NULL, + 0); if (err) return err; memset(&q->stats, 0, sizeof(q->stats)); @@ -1000,7 +1063,7 @@ static int setup_sge_queues(struct adapter *adap) msi_idx = 1; /* vector 0 is for non-queue interrupts */ else { err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, - NULL, NULL, -1); + NULL, NULL, NULL, -1); if (err) return err; msi_idx = -((int)s->intrq.abs_id + 1); @@ -1020,7 +1083,7 @@ static int setup_sge_queues(struct adapter *adap) * new/deleted queues. */ err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], - msi_idx, NULL, fwevtq_handler, -1); + msi_idx, NULL, fwevtq_handler, NULL, -1); if (err) { freeout: t4_free_sge_resources(adap); return err; @@ -1038,6 +1101,7 @@ freeout: t4_free_sge_resources(adap); err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, msi_idx, &q->fl, t4_ethrx_handler, + NULL, t4_get_mps_bg_map(adap, pi->tx_chan)); if (err) @@ -1063,18 +1127,19 @@ freeout: t4_free_sge_resources(adap); goto freeout; } -#define ALLOC_OFLD_RXQS(firstq, nq, per_chan, ids) do { \ - err = alloc_ofld_rxqs(adap, firstq, nq, per_chan, msi_idx, ids); \ +#define ALLOC_OFLD_RXQS(firstq, nq, per_chan, ids, lro) do { \ + err = alloc_ofld_rxqs(adap, firstq, nq, per_chan, msi_idx, ids, lro); \ if (err) \ goto freeout; \ if (msi_idx > 0) \ msi_idx += nq; \ } while (0) - ALLOC_OFLD_RXQS(s->iscsirxq, s->iscsiqsets, j, s->iscsi_rxq); - ALLOC_OFLD_RXQS(s->rdmarxq, s->rdmaqs, 1, s->rdma_rxq); + ALLOC_OFLD_RXQS(s->iscsirxq, s->iscsiqsets, j, s->iscsi_rxq, false); + ALLOC_OFLD_RXQS(s->iscsitrxq, s->niscsitq, j, s->iscsit_rxq, true); + ALLOC_OFLD_RXQS(s->rdmarxq, s->rdmaqs, 1, s->rdma_rxq, false); j = s->rdmaciqs / adap->params.nports; /* rdmaq queues per channel */ - ALLOC_OFLD_RXQS(s->rdmaciq, s->rdmaciqs, j, s->rdma_ciq); + ALLOC_OFLD_RXQS(s->rdmaciq, s->rdmaciqs, j, s->rdma_ciq, false); #undef ALLOC_OFLD_RXQS @@ -2406,6 +2471,9 @@ static void uld_attach(struct adapter *adap, unsigned int uld) } else if (uld == CXGB4_ULD_ISCSI) { lli.rxq_ids = adap->sge.iscsi_rxq; lli.nrxq = adap->sge.iscsiqsets; + } else if (uld == CXGB4_ULD_ISCSIT) { + lli.rxq_ids = adap->sge.iscsit_rxq; + lli.nrxq = adap->sge.niscsitq; } lli.ntxq = adap->sge.iscsiqsets; lli.nchan = adap->params.nports; @@ -2413,6 +2481,10 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.wr_cred = adap->params.ofldq_wr_cred; lli.adapter_type = adap->params.chip; lli.iscsi_iolen = MAXRXDATA_G(t4_read_reg(adap, TP_PARA_REG2_A)); + lli.iscsi_tagmask = t4_read_reg(adap, ULP_RX_ISCSI_TAGMASK_A); + lli.iscsi_pgsz_order = t4_read_reg(adap, ULP_RX_ISCSI_PSZ_A); + lli.iscsi_llimit = t4_read_reg(adap, ULP_RX_ISCSI_LLIMIT_A); + lli.iscsi_ppm = &adap->iscsi_ppm; lli.cclk_ps = 1000000000 / adap->params.vpd.cclk; lli.udb_density = 1 << adap->params.sge.eq_qpp; lli.ucq_density = 1 << adap->params.sge.iq_qpp; @@ -2677,6 +2749,8 @@ static int cxgb_up(struct adapter *adap) #if IS_ENABLED(CONFIG_IPV6) update_clip(adap); #endif + /* Initialize hash mac addr list*/ + INIT_LIST_HEAD(&adap->mac_hlist); out: return err; irq_err: @@ -4310,6 +4384,9 @@ static void cfg_queues(struct adapter *adap) s->rdmaciqs = (s->rdmaciqs / adap->params.nports) * adap->params.nports; s->rdmaciqs = max_t(int, s->rdmaciqs, adap->params.nports); + + if (!is_t4(adap->params.chip)) + s->niscsitq = s->iscsiqsets; } for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { @@ -4336,6 +4413,16 @@ static void cfg_queues(struct adapter *adap) r->fl.size = 72; } + if (!is_t4(adap->params.chip)) { + for (i = 0; i < ARRAY_SIZE(s->iscsitrxq); i++) { + struct sge_ofld_rxq *r = &s->iscsitrxq[i]; + + init_rspq(adap, &r->rspq, 5, 1, 1024, 64); + r->rspq.uld = CXGB4_ULD_ISCSIT; + r->fl.size = 72; + } + } + for (i = 0; i < ARRAY_SIZE(s->rdmarxq); i++) { struct sge_ofld_rxq *r = &s->rdmarxq[i]; @@ -4410,9 +4497,13 @@ static int enable_msix(struct adapter *adap) want = s->max_ethqsets + EXTRA_VECS; if (is_offload(adap)) { - want += s->rdmaqs + s->rdmaciqs + s->iscsiqsets; + want += s->rdmaqs + s->rdmaciqs + s->iscsiqsets + + s->niscsitq; /* need nchan for each possible ULD */ - ofld_need = 3 * nchan; + if (is_t4(adap->params.chip)) + ofld_need = 3 * nchan; + else + ofld_need = 4 * nchan; } #ifdef CONFIG_CHELSIO_T4_DCB /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for @@ -4444,12 +4535,16 @@ static int enable_msix(struct adapter *adap) if (allocated < want) { s->rdmaqs = nchan; s->rdmaciqs = nchan; + + if (!is_t4(adap->params.chip)) + s->niscsitq = nchan; } /* leftovers go to OFLD */ i = allocated - EXTRA_VECS - s->max_ethqsets - - s->rdmaqs - s->rdmaciqs; + s->rdmaqs - s->rdmaciqs - s->niscsitq; s->iscsiqsets = (i / nchan) * nchan; /* round down */ + } for (i = 0; i < allocated; ++i) adap->msix_info[i].vec = entries[i].vector; |