diff options
Diffstat (limited to 'drivers/net/cxgb3')
-rw-r--r-- | drivers/net/cxgb3/adapter.h | 5 | ||||
-rw-r--r-- | drivers/net/cxgb3/common.h | 28 | ||||
-rw-r--r-- | drivers/net/cxgb3/cxgb3_main.c | 67 | ||||
-rw-r--r-- | drivers/net/cxgb3/cxgb3_offload.c | 2 | ||||
-rw-r--r-- | drivers/net/cxgb3/cxgb3_offload.h | 5 | ||||
-rw-r--r-- | drivers/net/cxgb3/regs.h | 16 | ||||
-rw-r--r-- | drivers/net/cxgb3/sge.c | 46 | ||||
-rw-r--r-- | drivers/net/cxgb3/t3_hw.c | 8 | ||||
-rw-r--r-- | drivers/net/cxgb3/xgmac.c | 18 |
9 files changed, 135 insertions, 60 deletions
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 3e8618b4efb..4cd7f420766 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -264,6 +264,10 @@ struct adapter { struct work_struct fatal_error_handler_task; struct work_struct link_fault_handler_task; + struct work_struct db_full_task; + struct work_struct db_empty_task; + struct work_struct db_drop_task; + struct dentry *debugfs_root; struct mutex mdio_lock; @@ -335,6 +339,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); +extern struct workqueue_struct *cxgb3_wq; int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 6ff356d4c7a..fe08a004b0d 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -67,32 +67,6 @@ /* Additional NETIF_MSG_* categories */ #define NETIF_MSG_MMIO 0x8000000 -struct t3_rx_mode { - struct net_device *dev; - struct dev_mc_list *mclist; - unsigned int idx; -}; - -static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev, - struct dev_mc_list *mclist) -{ - p->dev = dev; - p->mclist = mclist; - p->idx = 0; -} - -static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm) -{ - u8 *addr = NULL; - - if (rm->mclist && rm->idx < rm->dev->mc_count) { - addr = rm->mclist->dmi_addr; - rm->mclist = rm->mclist->next; - rm->idx++; - } - return addr; -} - enum { MAX_NPORTS = 2, /* max # of ports */ MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ @@ -746,7 +720,7 @@ void t3_mac_enable_exact_filters(struct cmac *mac); int t3_mac_enable(struct cmac *mac, int which); int t3_mac_disable(struct cmac *mac, int which); int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu); -int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm); +int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev); int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]); int t3_mac_set_num_ucast(struct cmac *mac, int n); const struct mac_stats *t3_mac_update_stats(struct cmac *mac); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 89bec9c3c14..3e453e1d97e 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -45,6 +45,7 @@ #include <linux/firmware.h> #include <linux/log2.h> #include <linux/stringify.h> +#include <linux/sched.h> #include <asm/uaccess.h> #include "common.h" @@ -80,7 +81,7 @@ enum { #define CH_DEVICE(devid, idx) \ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } -static const struct pci_device_id cxgb3_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = { CH_DEVICE(0x20, 0), /* PE9000 */ CH_DEVICE(0x21, 1), /* T302E */ CH_DEVICE(0x22, 2), /* T310E */ @@ -140,7 +141,7 @@ MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not"); * will block keventd as it needs the rtnl lock, and we'll deadlock waiting * for our work to complete. Get our own work queue to solve this. */ -static struct workqueue_struct *cxgb3_wq; +struct workqueue_struct *cxgb3_wq; /** * link_report - show link status and link speed/duplex @@ -324,11 +325,9 @@ void t3_os_phymod_changed(struct adapter *adap, int port_id) static void cxgb_set_rxmode(struct net_device *dev) { - struct t3_rx_mode rm; struct port_info *pi = netdev_priv(dev); - init_rx_mode(&rm, dev, dev->mc_list); - t3_mac_set_rx_mode(&pi->mac, &rm); + t3_mac_set_rx_mode(&pi->mac, dev); } /** @@ -339,17 +338,15 @@ static void cxgb_set_rxmode(struct net_device *dev) */ static void link_start(struct net_device *dev) { - struct t3_rx_mode rm; struct port_info *pi = netdev_priv(dev); struct cmac *mac = &pi->mac; - init_rx_mode(&rm, dev, dev->mc_list); t3_mac_reset(mac); t3_mac_set_num_ucast(mac, MAX_MAC_IDX); t3_mac_set_mtu(mac, dev->mtu); t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr); t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr); - t3_mac_set_rx_mode(mac, &rm); + t3_mac_set_rx_mode(mac, dev); t3_link_start(&pi->phy, mac, &pi->link_config); t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); } @@ -590,6 +587,19 @@ static void setup_rss(struct adapter *adap) V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map); } +static void ring_dbs(struct adapter *adap) +{ + int i, j; + + for (i = 0; i < SGE_QSETS; i++) { + struct sge_qset *qs = &adap->sge.qs[i]; + + if (qs->adap) + for (j = 0; j < SGE_TXQ_PER_SET; j++) + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id)); + } +} + static void init_napi(struct adapter *adap) { int i; @@ -2754,6 +2764,42 @@ static void t3_adap_check_task(struct work_struct *work) spin_unlock_irq(&adapter->work_lock); } +static void db_full_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_full_task); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0); +} + +static void db_empty_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_empty_task); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0); +} + +static void db_drop_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_drop_task); + unsigned long delay = 1000; + unsigned short r; + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0); + + /* + * Sleep a while before ringing the driver qset dbs. + * The delay is between 1000-2023 usecs. + */ + get_random_bytes(&r, 2); + delay += r & 1023; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(delay)); + ring_dbs(adapter); +} + /* * Processes external (PHY) interrupts in process context. */ @@ -3222,6 +3268,11 @@ static int __devinit init_one(struct pci_dev *pdev, INIT_LIST_HEAD(&adapter->adapter_list); INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); + + INIT_WORK(&adapter->db_full_task, db_full_task); + INIT_WORK(&adapter->db_empty_task, db_empty_task); + INIT_WORK(&adapter->db_drop_task, db_drop_task); + INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); for (i = 0; i < ai->nports0 + ai->nports1; ++i) { diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 75064eea1d8..9498361119d 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -1252,7 +1252,7 @@ int cxgb3_offload_activate(struct adapter *adapter) struct mtutab mtutab; unsigned int l2t_capacity; - t = kcalloc(1, sizeof(*t), GFP_KERNEL); + t = kzalloc(sizeof(*t), GFP_KERNEL); if (!t) return -ENOMEM; diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 670aa62042d..929c298115c 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -73,7 +73,10 @@ enum { OFFLOAD_STATUS_UP, OFFLOAD_STATUS_DOWN, OFFLOAD_PORT_DOWN, - OFFLOAD_PORT_UP + OFFLOAD_PORT_UP, + OFFLOAD_DB_FULL, + OFFLOAD_DB_EMPTY, + OFFLOAD_DB_DROP }; struct cxgb3_client { diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 1b5327b5a96..cb42353c9fd 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -254,6 +254,22 @@ #define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) #define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) +#define S_HIPRIORITYDBFULL 7 +#define V_HIPRIORITYDBFULL(x) ((x) << S_HIPRIORITYDBFULL) +#define F_HIPRIORITYDBFULL V_HIPRIORITYDBFULL(1U) + +#define S_HIPRIORITYDBEMPTY 6 +#define V_HIPRIORITYDBEMPTY(x) ((x) << S_HIPRIORITYDBEMPTY) +#define F_HIPRIORITYDBEMPTY V_HIPRIORITYDBEMPTY(1U) + +#define S_LOPRIORITYDBFULL 5 +#define V_LOPRIORITYDBFULL(x) ((x) << S_LOPRIORITYDBFULL) +#define F_LOPRIORITYDBFULL V_LOPRIORITYDBFULL(1U) + +#define S_LOPRIORITYDBEMPTY 4 +#define V_LOPRIORITYDBEMPTY(x) ((x) << S_LOPRIORITYDBEMPTY) +#define F_LOPRIORITYDBEMPTY V_LOPRIORITYDBEMPTY(1U) + #define S_RSPQDISABLED 3 #define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) #define F_RSPQDISABLED V_RSPQDISABLED(1U) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 5dbc125822b..67e61b2a8c4 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -42,6 +42,7 @@ #include "sge_defs.h" #include "t3_cpl.h" #include "firmware_exports.h" +#include "cxgb3_offload.h" #define USE_GTS 0 @@ -480,6 +481,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) { if (q->pend_cred >= q->credits / 4) { q->pend_cred = 0; + wmb(); t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); } } @@ -2079,6 +2081,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, struct sge_fl *fl, int len, int complete) { struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + struct port_info *pi = netdev_priv(qs->netdev); struct sk_buff *skb = NULL; struct cpl_rx_pkt *cpl; struct skb_frag_struct *rx_frag; @@ -2116,11 +2119,18 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, if (!nr_frags) { offset = 2 + sizeof(struct cpl_rx_pkt); - qs->lro_va = sd->pg_chunk.va + 2; - } - len -= offset; + cpl = qs->lro_va = sd->pg_chunk.va + 2; + + if ((pi->rx_offload & T3_RX_CSUM) && + cpl->csum_valid && cpl->csum == htons(0xffff)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + } else + skb->ip_summed = CHECKSUM_NONE; + } else + cpl = qs->lro_va; - prefetch(qs->lro_va); + len -= offset; rx_frag += nr_frags; rx_frag->page = sd->pg_chunk.page; @@ -2136,12 +2146,8 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, return; skb_record_rx_queue(skb, qs - &adap->sge.qs[0]); - skb->ip_summed = CHECKSUM_UNNECESSARY; - cpl = qs->lro_va; if (unlikely(cpl->vlan_valid)) { - struct net_device *dev = qs->netdev; - struct port_info *pi = netdev_priv(dev); struct vlan_group *grp = pi->vlan_grp; if (likely(grp != NULL)) { @@ -2282,11 +2288,14 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, while (likely(budget_left && is_new_response(r, q))) { int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; struct sk_buff *skb = NULL; - u32 len, flags = ntohl(r->flags); - __be32 rss_hi = *(const __be32 *)r, - rss_lo = r->rss_hdr.rss_hash_val; + u32 len, flags; + __be32 rss_hi, rss_lo; + rmb(); eth = r->rss_hdr.opcode == CPL_RX_PKT; + rss_hi = *(const __be32 *)r; + rss_lo = r->rss_hdr.rss_hash_val; + flags = ntohl(r->flags); if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); @@ -2497,7 +2506,10 @@ static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, refill_rspq(adap, q, q->credits); q->credits = 0; } - } while (is_new_response(r, q) && is_pure_response(r)); + if (!is_new_response(r, q)) + break; + rmb(); + } while (is_pure_response(r)); if (sleeping) check_ring_db(adap, qs, sleeping); @@ -2531,6 +2543,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) if (!is_new_response(r, q)) return -1; + rmb(); if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); @@ -2829,8 +2842,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter) } if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) - CH_ALERT(adapter, "SGE dropped %s priority doorbell\n", - status & F_HIPIODRBDROPERR ? "high" : "lo"); + queue_work(cxgb3_wq, &adapter->db_drop_task); + + if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL)) + queue_work(cxgb3_wq, &adapter->db_full_task); + + if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY)) + queue_work(cxgb3_wq, &adapter->db_empty_task); t3_write_reg(adapter, A_SG_INT_CAUSE, status); if (status & SGE_FATALERR) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 032cfe06557..95a8ba0759f 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1262,7 +1262,8 @@ void t3_link_changed(struct adapter *adapter, int port_id) lc->fc = fc; } - t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc); + t3_os_link_changed(adapter, port_id, link_ok && !pi->link_fault, + speed, duplex, fc); } void t3_link_fault(struct adapter *adapter, int port_id) @@ -1432,7 +1433,10 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ - F_HIRCQPARITYERROR) + F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \ + F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \ + F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \ + F_LOPIODRBDROPERR) #define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ F_NFASRCHFAIL) diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index 0109ee4f2f9..c142a2132e9 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -297,29 +297,30 @@ static int hash_hw_addr(const u8 * addr) return hash; } -int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) +int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev) { u32 val, hash_lo, hash_hi; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; - if (rm->dev->flags & IFF_PROMISC) + if (dev->flags & IFF_PROMISC) val |= F_COPYALLFRAMES; t3_write_reg(adap, A_XGM_RX_CFG + oft, val); - if (rm->dev->flags & IFF_ALLMULTI) + if (dev->flags & IFF_ALLMULTI) hash_lo = hash_hi = 0xffffffff; else { - u8 *addr; + struct dev_mc_list *dmi; int exact_addr_idx = mac->nucast; hash_lo = hash_hi = 0; - while ((addr = t3_get_next_mcaddr(rm))) + netdev_for_each_mc_addr(dmi, dev) if (exact_addr_idx < EXACT_ADDR_FILTERS) - set_addr_filter(mac, exact_addr_idx++, addr); + set_addr_filter(mac, exact_addr_idx++, + dmi->dmi_addr); else { - int hash = hash_hw_addr(addr); + int hash = hash_hw_addr(dmi->dmi_addr); if (hash < 32) hash_lo |= (1 << hash); @@ -353,6 +354,9 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) * packet size register includes header, but not FCS. */ mtu += 14; + if (mtu > 1536) + mtu += 4; + if (mtu > MAX_FRAME_SIZE - 4) return -EINVAL; t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); |