diff options
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 430 |
1 files changed, 240 insertions, 190 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a485f7fdaf37..c411bb1845fd 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -33,10 +33,6 @@ module_param(num_vfs, uint, S_IRUGO); MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize"); -static bool multi_rxq = true; -module_param(multi_rxq, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(multi_rxq, "Multi Rx Queue support. Enabled by default"); - static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, @@ -48,7 +44,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { }; MODULE_DEVICE_TABLE(pci, be_dev_ids); /* UE Status Low CSR */ -static char *ue_status_low_desc[] = { +static const char * const ue_status_low_desc[] = { "CEV", "CTX", "DBUF", @@ -83,7 +79,7 @@ static char *ue_status_low_desc[] = { "MPU_INTPEND" }; /* UE Status High CSR */ -static char *ue_status_hi_desc[] = { +static const char * const ue_status_hi_desc[] = { "LPCMEMHOST", "MGMT_MAC", "PCS0ONLINE", @@ -107,7 +103,7 @@ static char *ue_status_hi_desc[] = { "HOST7", "HOST8", "HOST9", - "NETC" + "NETC", "Unknown", "Unknown", "Unknown", @@ -362,8 +358,8 @@ static void populate_lancer_stats(struct be_adapter *adapter) drvs->rx_priority_pause_frames = 0; drvs->pmem_fifo_overflow_drop = 0; drvs->rx_pause_frames = - make_64bit_val(pport_stats->rx_pause_frames_lo, - pport_stats->rx_pause_frames_hi); + make_64bit_val(pport_stats->rx_pause_frames_hi, + pport_stats->rx_pause_frames_lo); drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi, pport_stats->rx_crc_errors_lo); drvs->rx_control_frames = @@ -427,31 +423,40 @@ void netdev_stats_update(struct be_adapter *adapter) struct be_drv_stats *drvs = &adapter->drv_stats; struct net_device_stats *dev_stats = &adapter->netdev->stats; struct be_rx_obj *rxo; + struct be_tx_obj *txo; + unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0; int i; - memset(dev_stats, 0, sizeof(*dev_stats)); for_all_rx_queues(adapter, rxo, i) { - dev_stats->rx_packets += rx_stats(rxo)->rx_pkts; - dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes; - dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts; + pkts += rx_stats(rxo)->rx_pkts; + bytes += rx_stats(rxo)->rx_bytes; + mcast += rx_stats(rxo)->rx_mcast_pkts; + drops += rx_stats(rxo)->rx_dropped; /* no space in linux buffers: best possible approximation */ if (adapter->generation == BE_GEN3) { if (!(lancer_chip(adapter))) { - struct be_erx_stats_v1 *erx_stats = + struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter); - dev_stats->rx_dropped += - erx_stats->rx_drops_no_fragments[rxo->q.id]; + drops += erx->rx_drops_no_fragments[rxo->q.id]; } } else { - struct be_erx_stats_v0 *erx_stats = + struct be_erx_stats_v0 *erx = be_erx_stats_from_cmd(adapter); - dev_stats->rx_dropped += - erx_stats->rx_drops_no_fragments[rxo->q.id]; + drops += erx->rx_drops_no_fragments[rxo->q.id]; } } + dev_stats->rx_packets = pkts; + dev_stats->rx_bytes = bytes; + dev_stats->multicast = mcast; + dev_stats->rx_dropped = drops; - dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts; - dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes; + pkts = bytes = 0; + for_all_tx_queues(adapter, txo, i) { + pkts += tx_stats(txo)->be_tx_pkts; + bytes += tx_stats(txo)->be_tx_bytes; + } + dev_stats->tx_packets = pkts; + dev_stats->tx_bytes = bytes; /* bad pkts received */ dev_stats->rx_errors = drvs->rx_crc_errors + @@ -554,9 +559,9 @@ static u32 be_calc_rate(u64 bytes, unsigned long ticks) return rate; } -static void be_tx_rate_update(struct be_adapter *adapter) +static void be_tx_rate_update(struct be_tx_obj *txo) { - struct be_tx_stats *stats = tx_stats(adapter); + struct be_tx_stats *stats = tx_stats(txo); ulong now = jiffies; /* Wrapped around? */ @@ -575,10 +580,11 @@ static void be_tx_rate_update(struct be_adapter *adapter) } } -static void be_tx_stats_update(struct be_adapter *adapter, +static void be_tx_stats_update(struct be_tx_obj *txo, u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped) { - struct be_tx_stats *stats = tx_stats(adapter); + struct be_tx_stats *stats = tx_stats(txo); + stats->be_tx_reqs++; stats->be_tx_wrbs += wrb_cnt; stats->be_tx_bytes += copied; @@ -648,7 +654,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1); } - if (adapter->vlan_grp && vlan_tx_tag_present(skb)) { + if (vlan_tx_tag_present(skb)) { AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); vlan_tag = vlan_tx_tag_get(skb); vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; @@ -682,14 +688,13 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, } } -static int make_tx_wrbs(struct be_adapter *adapter, +static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb) { dma_addr_t busaddr; int i, copied = 0; struct device *dev = &adapter->pdev->dev; struct sk_buff *first_skb = skb; - struct be_queue_info *txq = &adapter->tx_obj.q; struct be_eth_wrb *wrb; struct be_eth_hdr_wrb *hdr; bool map_single = false; @@ -753,19 +758,19 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_tx_obj *tx_obj = &adapter->tx_obj; - struct be_queue_info *txq = &tx_obj->q; + struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; + struct be_queue_info *txq = &txo->q; u32 wrb_cnt = 0, copied = 0; u32 start = txq->head; bool dummy_wrb, stopped = false; wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); - copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb); + copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); if (copied) { /* record the sent skb in the sent_skb table */ - BUG_ON(tx_obj->sent_skb_list[start]); - tx_obj->sent_skb_list[start] = skb; + BUG_ON(txo->sent_skb_list[start]); + txo->sent_skb_list[start] = skb; /* Ensure txq has space for the next skb; Else stop the queue * *BEFORE* ringing the tx doorbell, so that we serialze the @@ -774,13 +779,13 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, atomic_add(wrb_cnt, &txq->used); if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= txq->len) { - netif_stop_queue(netdev); + netif_stop_subqueue(netdev, skb_get_queue_mapping(skb)); stopped = true; } be_txq_notify(adapter, txq->id, wrb_cnt); - be_tx_stats_update(adapter, wrb_cnt, copied, + be_tx_stats_update(txo, wrb_cnt, copied, skb_shinfo(skb)->gso_segs, stopped); } else { txq->head = start; @@ -842,13 +847,6 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) return status; } -static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - adapter->vlan_grp = grp; -} - static void be_vlan_add_vid(struct net_device *netdev, u16 vid) { struct be_adapter *adapter = netdev_priv(netdev); @@ -867,7 +865,6 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) struct be_adapter *adapter = netdev_priv(netdev); adapter->vlans_added--; - vlan_group_set_device(adapter->vlan_grp, vid, NULL); if (!be_physfn(adapter)) return; @@ -1177,8 +1174,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN); if (unlikely(!skb)) { - if (net_ratelimit()) - dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); + rxo->stats.rx_dropped++; be_rx_compl_discard(adapter, rxo, rxcp); return; } @@ -1196,16 +1192,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb->rxhash = rxcp->rss_hash; - if (unlikely(rxcp->vlanf)) { - if (!adapter->vlan_grp || adapter->vlans_added == 0) { - kfree_skb(skb); - return; - } - vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, - rxcp->vlan_tag); - } else { - netif_receive_skb(skb); - } + if (unlikely(rxcp->vlanf)) + __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag); + + netif_receive_skb(skb); } /* Process the RX completion indicated by rxcp when GRO is enabled */ @@ -1259,11 +1249,10 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, if (adapter->netdev->features & NETIF_F_RXHASH) skb->rxhash = rxcp->rss_hash; - if (likely(!rxcp->vlanf)) - napi_gro_frags(&eq_obj->napi); - else - vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, - rxcp->vlan_tag); + if (unlikely(rxcp->vlanf)) + __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag); + + napi_gro_frags(&eq_obj->napi); } static void be_parse_rx_compl_v1(struct be_adapter *adapter, @@ -1459,11 +1448,12 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) return txcp; } -static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index) +static u16 be_tx_compl_process(struct be_adapter *adapter, + struct be_tx_obj *txo, u16 last_index) { - struct be_queue_info *txq = &adapter->tx_obj.q; + struct be_queue_info *txq = &txo->q; struct be_eth_wrb *wrb; - struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; + struct sk_buff **sent_skbs = txo->sent_skb_list; struct sk_buff *sent_skb; u16 cur_index, num_wrbs = 1; /* account for hdr wrb */ bool unmap_skb_hdr = true; @@ -1504,7 +1494,8 @@ static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) } static int event_handle(struct be_adapter *adapter, - struct be_eq_obj *eq_obj) + struct be_eq_obj *eq_obj, + bool rearm) { struct be_eq_entry *eqe; u16 num = 0; @@ -1517,7 +1508,10 @@ static int event_handle(struct be_adapter *adapter, /* Deal with any spurious interrupts that come * without events */ - be_eq_notify(adapter, eq_obj->q.id, true, true, num); + if (!num) + rearm = true; + + be_eq_notify(adapter, eq_obj->q.id, rearm, true, num); if (num) napi_schedule(&eq_obj->napi); @@ -1563,15 +1557,17 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo) memset(page_info, 0, sizeof(*page_info)); } BUG_ON(atomic_read(&rxq->used)); + rxq->tail = rxq->head = 0; } -static void be_tx_compl_clean(struct be_adapter *adapter) +static void be_tx_compl_clean(struct be_adapter *adapter, + struct be_tx_obj *txo) { - struct be_queue_info *tx_cq = &adapter->tx_obj.cq; - struct be_queue_info *txq = &adapter->tx_obj.q; + struct be_queue_info *tx_cq = &txo->cq; + struct be_queue_info *txq = &txo->q; struct be_eth_tx_compl *txcp; u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; - struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; + struct sk_buff **sent_skbs = txo->sent_skb_list; struct sk_buff *sent_skb; bool dummy_wrb; @@ -1580,7 +1576,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); - num_wrbs += be_tx_compl_process(adapter, end_idx); + num_wrbs += be_tx_compl_process(adapter, txo, end_idx); cmpl++; } if (cmpl) { @@ -1607,7 +1603,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) index_adv(&end_idx, wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1, txq->len); - num_wrbs = be_tx_compl_process(adapter, end_idx); + num_wrbs = be_tx_compl_process(adapter, txo, end_idx); atomic_sub(num_wrbs, &txq->used); } } @@ -1666,16 +1662,20 @@ err: static void be_tx_queues_destroy(struct be_adapter *adapter) { struct be_queue_info *q; + struct be_tx_obj *txo; + u8 i; - q = &adapter->tx_obj.q; - if (q->created) - be_cmd_q_destroy(adapter, q, QTYPE_TXQ); - be_queue_free(adapter, q); + for_all_tx_queues(adapter, txo, i) { + q = &txo->q; + if (q->created) + be_cmd_q_destroy(adapter, q, QTYPE_TXQ); + be_queue_free(adapter, q); - q = &adapter->tx_obj.cq; - if (q->created) - be_cmd_q_destroy(adapter, q, QTYPE_CQ); - be_queue_free(adapter, q); + q = &txo->cq; + if (q->created) + be_cmd_q_destroy(adapter, q, QTYPE_CQ); + be_queue_free(adapter, q); + } /* Clear any residual events */ be_eq_clean(adapter, &adapter->tx_eq); @@ -1686,56 +1686,48 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_queue_free(adapter, q); } +/* One TX event queue is shared by all TX compl qs */ static int be_tx_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq, *q, *cq; + struct be_tx_obj *txo; + u8 i; adapter->tx_eq.max_eqd = 0; adapter->tx_eq.min_eqd = 0; adapter->tx_eq.cur_eqd = 96; adapter->tx_eq.enable_aic = false; - /* Alloc Tx Event queue */ + eq = &adapter->tx_eq.q; - if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, sizeof(struct be_eq_entry))) + if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, + sizeof(struct be_eq_entry))) return -1; - /* Ask BE to create Tx Event queue */ if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) - goto tx_eq_free; - + goto err; adapter->tx_eq.eq_idx = adapter->eq_next_idx++; - - /* Alloc TX eth compl queue */ - cq = &adapter->tx_obj.cq; - if (be_queue_alloc(adapter, cq, TX_CQ_LEN, + for_all_tx_queues(adapter, txo, i) { + cq = &txo->cq; + if (be_queue_alloc(adapter, cq, TX_CQ_LEN, sizeof(struct be_eth_tx_compl))) - goto tx_eq_destroy; + goto err; - /* Ask BE to create Tx eth compl queue */ - if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) - goto tx_cq_free; + if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) + goto err; - /* Alloc TX eth queue */ - q = &adapter->tx_obj.q; - if (be_queue_alloc(adapter, q, TX_Q_LEN, sizeof(struct be_eth_wrb))) - goto tx_cq_destroy; + q = &txo->q; + if (be_queue_alloc(adapter, q, TX_Q_LEN, + sizeof(struct be_eth_wrb))) + goto err; - /* Ask BE to create Tx eth queue */ - if (be_cmd_txq_create(adapter, q, cq)) - goto tx_q_free; + if (be_cmd_txq_create(adapter, q, cq)) + goto err; + } return 0; -tx_q_free: - be_queue_free(adapter, q); -tx_cq_destroy: - be_cmd_q_destroy(adapter, cq, QTYPE_CQ); -tx_cq_free: - be_queue_free(adapter, cq); -tx_eq_destroy: - be_cmd_q_destroy(adapter, eq, QTYPE_EQ); -tx_eq_free: - be_queue_free(adapter, eq); +err: + be_tx_queues_destroy(adapter); return -1; } @@ -1746,36 +1738,23 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) int i; for_all_rx_queues(adapter, rxo, i) { - q = &rxo->q; - if (q->created) { - be_cmd_q_destroy(adapter, q, QTYPE_RXQ); - /* After the rxq is invalidated, wait for a grace time - * of 1ms for all dma to end and the flush compl to - * arrive - */ - mdelay(1); - be_rx_q_clean(adapter, rxo); - } - be_queue_free(adapter, q); + be_queue_free(adapter, &rxo->q); q = &rxo->cq; if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); - /* Clear any residual events */ q = &rxo->rx_eq.q; - if (q->created) { - be_eq_clean(adapter, &rxo->rx_eq); + if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_EQ); - } be_queue_free(adapter, q); } } static u32 be_num_rxqs_want(struct be_adapter *adapter) { - if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && + if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { return 1 + MAX_RSS_QS; /* one default non-RSS queue */ } else { @@ -1827,30 +1806,14 @@ static int be_rx_queues_create(struct be_adapter *adapter) rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); if (rc) goto err; - /* Rx Q */ + + /* Rx Q - will be created in be_open() */ q = &rxo->q; rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d)); if (rc) goto err; - rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, - BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, - (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id); - if (rc) - goto err; - } - - if (be_multi_rxq(adapter)) { - u8 rsstable[MAX_RSS_QS]; - - for_all_rss_queues(adapter, rxo, i) - rsstable[i] = rxo->rss_id; - - rc = be_cmd_rss_config(adapter, rsstable, - adapter->num_rx_qs - 1); - if (rc) - goto err; } return 0; @@ -1876,10 +1839,10 @@ static irqreturn_t be_intx(int irq, void *dev) if (lancer_chip(adapter)) { if (event_peek(&adapter->tx_eq)) - tx = event_handle(adapter, &adapter->tx_eq); + tx = event_handle(adapter, &adapter->tx_eq, false); for_all_rx_queues(adapter, rxo, i) { if (event_peek(&rxo->rx_eq)) - rx |= event_handle(adapter, &rxo->rx_eq); + rx |= event_handle(adapter, &rxo->rx_eq, true); } if (!(tx || rx)) @@ -1892,11 +1855,11 @@ static irqreturn_t be_intx(int irq, void *dev) return IRQ_NONE; if ((1 << adapter->tx_eq.eq_idx & isr)) - event_handle(adapter, &adapter->tx_eq); + event_handle(adapter, &adapter->tx_eq, false); for_all_rx_queues(adapter, rxo, i) { if ((1 << rxo->rx_eq.eq_idx & isr)) - event_handle(adapter, &rxo->rx_eq); + event_handle(adapter, &rxo->rx_eq, true); } } @@ -1908,7 +1871,7 @@ static irqreturn_t be_msix_rx(int irq, void *dev) struct be_rx_obj *rxo = dev; struct be_adapter *adapter = rxo->adapter; - event_handle(adapter, &rxo->rx_eq); + event_handle(adapter, &rxo->rx_eq, true); return IRQ_HANDLED; } @@ -1917,7 +1880,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(adapter, &adapter->tx_eq); + event_handle(adapter, &adapter->tx_eq, false); return IRQ_HANDLED; } @@ -1978,45 +1941,48 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); struct be_adapter *adapter = container_of(tx_eq, struct be_adapter, tx_eq); - struct be_queue_info *txq = &adapter->tx_obj.q; - struct be_queue_info *tx_cq = &adapter->tx_obj.cq; + struct be_tx_obj *txo; struct be_eth_tx_compl *txcp; - int tx_compl = 0, mcc_compl, status = 0; - u16 end_idx, num_wrbs = 0; + int tx_compl, mcc_compl, status = 0; + u8 i; + u16 num_wrbs; + + for_all_tx_queues(adapter, txo, i) { + tx_compl = 0; + num_wrbs = 0; + while ((txcp = be_tx_compl_get(&txo->cq))) { + num_wrbs += be_tx_compl_process(adapter, txo, + AMAP_GET_BITS(struct amap_eth_tx_compl, + wrb_index, txcp)); + tx_compl++; + } + if (tx_compl) { + be_cq_notify(adapter, txo->cq.id, true, tx_compl); - while ((txcp = be_tx_compl_get(tx_cq))) { - end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, - wrb_index, txcp); - num_wrbs += be_tx_compl_process(adapter, end_idx); - tx_compl++; + atomic_sub(num_wrbs, &txo->q.used); + + /* As Tx wrbs have been freed up, wake up netdev queue + * if it was stopped due to lack of tx wrbs. */ + if (__netif_subqueue_stopped(adapter->netdev, i) && + atomic_read(&txo->q.used) < txo->q.len / 2) { + netif_wake_subqueue(adapter->netdev, i); + } + + adapter->drv_stats.be_tx_events++; + txo->stats.be_tx_compl += tx_compl; + } } mcc_compl = be_process_mcc(adapter, &status); - napi_complete(napi); - if (mcc_compl) { struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl); } - if (tx_compl) { - be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl); - - atomic_sub(num_wrbs, &txq->used); - - /* As Tx wrbs have been freed up, wake up netdev queue if - * it was stopped due to lack of tx wrbs. - */ - if (netif_queue_stopped(adapter->netdev) && - atomic_read(&txq->used) < txq->len / 2) { - netif_wake_queue(adapter->netdev); - } - - tx_stats(adapter)->be_tx_events++; - tx_stats(adapter)->be_tx_compl += tx_compl; - } + napi_complete(napi); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); return 1; } @@ -2065,6 +2031,7 @@ static void be_worker(struct work_struct *work) struct be_adapter *adapter = container_of(work, struct be_adapter, work.work); struct be_rx_obj *rxo; + struct be_tx_obj *txo; int i; if (!adapter->ue_detected && !lancer_chip(adapter)) @@ -2092,7 +2059,9 @@ static void be_worker(struct work_struct *work) else be_cmd_get_stats(adapter, &adapter->stats_cmd); } - be_tx_rate_update(adapter); + + for_all_tx_queues(adapter, txo, i) + be_tx_rate_update(txo); for_all_rx_queues(adapter, rxo, i) { be_rx_rate_update(rxo); @@ -2290,10 +2259,36 @@ done: adapter->isr_registered = false; } +static void be_rx_queues_clear(struct be_adapter *adapter) +{ + struct be_queue_info *q; + struct be_rx_obj *rxo; + int i; + + for_all_rx_queues(adapter, rxo, i) { + q = &rxo->q; + if (q->created) { + be_cmd_rxq_destroy(adapter, q); + /* After the rxq is invalidated, wait for a grace time + * of 1ms for all dma to end and the flush compl to + * arrive + */ + mdelay(1); + be_rx_q_clean(adapter, rxo); + } + + /* Clear any residual events */ + q = &rxo->rx_eq.q; + if (q->created) + be_eq_clean(adapter, &rxo->rx_eq); + } +} + static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); struct be_rx_obj *rxo; + struct be_tx_obj *txo; struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec, i; @@ -2311,10 +2306,11 @@ static int be_close(struct net_device *netdev) napi_disable(&tx_eq->napi); if (lancer_chip(adapter)) { - be_cq_notify(adapter, adapter->tx_obj.cq.id, false, 0); be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0); for_all_rx_queues(adapter, rxo, i) be_cq_notify(adapter, rxo->cq.id, false, 0); + for_all_tx_queues(adapter, txo, i) + be_cq_notify(adapter, txo->cq.id, false, 0); } if (msix_enabled(adapter)) { @@ -2333,8 +2329,43 @@ static int be_close(struct net_device *netdev) /* Wait for all pending tx completions to arrive so that * all tx skbs are freed. */ - be_tx_compl_clean(adapter); + for_all_tx_queues(adapter, txo, i) + be_tx_compl_clean(adapter, txo); + + be_rx_queues_clear(adapter); + return 0; +} + +static int be_rx_queues_setup(struct be_adapter *adapter) +{ + struct be_rx_obj *rxo; + int rc, i; + u8 rsstable[MAX_RSS_QS]; + + for_all_rx_queues(adapter, rxo, i) { + rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, + rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE, + adapter->if_handle, + (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id); + if (rc) + return rc; + } + + if (be_multi_rxq(adapter)) { + for_all_rss_queues(adapter, rxo, i) + rsstable[i] = rxo->rss_id; + rc = be_cmd_rss_config(adapter, rsstable, + adapter->num_rx_qs - 1); + if (rc) + return rc; + } + + /* First time posting */ + for_all_rx_queues(adapter, rxo, i) { + be_post_rx_frags(rxo, GFP_KERNEL); + napi_enable(&rxo->rx_eq.napi); + } return 0; } @@ -2348,10 +2379,10 @@ static int be_open(struct net_device *netdev) u8 mac_speed; u16 link_speed; - for_all_rx_queues(adapter, rxo, i) { - be_post_rx_frags(rxo, GFP_KERNEL); - napi_enable(&rxo->rx_eq.napi); - } + status = be_rx_queues_setup(adapter); + if (status) + goto err; + napi_enable(&tx_eq->napi); be_irq_register(adapter); @@ -2480,6 +2511,8 @@ static int be_setup(struct be_adapter *adapter) int status; u8 mac[ETH_ALEN]; + be_cmd_req_native_mode(adapter); + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST; @@ -2539,6 +2572,9 @@ static int be_setup(struct be_adapter *adapter) if (status != 0) goto tx_qs_destroy; + /* Allow all priorities by default. A GRP5 evt may modify this */ + adapter->vlan_prio_bmap = 0xff; + status = be_mcc_queues_create(adapter); if (status != 0) goto rx_qs_destroy; @@ -2584,6 +2620,8 @@ static int be_clear(struct be_adapter *adapter) be_cmd_if_destroy(adapter, adapter->if_handle, 0); + adapter->be3_native = 0; + /* tell fw we're done with firing cmds */ be_cmd_fw_clean(adapter); return 0; @@ -2901,7 +2939,6 @@ static struct net_device_ops be_netdev_ops = { .ndo_set_mac_address = be_mac_addr_set, .ndo_change_mtu = be_change_mtu, .ndo_validate_addr = eth_validate_addr, - .ndo_vlan_rx_register = be_vlan_register, .ndo_vlan_rx_add_vid = be_vlan_add_vid, .ndo_vlan_rx_kill_vid = be_vlan_rem_vid, .ndo_set_vf_mac = be_set_vf_mac, @@ -2925,12 +2962,9 @@ static void be_netdev_init(struct net_device *netdev) netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | + netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (lancer_chip(adapter)) - netdev->vlan_features |= NETIF_F_TSO6; - netdev->flags |= IFF_MULTICAST; /* Default settings for Rx and Tx flow control */ @@ -3185,7 +3219,16 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - be_cmd_check_native_mode(adapter); + if ((num_vfs && adapter->sriov_enabled) || + (adapter->function_mode & 0x400) || + lancer_chip(adapter) || !be_physfn(adapter)) { + adapter->num_tx_qs = 1; + netif_set_real_num_tx_queues(adapter->netdev, + adapter->num_tx_qs); + } else { + adapter->num_tx_qs = MAX_TX_QS; + } + return 0; } @@ -3288,7 +3331,7 @@ static int __devinit be_probe(struct pci_dev *pdev, goto disable_dev; pci_set_master(pdev); - netdev = alloc_etherdev(sizeof(struct be_adapter)); + netdev = alloc_etherdev_mq(sizeof(struct be_adapter), MAX_TX_QS); if (netdev == NULL) { status = -ENOMEM; goto rel_reg; @@ -3360,6 +3403,12 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto stats_clean; + /* The INTR bit may be set in the card when probed by a kdump kernel + * after a crash. + */ + if (!lancer_chip(adapter)) + be_intr_set(adapter, false); + be_msix_enable(adapter); INIT_DELAYED_WORK(&adapter->work, be_worker); @@ -3396,6 +3445,7 @@ static int __devinit be_probe(struct pci_dev *pdev, } dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); + schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; |