diff options
author | Sathya Perla <sathya.perla@emulex.com> | 2011-06-12 20:01:58 +0000 |
---|---|---|
committer | David S. Miller <davem@conan.davemloft.net> | 2011-06-16 23:02:04 -0400 |
commit | 3c8def9776c3d4636291432522ea312f7a44be95 (patch) | |
tree | eec2cc837656dd9ee2a5e16dd7648d6a18e592d1 /drivers/net/benet/be_main.c | |
parent | 15b4d93f0316caec44e07255c1d73bde4fac12e4 (diff) |
be2net: support multiple TX queues
This patch provides support for multiple TX queues.
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@conan.davemloft.net>
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 227 |
1 files changed, 126 insertions, 101 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6ddaa34121e..c4f564cd745 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -427,6 +427,7 @@ 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; int i; memset(dev_stats, 0, sizeof(*dev_stats)); @@ -450,8 +451,10 @@ void netdev_stats_update(struct be_adapter *adapter) } } - dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts; - dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes; + for_all_tx_queues(adapter, txo, i) { + dev_stats->tx_packets += tx_stats(txo)->be_tx_pkts; + dev_stats->tx_bytes += tx_stats(txo)->be_tx_bytes; + } /* bad pkts received */ dev_stats->rx_errors = drvs->rx_crc_errors + @@ -554,9 +557,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 +578,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; @@ -682,14 +686,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 +756,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 +777,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; @@ -1459,11 +1462,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 +1508,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 +1522,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); @@ -1565,13 +1573,14 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo) BUG_ON(atomic_read(&rxq->used)); } -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 +1589,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 +1616,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 +1675,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 +1699,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; } @@ -1876,10 +1881,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 +1897,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 +1913,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 +1922,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 +1983,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); + + atomic_sub(num_wrbs, &txo->q.used); - 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++; + /* 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 +2073,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 +2101,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); @@ -2294,6 +2305,7 @@ 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 +2323,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,7 +2346,8 @@ 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); return 0; } @@ -3183,6 +3197,17 @@ static int be_get_config(struct be_adapter *adapter) 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; } @@ -3285,7 +3310,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; |