diff --git a/debian/changelog b/debian/changelog index f62317f88..c137f1bae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -52,6 +52,10 @@ linux (3.2.25-1) UNRELEASED; urgency=low (Closes: #682726) * debugfs: Add mode, uid and gid mount options; set default mode to 700 (Closes: #681418) + * net: new counter for tx_timeout errors in sysfs + * net: Add byte queue limits (bql) for reduced buffer-bloat + * bnx2,bnx2x,e1000e,forcedeth,igb,ixgbe,r8169,sfc,skge,sky2,tg3: + Add support for bql -- Ben Hutchings Tue, 24 Jul 2012 02:20:37 +0100 diff --git a/debian/patches/features/all/bql/bnx2-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/bnx2-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..bf47d2154 --- /dev/null +++ b/debian/patches/features/all/bql/bnx2-support-for-byte-queue-limits.patch @@ -0,0 +1,60 @@ +From: Eric Dumazet +Date: Tue, 29 Nov 2011 11:53:05 +0000 +Subject: bnx2: Support for byte queue limits + +commit e98319098885859e34c23cc8a130b6b8668a6abe upstream. + +Changes to bnx2 to use byte queue limits. + +Signed-off-by: Eric Dumazet +CC: Tom Herbert +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bnx2.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c +index d573169..787e175 100644 +--- a/drivers/net/ethernet/broadcom/bnx2.c ++++ b/drivers/net/ethernet/broadcom/bnx2.c +@@ -2810,6 +2810,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + u16 hw_cons, sw_cons, sw_ring_cons; + int tx_pkt = 0, index; ++ unsigned int tx_bytes = 0; + struct netdev_queue *txq; + + index = (bnapi - bp->bnx2_napi); +@@ -2864,6 +2865,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) + + sw_cons = NEXT_TX_BD(sw_cons); + ++ tx_bytes += skb->len; + dev_kfree_skb(skb); + tx_pkt++; + if (tx_pkt == budget) +@@ -2873,6 +2875,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) + hw_cons = bnx2_get_hw_tx_cons(bnapi); + } + ++ netdev_tx_completed_queue(txq, tx_pkt, tx_bytes); + txr->hw_tx_cons = hw_cons; + txr->tx_cons = sw_cons; + +@@ -5393,6 +5396,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp) + } + dev_kfree_skb(skb); + } ++ netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i)); + } + } + +@@ -6546,6 +6550,8 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) + } + txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END; + ++ netdev_tx_sent_queue(txq, skb->len); ++ + prod = NEXT_TX_BD(prod); + txr->tx_prod_bseq += skb->len; + diff --git a/debian/patches/features/all/bql/bnx2x-fix-crash-while-ethtool-t.patch b/debian/patches/features/all/bql/bnx2x-fix-crash-while-ethtool-t.patch new file mode 100644 index 000000000..ca36518c0 --- /dev/null +++ b/debian/patches/features/all/bql/bnx2x-fix-crash-while-ethtool-t.patch @@ -0,0 +1,40 @@ +From: Dmitry Kravkov +Date: Tue, 6 Dec 2011 02:05:12 +0000 +Subject: bnx2x: fix crash while ethtool -t + +commit 73dbb5e1627a35c8ab81f3813c096e9e7aaabaaa upstream. + +commit 2df1a70aaf70e8dff11b89b938a5f317556ee640 "bnx2x: Support +for byte queue limits" has introduced an asymmetry in usage of +netdev_tx_completed_queue and netdev_tx_sent_queue. Missing +call to netdev_tx_sent_queue causes the crash during ethtool -t. + +The patch adds the missing call. + +Signed-off-by: Dmitry Kravkov +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +[bwh: Backported to 3.2: adjust context] +--- + drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +@@ -1740,6 +1740,7 @@ + struct sw_rx_bd *rx_buf; + u16 len; + int rc = -ENODEV; ++ struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, txdata->txq_index); + + /* check the loopback mode */ + switch (loopback_mode) { +@@ -1784,6 +1785,8 @@ + tx_start_idx = le16_to_cpu(*txdata->tx_cons_sb); + rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb); + ++ netdev_tx_sent_queue(txq, skb->len); ++ + pkt_prod = txdata->tx_pkt_prod++; + tx_buf = &txdata->tx_buf_ring[TX_BD(pkt_prod)]; + tx_buf->first_bd = txdata->tx_bd_prod; diff --git a/debian/patches/features/all/bql/bnx2x-remove-unused-variable.patch b/debian/patches/features/all/bql/bnx2x-remove-unused-variable.patch new file mode 100644 index 000000000..c757a3245 --- /dev/null +++ b/debian/patches/features/all/bql/bnx2x-remove-unused-variable.patch @@ -0,0 +1,32 @@ +From: Dmitry Kravkov +Date: Sun, 13 Nov 2011 04:34:23 +0000 +Subject: bnx2x: remove unused variable + +commit ad756594a8d88ffc048d14b8d5c02971e08856ce upstream. + +Signed-off-by: Dmitry Kravkov +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +index 1ace946..f946a6e 100644 +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +@@ -1094,13 +1094,11 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp) + for_each_cos_in_tx_queue(fp, cos) { + struct bnx2x_fp_txdata *txdata = &fp->txdata[cos]; + +- u16 bd_cons = txdata->tx_bd_cons; + u16 sw_prod = txdata->tx_pkt_prod; + u16 sw_cons = txdata->tx_pkt_cons; + + while (sw_cons != sw_prod) { +- bd_cons = bnx2x_free_tx_pkt(bp, txdata, +- TX_BD(sw_cons)); ++ bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons)); + sw_cons++; + } + } diff --git a/debian/patches/features/all/bql/bnx2x-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/bnx2x-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..b2adc7f4a --- /dev/null +++ b/debian/patches/features/all/bql/bnx2x-support-for-byte-queue-limits.patch @@ -0,0 +1,111 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:37 +0000 +Subject: bnx2x: Support for byte queue limits + +commit 2df1a70aaf70e8dff11b89b938a5f317556ee640 upstream. + +Changes to bnx2x to use byte queue limits. + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 26 +++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +index 8336c78..42ce566 100644 +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +@@ -102,7 +102,8 @@ int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ + * return idx of last bd freed + */ + static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, +- u16 idx) ++ u16 idx, unsigned int *pkts_compl, ++ unsigned int *bytes_compl) + { + struct sw_tx_bd *tx_buf = &txdata->tx_buf_ring[idx]; + struct eth_tx_start_bd *tx_start_bd; +@@ -159,6 +160,10 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, + + /* release skb */ + WARN_ON(!skb); ++ if (skb) { ++ (*pkts_compl)++; ++ (*bytes_compl) += skb->len; ++ } + dev_kfree_skb_any(skb); + tx_buf->first_bd = 0; + tx_buf->skb = NULL; +@@ -170,6 +175,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata) + { + struct netdev_queue *txq; + u16 hw_cons, sw_cons, bd_cons = txdata->tx_bd_cons; ++ unsigned int pkts_compl = 0, bytes_compl = 0; + + #ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) +@@ -189,10 +195,14 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata) + " pkt_cons %u\n", + txdata->txq_index, hw_cons, sw_cons, pkt_cons); + +- bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons); ++ bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons, ++ &pkts_compl, &bytes_compl); ++ + sw_cons++; + } + ++ netdev_tx_completed_queue(txq, pkts_compl, bytes_compl); ++ + txdata->tx_pkt_cons = sw_cons; + txdata->tx_bd_cons = bd_cons; + +@@ -1077,14 +1087,18 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp) + struct bnx2x_fastpath *fp = &bp->fp[i]; + for_each_cos_in_tx_queue(fp, cos) { + struct bnx2x_fp_txdata *txdata = &fp->txdata[cos]; ++ unsigned pkts_compl = 0, bytes_compl = 0; + + u16 sw_prod = txdata->tx_pkt_prod; + u16 sw_cons = txdata->tx_pkt_cons; + + while (sw_cons != sw_prod) { +- bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons)); ++ bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons), ++ &pkts_compl, &bytes_compl); + sw_cons++; + } ++ netdev_tx_reset_queue( ++ netdev_get_tx_queue(bp->dev, txdata->txq_index)); + } + } + } +@@ -2788,6 +2802,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) + mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { ++ unsigned int pkts_compl = 0, bytes_compl = 0; + + DP(NETIF_MSG_TX_QUEUED, "Unable to map page - " + "dropping packet...\n"); +@@ -2799,7 +2814,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) + */ + first_bd->nbd = cpu_to_le16(nbd); + bnx2x_free_tx_pkt(bp, txdata, +- TX_BD(txdata->tx_pkt_prod)); ++ TX_BD(txdata->tx_pkt_prod), ++ &pkts_compl, &bytes_compl); + return NETDEV_TX_OK; + } + +@@ -2860,6 +2876,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) + pbd_e2->parsing_data); + DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod); + ++ netdev_tx_sent_queue(txq, skb->len); ++ + txdata->tx_pkt_prod++; + /* + * Make sure that the BD data is updated before updating the producer diff --git a/debian/patches/features/all/bql/bql-avoid-possible-inconsistent-calculation.patch b/debian/patches/features/all/bql/bql-avoid-possible-inconsistent-calculation.patch new file mode 100644 index 000000000..bf20bd252 --- /dev/null +++ b/debian/patches/features/all/bql/bql-avoid-possible-inconsistent-calculation.patch @@ -0,0 +1,55 @@ +From: Hiroaki SHIMODA +Date: Wed, 30 May 2012 12:25:37 +0000 +Subject: bql: Avoid possible inconsistent calculation. + +commit 914bec1011a25f65cdc94988a6f974bfb9a3c10d upstream. + +dql->num_queued could change while processing dql_completed(). +To provide consistent calculation, added an on stack variable. + +Signed-off-by: Hiroaki SHIMODA +Cc: Tom Herbert +Cc: Eric Dumazet +Cc: Denys Fedoryshchenko +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + lib/dynamic_queue_limits.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +index 0fafa77..0777c5a 100644 +--- a/lib/dynamic_queue_limits.c ++++ b/lib/dynamic_queue_limits.c +@@ -17,16 +17,18 @@ + void dql_completed(struct dql *dql, unsigned int count) + { + unsigned int inprogress, prev_inprogress, limit; +- unsigned int ovlimit, completed; ++ unsigned int ovlimit, completed, num_queued; + bool all_prev_completed; + ++ num_queued = ACCESS_ONCE(dql->num_queued); ++ + /* Can't complete more than what's in queue */ +- BUG_ON(count > dql->num_queued - dql->num_completed); ++ BUG_ON(count > num_queued - dql->num_completed); + + completed = dql->num_completed + count; + limit = dql->limit; +- ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit); +- inprogress = dql->num_queued - completed; ++ ovlimit = POSDIFF(num_queued - dql->num_completed, limit); ++ inprogress = num_queued - completed; + prev_inprogress = dql->prev_num_queued - dql->num_completed; + all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued); + +@@ -106,7 +108,7 @@ void dql_completed(struct dql *dql, unsigned int count) + dql->prev_ovlimit = ovlimit; + dql->prev_last_obj_cnt = dql->last_obj_cnt; + dql->num_completed = completed; +- dql->prev_num_queued = dql->num_queued; ++ dql->prev_num_queued = num_queued; + } + EXPORT_SYMBOL(dql_completed); + diff --git a/debian/patches/features/all/bql/bql-avoid-unneeded-limit-decrement.patch b/debian/patches/features/all/bql/bql-avoid-unneeded-limit-decrement.patch new file mode 100644 index 000000000..1043044e4 --- /dev/null +++ b/debian/patches/features/all/bql/bql-avoid-unneeded-limit-decrement.patch @@ -0,0 +1,70 @@ +From: Hiroaki SHIMODA +Date: Wed, 30 May 2012 12:25:19 +0000 +Subject: bql: Avoid unneeded limit decrement. + +commit 25426b794efdc70dde7fd3134dc56fac3e7d562d upstream. + +When below pattern is observed, + + TIME + dql_queued() dql_completed() | + a) initial state | + | + b) X bytes queued V + + c) Y bytes queued + d) X bytes completed + e) Z bytes queued + f) Y bytes completed + +a) dql->limit has already some value and there is no in-flight packet. +b) X bytes queued. +c) Y bytes queued and excess limit. +d) X bytes completed and dql->prev_ovlimit is set and also + dql->prev_num_queued is set Y. +e) Z bytes queued. +f) Y bytes completed. inprogress and prev_inprogress are true. + +At f), according to the comment, all_prev_completed becomes +true and limit should be increased. But POSDIFF() ignores +(completed == dql->prev_num_queued) case, so limit is decreased. + +Signed-off-by: Hiroaki SHIMODA +Cc: Tom Herbert +Cc: Eric Dumazet +Cc: Denys Fedoryshchenko +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + lib/dynamic_queue_limits.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +index c87eb76..0fafa77 100644 +--- a/lib/dynamic_queue_limits.c ++++ b/lib/dynamic_queue_limits.c +@@ -11,12 +11,14 @@ + #include + + #define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0) ++#define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0) + + /* Records completed count and recalculates the queue limit */ + void dql_completed(struct dql *dql, unsigned int count) + { + unsigned int inprogress, prev_inprogress, limit; +- unsigned int ovlimit, all_prev_completed, completed; ++ unsigned int ovlimit, completed; ++ bool all_prev_completed; + + /* Can't complete more than what's in queue */ + BUG_ON(count > dql->num_queued - dql->num_completed); +@@ -26,7 +28,7 @@ void dql_completed(struct dql *dql, unsigned int count) + ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit); + inprogress = dql->num_queued - completed; + prev_inprogress = dql->prev_num_queued - dql->num_completed; +- all_prev_completed = POSDIFF(completed, dql->prev_num_queued); ++ all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued); + + if ((ovlimit && !inprogress) || + (dql->prev_ovlimit && all_prev_completed)) { diff --git a/debian/patches/features/all/bql/bql-byte-queue-limits.patch b/debian/patches/features/all/bql/bql-byte-queue-limits.patch new file mode 100644 index 000000000..29057e621 --- /dev/null +++ b/debian/patches/features/all/bql/bql-byte-queue-limits.patch @@ -0,0 +1,325 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:09 +0000 +Subject: bql: Byte queue limits + +commit 114cf5802165ee93e3ab461c9c505cd94a08b800 upstream. + +Networking stack support for byte queue limits, uses dynamic queue +limits library. Byte queue limits are maintained per transmit queue, +and a dql structure has been added to netdev_queue structure for this +purpose. + +Configuration of bql is in the tx- sysfs directory for the queue +under the byte_queue_limits directory. Configuration includes: +limit_min, bql minimum limit +limit_max, bql maximum limit +hold_time, bql slack hold time + +Also under the directory are: +limit, current byte limit +inflight, current number of bytes on the queue + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +[bwh: Adjust context in net/Kconfig for 3.2] +--- + include/linux/netdevice.h | 32 ++++++++++- + net/Kconfig | 6 ++ + net/core/dev.c | 3 + + net/core/net-sysfs.c | 140 ++++++++++++++++++++++++++++++++++++++++++--- + 4 files changed, 172 insertions(+), 9 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -540,7 +541,6 @@ + */ + struct net_device *dev; + struct Qdisc *qdisc; +- unsigned long state; + struct Qdisc *qdisc_sleeping; + #ifdef CONFIG_SYSFS + struct kobject kobj; +@@ -563,6 +563,12 @@ + * (/sys/class/net/DEV/Q/trans_timeout) + */ + unsigned long trans_timeout; ++ ++ unsigned long state; ++ ++#ifdef CONFIG_BQL ++ struct dql dql; ++#endif + } ____cacheline_aligned_in_smp; + + static inline int netdev_queue_numa_node_read(const struct netdev_queue *q) +@@ -1926,6 +1932,15 @@ + static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue, + unsigned int bytes) + { ++#ifdef CONFIG_BQL ++ dql_queued(&dev_queue->dql, bytes); ++ if (unlikely(dql_avail(&dev_queue->dql) < 0)) { ++ set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state); ++ if (unlikely(dql_avail(&dev_queue->dql) >= 0)) ++ clear_bit(__QUEUE_STATE_STACK_XOFF, ++ &dev_queue->state); ++ } ++#endif + } + + static inline void netdev_sent_queue(struct net_device *dev, unsigned int bytes) +@@ -1936,6 +1951,18 @@ + static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue, + unsigned pkts, unsigned bytes) + { ++#ifdef CONFIG_BQL ++ if (likely(bytes)) { ++ dql_completed(&dev_queue->dql, bytes); ++ if (unlikely(test_bit(__QUEUE_STATE_STACK_XOFF, ++ &dev_queue->state) && ++ dql_avail(&dev_queue->dql) >= 0)) { ++ if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, ++ &dev_queue->state)) ++ netif_schedule_queue(dev_queue); ++ } ++ } ++#endif + } + + static inline void netdev_completed_queue(struct net_device *dev, +@@ -1946,6 +1973,9 @@ + + static inline void netdev_tx_reset_queue(struct netdev_queue *q) + { ++#ifdef CONFIG_BQL ++ dql_reset(&q->dql); ++#endif + } + + static inline void netdev_reset_queue(struct net_device *dev_queue) +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -232,6 +232,12 @@ + depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS + default y + ++config BQL ++ boolean ++ depends on SYSFS ++ select DQL ++ default y ++ + config BPF_JIT + bool "enable BPF Just In Time compiler" + depends on HAVE_BPF_JIT +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -5524,6 +5524,9 @@ + queue->xmit_lock_owner = -1; + netdev_queue_numa_node_write(queue, NUMA_NO_NODE); + queue->dev = dev; ++#ifdef CONFIG_BQL ++ dql_init(&queue->dql, HZ); ++#endif + } + + static int netif_alloc_netdev_queues(struct net_device *dev) +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #include "net-sysfs.h" +@@ -845,6 +846,116 @@ + static struct netdev_queue_attribute queue_trans_timeout = + __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL); + ++#ifdef CONFIG_BQL ++/* ++ * Byte queue limits sysfs structures and functions. ++ */ ++static ssize_t bql_show(char *buf, unsigned int value) ++{ ++ return sprintf(buf, "%u\n", value); ++} ++ ++static ssize_t bql_set(const char *buf, const size_t count, ++ unsigned int *pvalue) ++{ ++ unsigned int value; ++ int err; ++ ++ if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) ++ value = DQL_MAX_LIMIT; ++ else { ++ err = kstrtouint(buf, 10, &value); ++ if (err < 0) ++ return err; ++ if (value > DQL_MAX_LIMIT) ++ return -EINVAL; ++ } ++ ++ *pvalue = value; ++ ++ return count; ++} ++ ++static ssize_t bql_show_hold_time(struct netdev_queue *queue, ++ struct netdev_queue_attribute *attr, ++ char *buf) ++{ ++ struct dql *dql = &queue->dql; ++ ++ return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); ++} ++ ++static ssize_t bql_set_hold_time(struct netdev_queue *queue, ++ struct netdev_queue_attribute *attribute, ++ const char *buf, size_t len) ++{ ++ struct dql *dql = &queue->dql; ++ unsigned value; ++ int err; ++ ++ err = kstrtouint(buf, 10, &value); ++ if (err < 0) ++ return err; ++ ++ dql->slack_hold_time = msecs_to_jiffies(value); ++ ++ return len; ++} ++ ++static struct netdev_queue_attribute bql_hold_time_attribute = ++ __ATTR(hold_time, S_IRUGO | S_IWUSR, bql_show_hold_time, ++ bql_set_hold_time); ++ ++static ssize_t bql_show_inflight(struct netdev_queue *queue, ++ struct netdev_queue_attribute *attr, ++ char *buf) ++{ ++ struct dql *dql = &queue->dql; ++ ++ return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); ++} ++ ++static struct netdev_queue_attribute bql_inflight_attribute = ++ __ATTR(inflight, S_IRUGO | S_IWUSR, bql_show_inflight, NULL); ++ ++#define BQL_ATTR(NAME, FIELD) \ ++static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ ++ struct netdev_queue_attribute *attr, \ ++ char *buf) \ ++{ \ ++ return bql_show(buf, queue->dql.FIELD); \ ++} \ ++ \ ++static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ ++ struct netdev_queue_attribute *attr, \ ++ const char *buf, size_t len) \ ++{ \ ++ return bql_set(buf, len, &queue->dql.FIELD); \ ++} \ ++ \ ++static struct netdev_queue_attribute bql_ ## NAME ## _attribute = \ ++ __ATTR(NAME, S_IRUGO | S_IWUSR, bql_show_ ## NAME, \ ++ bql_set_ ## NAME); ++ ++BQL_ATTR(limit, limit) ++BQL_ATTR(limit_max, max_limit) ++BQL_ATTR(limit_min, min_limit) ++ ++static struct attribute *dql_attrs[] = { ++ &bql_limit_attribute.attr, ++ &bql_limit_max_attribute.attr, ++ &bql_limit_min_attribute.attr, ++ &bql_hold_time_attribute.attr, ++ &bql_inflight_attribute.attr, ++ NULL ++}; ++ ++static struct attribute_group dql_group = { ++ .name = "byte_queue_limits", ++ .attrs = dql_attrs, ++}; ++#endif /* CONFIG_BQL */ ++ + #ifdef CONFIG_XPS + static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue) + { +@@ -1096,17 +1207,17 @@ + NULL + }; + +-#ifdef CONFIG_XPS + static void netdev_queue_release(struct kobject *kobj) + { + struct netdev_queue *queue = to_netdev_queue(kobj); + ++#ifdef CONFIG_XPS + xps_queue_release(queue); ++#endif + + memset(kobj, 0, sizeof(*kobj)); + dev_put(queue->dev); + } +-#endif /* CONFIG_XPS */ + + static struct kobj_type netdev_queue_ktype = { + .sysfs_ops = &netdev_queue_sysfs_ops, +@@ -1125,14 +1236,21 @@ + kobj->kset = net->queues_kset; + error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, + "tx-%u", index); +- if (error) { +- kobject_put(kobj); +- return error; +- } ++ if (error) ++ goto exit; ++ ++#ifdef CONFIG_BQL ++ error = sysfs_create_group(kobj, &dql_group); ++ if (error) ++ goto exit; ++#endif + + kobject_uevent(kobj, KOBJ_ADD); + dev_hold(queue->dev); + ++ return 0; ++exit: ++ kobject_put(kobj); + return error; + } + #endif /* CONFIG_SYSFS */ +@@ -1152,8 +1270,14 @@ + } + } + +- while (--i >= new_num) +- kobject_put(&net->_tx[i].kobj); ++ while (--i >= new_num) { ++ struct netdev_queue *queue = net->_tx + i; ++ ++#ifdef CONFIG_BQL ++ sysfs_remove_group(&queue->kobj, &dql_group); ++#endif ++ kobject_put(&queue->kobj); ++ } + + return error; + #else diff --git a/debian/patches/features/all/bql/bql-fix-config_xps-n-build.patch b/debian/patches/features/all/bql/bql-fix-config_xps-n-build.patch new file mode 100644 index 000000000..bbd9f8411 --- /dev/null +++ b/debian/patches/features/all/bql/bql-fix-config_xps-n-build.patch @@ -0,0 +1,29 @@ +From: Eric Dumazet +Date: Sun, 4 Dec 2011 12:38:00 +0000 +Subject: bql: fix CONFIG_XPS=n build + +commit b474ae77609b725098d5a7cc8f69c1c528710d53 upstream. + +netdev_queue_release() should be called even if CONFIG_XPS=n +to properly release device reference. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + net/core/net-sysfs.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c +index 3bf72b6..9d13463 100644 +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -1221,9 +1221,7 @@ static void netdev_queue_release(struct kobject *kobj) + + static struct kobj_type netdev_queue_ktype = { + .sysfs_ops = &netdev_queue_sysfs_ops, +-#ifdef CONFIG_XPS + .release = netdev_queue_release, +-#endif + .default_attrs = netdev_queue_default_attrs, + }; + diff --git a/debian/patches/features/all/bql/bql-fix-inconsistency-between-file-mode-and-attr-method.patch b/debian/patches/features/all/bql/bql-fix-inconsistency-between-file-mode-and-attr-method.patch new file mode 100644 index 000000000..1a747ce5d --- /dev/null +++ b/debian/patches/features/all/bql/bql-fix-inconsistency-between-file-mode-and-attr-method.patch @@ -0,0 +1,30 @@ +From: Hiroaki SHIMODA +Date: Sat, 14 Jan 2012 07:10:21 +0000 +Subject: bql: Fix inconsistency between file mode and attr method. + +commit 795d9a2538b205d9329f34798ec96503a07b7919 upstream. + +There is no store() method for inflight attribute in the +tx-/byte_queue_limits sysfs directory. +So remove S_IWUSR bit. + +Signed-off-by: Hiroaki SHIMODA +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + net/core/net-sysfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c +index f3dbd4f..a1727cd 100644 +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -929,7 +929,7 @@ static ssize_t bql_show_inflight(struct netdev_queue *queue, + } + + static struct netdev_queue_attribute bql_inflight_attribute = +- __ATTR(inflight, S_IRUGO | S_IWUSR, bql_show_inflight, NULL); ++ __ATTR(inflight, S_IRUGO, bql_show_inflight, NULL); + + #define BQL_ATTR(NAME, FIELD) \ + static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ diff --git a/debian/patches/features/all/bql/bql-fix-posdiff-to-integer-overflow-aware.patch b/debian/patches/features/all/bql/bql-fix-posdiff-to-integer-overflow-aware.patch new file mode 100644 index 000000000..c08ba1ff8 --- /dev/null +++ b/debian/patches/features/all/bql/bql-fix-posdiff-to-integer-overflow-aware.patch @@ -0,0 +1,31 @@ +From: Hiroaki SHIMODA +Date: Wed, 30 May 2012 12:24:39 +0000 +Subject: bql: Fix POSDIFF() to integer overflow aware. + +commit 0cfd32b736ae0c36b42697584811042726c07cba upstream. + +POSDIFF() fails to take into account integer overflow case. + +Signed-off-by: Hiroaki SHIMODA +Cc: Tom Herbert +Cc: Eric Dumazet +Cc: Denys Fedoryshchenko +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + lib/dynamic_queue_limits.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +index 6ab4587..c87eb76 100644 +--- a/lib/dynamic_queue_limits.c ++++ b/lib/dynamic_queue_limits.c +@@ -10,7 +10,7 @@ + #include + #include + +-#define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0) ++#define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0) + + /* Records completed count and recalculates the queue limit */ + void dql_completed(struct dql *dql, unsigned int count) diff --git a/debian/patches/features/all/bql/dql-dynamic-queue-limits.patch b/debian/patches/features/all/bql/dql-dynamic-queue-limits.patch new file mode 100644 index 000000000..18e537602 --- /dev/null +++ b/debian/patches/features/all/bql/dql-dynamic-queue-limits.patch @@ -0,0 +1,328 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:32:35 +0000 +Subject: dql: Dynamic queue limits + +commit 75957ba36c05b979701e9ec64b37819adc12f830 upstream. + +Implementation of dynamic queue limits (dql). This is a libary which +allows a queue limit to be dynamically managed. The goal of dql is +to set the queue limit, number of objects to the queue, to be minimized +without allowing the queue to be starved. + +dql would be used with a queue which has these properties: + +1) Objects are queued up to some limit which can be expressed as a + count of objects. +2) Periodically a completion process executes which retires consumed + objects. +3) Starvation occurs when limit has been reached, all queued data has + actually been consumed but completion processing has not yet run, + so queuing new data is blocked. +4) Minimizing the amount of queued data is desirable. + +A canonical example of such a queue would be a NIC HW transmit queue. + +The queue limit is dynamic, it will increase or decrease over time +depending on the workload. The queue limit is recalculated each time +completion processing is done. Increases occur when the queue is +starved and can exponentially increase over successive intervals. +Decreases occur when more data is being maintained in the queue than +needed to prevent starvation. The number of extra objects, or "slack", +is measured over successive intervals, and to avoid hysteresis the +limit is only reduced by the miminum slack seen over a configurable +time period. + +dql API provides routines to manage the queue: +- dql_init is called to intialize the dql structure +- dql_reset is called to reset dynamic values +- dql_queued called when objects are being enqueued +- dql_avail returns availability in the queue +- dql_completed is called when objects have be consumed in the queue + +Configuration consists of: +- max_limit, maximum limit +- min_limit, minimum limit +- slack_hold_time, time to measure instances of slack before reducing + queue limit + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + include/linux/dynamic_queue_limits.h | 97 +++++++++++++++++++++++++ + lib/Kconfig | 3 + + lib/Makefile | 2 + + lib/dynamic_queue_limits.c | 133 ++++++++++++++++++++++++++++++++++ + 4 files changed, 235 insertions(+) + create mode 100644 include/linux/dynamic_queue_limits.h + create mode 100644 lib/dynamic_queue_limits.c + +diff --git a/include/linux/dynamic_queue_limits.h b/include/linux/dynamic_queue_limits.h +new file mode 100644 +index 0000000..5621547 +--- /dev/null ++++ b/include/linux/dynamic_queue_limits.h +@@ -0,0 +1,97 @@ ++/* ++ * Dynamic queue limits (dql) - Definitions ++ * ++ * Copyright (c) 2011, Tom Herbert ++ * ++ * This header file contains the definitions for dynamic queue limits (dql). ++ * dql would be used in conjunction with a producer/consumer type queue ++ * (possibly a HW queue). Such a queue would have these general properties: ++ * ++ * 1) Objects are queued up to some limit specified as number of objects. ++ * 2) Periodically a completion process executes which retires consumed ++ * objects. ++ * 3) Starvation occurs when limit has been reached, all queued data has ++ * actually been consumed, but completion processing has not yet run ++ * so queuing new data is blocked. ++ * 4) Minimizing the amount of queued data is desirable. ++ * ++ * The goal of dql is to calculate the limit as the minimum number of objects ++ * needed to prevent starvation. ++ * ++ * The primary functions of dql are: ++ * dql_queued - called when objects are enqueued to record number of objects ++ * dql_avail - returns how many objects are available to be queued based ++ * on the object limit and how many objects are already enqueued ++ * dql_completed - called at completion time to indicate how many objects ++ * were retired from the queue ++ * ++ * The dql implementation does not implement any locking for the dql data ++ * structures, the higher layer should provide this. dql_queued should ++ * be serialized to prevent concurrent execution of the function; this ++ * is also true for dql_completed. However, dql_queued and dlq_completed can ++ * be executed concurrently (i.e. they can be protected by different locks). ++ */ ++ ++#ifndef _LINUX_DQL_H ++#define _LINUX_DQL_H ++ ++#ifdef __KERNEL__ ++ ++struct dql { ++ /* Fields accessed in enqueue path (dql_queued) */ ++ unsigned int num_queued; /* Total ever queued */ ++ unsigned int adj_limit; /* limit + num_completed */ ++ unsigned int last_obj_cnt; /* Count at last queuing */ ++ ++ /* Fields accessed only by completion path (dql_completed) */ ++ ++ unsigned int limit ____cacheline_aligned_in_smp; /* Current limit */ ++ unsigned int num_completed; /* Total ever completed */ ++ ++ unsigned int prev_ovlimit; /* Previous over limit */ ++ unsigned int prev_num_queued; /* Previous queue total */ ++ unsigned int prev_last_obj_cnt; /* Previous queuing cnt */ ++ ++ unsigned int lowest_slack; /* Lowest slack found */ ++ unsigned long slack_start_time; /* Time slacks seen */ ++ ++ /* Configuration */ ++ unsigned int max_limit; /* Max limit */ ++ unsigned int min_limit; /* Minimum limit */ ++ unsigned int slack_hold_time; /* Time to measure slack */ ++}; ++ ++/* Set some static maximums */ ++#define DQL_MAX_OBJECT (UINT_MAX / 16) ++#define DQL_MAX_LIMIT ((UINT_MAX / 2) - DQL_MAX_OBJECT) ++ ++/* ++ * Record number of objects queued. Assumes that caller has already checked ++ * availability in the queue with dql_avail. ++ */ ++static inline void dql_queued(struct dql *dql, unsigned int count) ++{ ++ BUG_ON(count > DQL_MAX_OBJECT); ++ ++ dql->num_queued += count; ++ dql->last_obj_cnt = count; ++} ++ ++/* Returns how many objects can be queued, < 0 indicates over limit. */ ++static inline int dql_avail(const struct dql *dql) ++{ ++ return dql->adj_limit - dql->num_queued; ++} ++ ++/* Record number of completed objects and recalculate the limit. */ ++void dql_completed(struct dql *dql, unsigned int count); ++ ++/* Reset dql state */ ++void dql_reset(struct dql *dql); ++ ++/* Initialize dql state */ ++int dql_init(struct dql *dql, unsigned hold_time); ++ ++#endif /* _KERNEL_ */ ++ ++#endif /* _LINUX_DQL_H */ +diff --git a/lib/Kconfig b/lib/Kconfig +index 32f3e5a..63b5782 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -244,6 +244,9 @@ config CPU_RMAP + bool + depends on SMP + ++config DQL ++ bool ++ + # + # Netlink attribute parsing support is select'ed if needed + # +diff --git a/lib/Makefile b/lib/Makefile +index a4da283..ff00d4d 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -115,6 +115,8 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o + + obj-$(CONFIG_CORDIC) += cordic.o + ++obj-$(CONFIG_DQL) += dynamic_queue_limits.o ++ + hostprogs-y := gen_crc32table + clean-files := crc32table.h + +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +new file mode 100644 +index 0000000..3d1bdcd +--- /dev/null ++++ b/lib/dynamic_queue_limits.c +@@ -0,0 +1,133 @@ ++/* ++ * Dynamic byte queue limits. See include/linux/dynamic_queue_limits.h ++ * ++ * Copyright (c) 2011, Tom Herbert ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0) ++ ++/* Records completed count and recalculates the queue limit */ ++void dql_completed(struct dql *dql, unsigned int count) ++{ ++ unsigned int inprogress, prev_inprogress, limit; ++ unsigned int ovlimit, all_prev_completed, completed; ++ ++ /* Can't complete more than what's in queue */ ++ BUG_ON(count > dql->num_queued - dql->num_completed); ++ ++ completed = dql->num_completed + count; ++ limit = dql->limit; ++ ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit); ++ inprogress = dql->num_queued - completed; ++ prev_inprogress = dql->prev_num_queued - dql->num_completed; ++ all_prev_completed = POSDIFF(completed, dql->prev_num_queued); ++ ++ if ((ovlimit && !inprogress) || ++ (dql->prev_ovlimit && all_prev_completed)) { ++ /* ++ * Queue considered starved if: ++ * - The queue was over-limit in the last interval, ++ * and there is no more data in the queue. ++ * OR ++ * - The queue was over-limit in the previous interval and ++ * when enqueuing it was possible that all queued data ++ * had been consumed. This covers the case when queue ++ * may have becomes starved between completion processing ++ * running and next time enqueue was scheduled. ++ * ++ * When queue is starved increase the limit by the amount ++ * of bytes both sent and completed in the last interval, ++ * plus any previous over-limit. ++ */ ++ limit += POSDIFF(completed, dql->prev_num_queued) + ++ dql->prev_ovlimit; ++ dql->slack_start_time = jiffies; ++ dql->lowest_slack = UINT_MAX; ++ } else if (inprogress && prev_inprogress && !all_prev_completed) { ++ /* ++ * Queue was not starved, check if the limit can be decreased. ++ * A decrease is only considered if the queue has been busy in ++ * the whole interval (the check above). ++ * ++ * If there is slack, the amount of execess data queued above ++ * the the amount needed to prevent starvation, the queue limit ++ * can be decreased. To avoid hysteresis we consider the ++ * minimum amount of slack found over several iterations of the ++ * completion routine. ++ */ ++ unsigned int slack, slack_last_objs; ++ ++ /* ++ * Slack is the maximum of ++ * - The queue limit plus previous over-limit minus twice ++ * the number of objects completed. Note that two times ++ * number of completed bytes is a basis for an upper bound ++ * of the limit. ++ * - Portion of objects in the last queuing operation that ++ * was not part of non-zero previous over-limit. That is ++ * "round down" by non-overlimit portion of the last ++ * queueing operation. ++ */ ++ slack = POSDIFF(limit + dql->prev_ovlimit, ++ 2 * (completed - dql->num_completed)); ++ slack_last_objs = dql->prev_ovlimit ? ++ POSDIFF(dql->prev_last_obj_cnt, dql->prev_ovlimit) : 0; ++ ++ slack = max(slack, slack_last_objs); ++ ++ if (slack < dql->lowest_slack) ++ dql->lowest_slack = slack; ++ ++ if (time_after(jiffies, ++ dql->slack_start_time + dql->slack_hold_time)) { ++ limit = POSDIFF(limit, dql->lowest_slack); ++ dql->slack_start_time = jiffies; ++ dql->lowest_slack = UINT_MAX; ++ } ++ } ++ ++ /* Enforce bounds on limit */ ++ limit = clamp(limit, dql->min_limit, dql->max_limit); ++ ++ if (limit != dql->limit) { ++ dql->limit = limit; ++ ovlimit = 0; ++ } ++ ++ dql->adj_limit = limit + completed; ++ dql->prev_ovlimit = ovlimit; ++ dql->prev_last_obj_cnt = dql->last_obj_cnt; ++ dql->num_completed = completed; ++ dql->prev_num_queued = dql->num_queued; ++} ++EXPORT_SYMBOL(dql_completed); ++ ++void dql_reset(struct dql *dql) ++{ ++ /* Reset all dynamic values */ ++ dql->limit = 0; ++ dql->num_queued = 0; ++ dql->num_completed = 0; ++ dql->last_obj_cnt = 0; ++ dql->prev_num_queued = 0; ++ dql->prev_last_obj_cnt = 0; ++ dql->prev_ovlimit = 0; ++ dql->lowest_slack = UINT_MAX; ++ dql->slack_start_time = jiffies; ++} ++EXPORT_SYMBOL(dql_reset); ++ ++int dql_init(struct dql *dql, unsigned hold_time) ++{ ++ dql->max_limit = DQL_MAX_LIMIT; ++ dql->min_limit = 0; ++ dql->slack_hold_time = hold_time; ++ dql_reset(dql); ++ return 0; ++} ++EXPORT_SYMBOL(dql_init); diff --git a/debian/patches/features/all/bql/dql-fix-undefined-jiffies.patch b/debian/patches/features/all/bql/dql-fix-undefined-jiffies.patch new file mode 100644 index 000000000..1ec848637 --- /dev/null +++ b/debian/patches/features/all/bql/dql-fix-undefined-jiffies.patch @@ -0,0 +1,28 @@ +From: Tom Herbert +Date: Sun, 11 Mar 2012 19:59:43 -0700 +Subject: dql: Fix undefined jiffies + +commit 930c514f6960454a5082f7e533bd2867df6fe9cb upstream. + +In some configurations, jiffies may be undefined in +lib/dynamic_queue_limits.c. Adding include of jiffies.h to avoid +this. + +Signed-off-by: Tom Herbert +Signed-off-by: David S. Miller +--- + lib/dynamic_queue_limits.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +index 3d1bdcd..6ab4587 100644 +--- a/lib/dynamic_queue_limits.c ++++ b/lib/dynamic_queue_limits.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0) diff --git a/debian/patches/features/all/bql/e1000e-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/e1000e-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..4e4a8090d --- /dev/null +++ b/debian/patches/features/all/bql/e1000e-support-for-byte-queue-limits.patch @@ -0,0 +1,63 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:16 +0000 +Subject: e1000e: Support for byte queue limits + +commit 3f0cfa3bc11e7f00c9994e0f469cbc0e7da7b00c upstream. + +Changes to e1000e to use byte queue limits. + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index a5bd7a3..c6e9763 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -1079,6 +1079,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) + unsigned int i, eop; + unsigned int count = 0; + unsigned int total_tx_bytes = 0, total_tx_packets = 0; ++ unsigned int bytes_compl = 0, pkts_compl = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->buffer_info[i].next_to_watch; +@@ -1096,6 +1097,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) + if (cleaned) { + total_tx_packets += buffer_info->segs; + total_tx_bytes += buffer_info->bytecount; ++ if (buffer_info->skb) { ++ bytes_compl += buffer_info->skb->len; ++ pkts_compl++; ++ } + } + + e1000_put_txbuf(adapter, buffer_info); +@@ -1114,6 +1119,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) + + tx_ring->next_to_clean = i; + ++ netdev_completed_queue(netdev, pkts_compl, bytes_compl); ++ + #define TX_WAKE_THRESHOLD 32 + if (count && netif_carrier_ok(netdev) && + e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) { +@@ -2240,6 +2247,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter) + e1000_put_txbuf(adapter, buffer_info); + } + ++ netdev_reset_queue(adapter->netdev); + size = sizeof(struct e1000_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); + +@@ -5027,6 +5035,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + /* if count is 0 then mapping error has occurred */ + count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); + if (count) { ++ netdev_sent_queue(netdev, skb->len); + e1000_tx_queue(adapter, tx_flags, count); + /* Make sure there is space in the ring for the next send. */ + e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); diff --git a/debian/patches/features/all/bql/forcedeath-fix-bql-support-for-forcedeath.patch b/debian/patches/features/all/bql/forcedeath-fix-bql-support-for-forcedeath.patch new file mode 100644 index 000000000..7c1843d3f --- /dev/null +++ b/debian/patches/features/all/bql/forcedeath-fix-bql-support-for-forcedeath.patch @@ -0,0 +1,39 @@ +From: Igor Maravic +Date: Thu, 1 Dec 2011 23:48:20 +0000 +Subject: forcedeath: Fix bql support for forcedeath + +commit 7505afe28c16a8d386624930a018d0052c75d687 upstream. + +Moved netdev_completed_queue() out of while loop in function nv_tx_done_optimized(). +Because this function was in while loop, +BUG_ON(count > dql->num_queued - dql->num_completed) +was hit in dql_completed(). + +Signed-off-by: Igor Maravic +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/nvidia/forcedeth.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c +index 5245dac..4c4e7f4 100644 +--- a/drivers/net/ethernet/nvidia/forcedeth.c ++++ b/drivers/net/ethernet/nvidia/forcedeth.c +@@ -2561,13 +2561,14 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit) + nv_tx_flip_ownership(dev); + } + +- netdev_completed_queue(np->dev, tx_work, bytes_cleaned); +- + if (unlikely(np->get_tx.ex++ == np->last_tx.ex)) + np->get_tx.ex = np->first_tx.ex; + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) + np->get_tx_ctx = np->first_tx_ctx; + } ++ ++ netdev_completed_queue(np->dev, tx_work, bytes_cleaned); ++ + if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) { + np->tx_stop = 0; + netif_wake_queue(dev); diff --git a/debian/patches/features/all/bql/forcedeth-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/forcedeth-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..c5a1e62c5 --- /dev/null +++ b/debian/patches/features/all/bql/forcedeth-support-for-byte-queue-limits.patch @@ -0,0 +1,105 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:23 +0000 +Subject: forcedeth: Support for byte queue limits + +commit b8bfca9439d4ed03446bc9a3fdaef81b364d32dd upstream. + +Changes to forcedeth to use byte queue limits. + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/nvidia/forcedeth.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/ethernet/nvidia/forcedeth.c ++++ b/drivers/net/ethernet/nvidia/forcedeth.c +@@ -1849,6 +1849,7 @@ + np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1]; + np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb; + np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1]; ++ netdev_reset_queue(np->dev); + np->tx_pkts_in_progress = 0; + np->tx_change_owner = NULL; + np->tx_end_flip = NULL; +@@ -2194,6 +2195,9 @@ + + /* set tx flags */ + start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); ++ ++ netdev_sent_queue(np->dev, skb->len); ++ + np->put_tx.orig = put_tx; + + spin_unlock_irqrestore(&np->lock, flags); +@@ -2338,6 +2342,9 @@ + + /* set tx flags */ + start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); ++ ++ netdev_sent_queue(np->dev, skb->len); ++ + np->put_tx.ex = put_tx; + + spin_unlock_irqrestore(&np->lock, flags); +@@ -2375,6 +2382,7 @@ + u32 flags; + int tx_work = 0; + struct ring_desc *orig_get_tx = np->get_tx.orig; ++ unsigned int bytes_compl = 0; + + while ((np->get_tx.orig != np->put_tx.orig) && + !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID) && +@@ -2391,6 +2399,7 @@ + dev->stats.tx_packets++; + dev->stats.tx_bytes += np->get_tx_ctx->skb->len; + } ++ bytes_compl += np->get_tx_ctx->skb->len; + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; + tx_work++; +@@ -2404,6 +2413,7 @@ + dev->stats.tx_packets++; + dev->stats.tx_bytes += np->get_tx_ctx->skb->len; + } ++ bytes_compl += np->get_tx_ctx->skb->len; + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; + tx_work++; +@@ -2414,6 +2424,9 @@ + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) + np->get_tx_ctx = np->first_tx_ctx; + } ++ ++ netdev_completed_queue(np->dev, tx_work, bytes_compl); ++ + if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) { + np->tx_stop = 0; + netif_wake_queue(dev); +@@ -2427,6 +2440,7 @@ + u32 flags; + int tx_work = 0; + struct ring_desc_ex *orig_get_tx = np->get_tx.ex; ++ unsigned long bytes_cleaned = 0; + + while ((np->get_tx.ex != np->put_tx.ex) && + !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX2_VALID) && +@@ -2447,6 +2461,7 @@ + dev->stats.tx_bytes += np->get_tx_ctx->skb->len; + } + ++ bytes_cleaned += np->get_tx_ctx->skb->len; + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; + tx_work++; +@@ -2454,6 +2469,9 @@ + if (np->tx_limit) + nv_tx_flip_ownership(dev); + } ++ ++ netdev_completed_queue(np->dev, tx_work, bytes_cleaned); ++ + if (unlikely(np->get_tx.ex++ == np->last_tx.ex)) + np->get_tx.ex = np->first_tx.ex; + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) diff --git a/debian/patches/features/all/bql/igb-add-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/igb-add-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..ede9b2687 --- /dev/null +++ b/debian/patches/features/all/bql/igb-add-support-for-byte-queue-limits.patch @@ -0,0 +1,65 @@ +From: Eric Dumazet +Date: Wed, 4 Jan 2012 20:23:36 +0000 +Subject: igb: Add support for byte queue limits. + +commit bdbc063129e811264cd6c311d8c2d9b95de01231 upstream. + +This adds support for byte queue limits (BQL) + +Since this driver collects bytes count in 'bytecount' field, use it also +in igb_tx_map() + +Signed-off-by: Eric Dumazet +CC: Alexander Duyck +Tested-by: Aaron Brown +Signed-off-by: Jeff Kirsher +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/intel/igb/igb.h | 5 +++++ + drivers/net/ethernet/intel/igb/igb_main.c | 5 +++++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h +index c69feeb..3d12e67 100644 +--- a/drivers/net/ethernet/intel/igb/igb.h ++++ b/drivers/net/ethernet/intel/igb/igb.h +@@ -447,4 +447,9 @@ static inline s32 igb_get_phy_info(struct e1000_hw *hw) + return 0; + } + ++static inline struct netdev_queue *txring_txq(const struct igb_ring *tx_ring) ++{ ++ return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); ++} ++ + #endif /* _IGB_H_ */ +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index 89d576c..dcc68cc 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -3201,6 +3201,7 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring) + buffer_info = &tx_ring->tx_buffer_info[i]; + igb_unmap_and_free_tx_resource(tx_ring, buffer_info); + } ++ netdev_tx_reset_queue(txring_txq(tx_ring)); + + size = sizeof(struct igb_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); +@@ -4238,6 +4239,8 @@ static void igb_tx_map(struct igb_ring *tx_ring, + frag++; + } + ++ netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount); ++ + /* write last descriptor with RS and EOP bits */ + cmd_type |= cpu_to_le32(size) | cpu_to_le32(IGB_TXD_DCMD); + tx_desc->read.cmd_type_len = cmd_type; +@@ -5777,6 +5780,8 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) + } + } + ++ netdev_tx_completed_queue(txring_txq(tx_ring), ++ total_packets, total_bytes); + i += tx_ring->count; + tx_ring->next_to_clean = i; + u64_stats_update_begin(&tx_ring->tx_syncp); diff --git a/debian/patches/features/all/bql/igb-fix-ethtool-offline-test.patch b/debian/patches/features/all/bql/igb-fix-ethtool-offline-test.patch new file mode 100644 index 000000000..0b86234d1 --- /dev/null +++ b/debian/patches/features/all/bql/igb-fix-ethtool-offline-test.patch @@ -0,0 +1,56 @@ +From: Jeff Kirsher +Date: Thu, 19 Jan 2012 18:31:34 +0000 +Subject: igb: fix ethtool offline test + +commit 51a76c30929cc8b7d541f51e634f146e54ea9bb7 upstream. + +A bug was introduced with the following patch: + + Commmit bdbc063129e811264cd6c311d8c2d9b95de01231 + Author: Eric Dumazet + igb: Add support for byte queue limits. + +The ethtool offline tests will cause a perpetual link flap, this +is because the tests also need to account for byte queue limits (BQL). + +CC: Eric Dumazet +Signed-off-by: Jeff Kirsher +Signed-off-by: John Fastabend +Tested-by: Jeff Pieper +--- + drivers/net/ethernet/intel/igb/igb_ethtool.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c +index aa399a8..e10821a 100644 +--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c ++++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c +@@ -1577,7 +1577,9 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring, + union e1000_adv_rx_desc *rx_desc; + struct igb_rx_buffer *rx_buffer_info; + struct igb_tx_buffer *tx_buffer_info; ++ struct netdev_queue *txq; + u16 rx_ntc, tx_ntc, count = 0; ++ unsigned int total_bytes = 0, total_packets = 0; + + /* initialize next to clean and descriptor values */ + rx_ntc = rx_ring->next_to_clean; +@@ -1601,6 +1603,8 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring, + + /* unmap buffer on tx side */ + tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc]; ++ total_bytes += tx_buffer_info->bytecount; ++ total_packets += tx_buffer_info->gso_segs; + igb_unmap_and_free_tx_resource(tx_ring, tx_buffer_info); + + /* increment rx/tx next to clean counters */ +@@ -1615,6 +1619,9 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring, + rx_desc = IGB_RX_DESC(rx_ring, rx_ntc); + } + ++ txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); ++ netdev_tx_completed_queue(txq, total_packets, total_bytes); ++ + /* re-map buffers to ring, store next to clean values */ + igb_alloc_rx_buffers(rx_ring, count); + rx_ring->next_to_clean = rx_ntc; diff --git a/debian/patches/features/all/bql/igb-ixgbe-netdev_tx_reset_queue-incorrectly-called-from-tx-init.patch b/debian/patches/features/all/bql/igb-ixgbe-netdev_tx_reset_queue-incorrectly-called-from-tx-init.patch new file mode 100644 index 000000000..0f9d8c304 --- /dev/null +++ b/debian/patches/features/all/bql/igb-ixgbe-netdev_tx_reset_queue-incorrectly-called-from-tx-init.patch @@ -0,0 +1,79 @@ +From: John Fastabend +Date: Mon, 23 Apr 2012 12:22:39 +0000 +Subject: igb, ixgbe: netdev_tx_reset_queue incorrectly called from tx init + path + +commit dad8a3b3eaa0c2ca25368a0b9f65edca84e27a40 upstream. + +igb and ixgbe incorrectly call netdev_tx_reset_queue() from +i{gb|xgbe}_clean_tx_ring() this sort of works in most cases except +when the number of real tx queues changes. When the number of real +tx queues changes netdev_tx_reset_queue() only gets called on the +new number of queues so when we reduce the number of queues we risk +triggering the watchdog timer and repeated device resets. + +So this is not only a cosmetic issue but causes real bugs. For +example enabling/disabling DCB or FCoE in ixgbe will trigger this. + +CC: Alexander Duyck +Signed-off-by: John Fastabend +Tested-by: John Bishop +Tested-by: Aaron Brown +Signed-off-by: Jeff Kirsher +--- + drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- + drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 ++ + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- + 3 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -2711,8 +2711,6 @@ + + txdctl |= E1000_TXDCTL_QUEUE_ENABLE; + wr32(E1000_TXDCTL(reg_idx), txdctl); +- +- netdev_tx_reset_queue(txring_txq(ring)); + } + + /** +@@ -3206,6 +3204,8 @@ + igb_unmap_and_free_tx_resource(tx_ring, buffer_info); + } + ++ netdev_tx_reset_queue(txring_txq(tx_ring)); ++ + size = sizeof(struct igb_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); + +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +@@ -1764,6 +1764,8 @@ + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + } + ++ netdev_tx_reset_queue(txring_txq(tx_ring)); ++ + /* re-map buffers to ring, store next to clean values */ + ixgbe_alloc_rx_buffers(rx_ring, count); + rx_ring->next_to_clean = rx_ntc; +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -2411,8 +2411,6 @@ + /* enable queue */ + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl); + +- netdev_tx_reset_queue(txring_txq(ring)); +- + /* TXDCTL.EN will return 0 on 82598 if link is down, so skip it */ + if (hw->mac.type == ixgbe_mac_82598EB && + !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP)) +@@ -3930,6 +3928,8 @@ + ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info); + } + ++ netdev_tx_reset_queue(txring_txq(tx_ring)); ++ + size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); + diff --git a/debian/patches/features/all/bql/ixgbe-add-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/ixgbe-add-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..c31aa8a4d --- /dev/null +++ b/debian/patches/features/all/bql/ixgbe-add-support-for-byte-queue-limits.patch @@ -0,0 +1,59 @@ +From: Alexander Duyck +Date: Tue, 7 Feb 2012 08:14:33 +0000 +Subject: ixgbe: add support for byte queue limits + +commit b2d96e0ac07cf4929c6b0eb13121672048368117 upstream. + +This adds support for byte queue limits (BQL). + +Based on patch from Eric Dumazet for igb. + +Signed-off-by: Alexander Duyck +Tested-by: Stephen Ko +--- + drivers/net/ethernet/intel/ixgbe/ixgbe.h | 5 +++++ + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 7 +++++++ + 2 files changed, 12 insertions(+) + +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h +@@ -629,4 +629,9 @@ + extern int ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type); + #endif /* IXGBE_FCOE */ + ++static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring) ++{ ++ return netdev_get_tx_queue(ring->netdev, ring->queue_index); ++} ++ + #endif /* _IXGBE_H_ */ +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -832,6 +832,9 @@ + return true; + } + ++ netdev_tx_completed_queue(txring_txq(tx_ring), ++ total_packets, total_bytes); ++ + #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) + if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) && + (ixgbe_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) { +@@ -2408,6 +2411,8 @@ + /* enable queue */ + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl); + ++ netdev_tx_reset_queue(txring_txq(ring)); ++ + /* TXDCTL.EN will return 0 on 82598 if link is down, so skip it */ + if (hw->mac.type == ixgbe_mac_82598EB && + !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP)) +@@ -6581,6 +6586,8 @@ + tx_buffer_info->gso_segs = gso_segs; + tx_buffer_info->skb = skb; + ++ netdev_tx_sent_queue(txring_txq(tx_ring), tx_buffer_info->bytecount); ++ + /* set the timestamp */ + first->time_stamp = jiffies; + diff --git a/debian/patches/features/all/bql/net-add-netdev-interfaces-for-recording-sends-comp.patch b/debian/patches/features/all/bql/net-add-netdev-interfaces-for-recording-sends-comp.patch new file mode 100644 index 000000000..5a95f5a07 --- /dev/null +++ b/debian/patches/features/all/bql/net-add-netdev-interfaces-for-recording-sends-comp.patch @@ -0,0 +1,56 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:32:52 +0000 +Subject: net: Add netdev interfaces for recording sends/comp + +commit c5d67bd78c5dc540e3461c36fb3d389fbe0de4c3 upstream. + +Add interfaces for drivers to call for recording number of packets and +bytes at send time and transmit completion. Also, added a function to +"reset" a queue. These will be used by Byte Queue Limits. + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + include/linux/netdevice.h | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index d19f932..9b24cc7 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1859,6 +1859,34 @@ static inline int netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_qu + return dev_queue->state & QUEUE_STATE_ANY_XOFF_OR_FROZEN; + } + ++static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue, ++ unsigned int bytes) ++{ ++} ++ ++static inline void netdev_sent_queue(struct net_device *dev, unsigned int bytes) ++{ ++ netdev_tx_sent_queue(netdev_get_tx_queue(dev, 0), bytes); ++} ++ ++static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue, ++ unsigned pkts, unsigned bytes) ++{ ++} ++ ++static inline void netdev_completed_queue(struct net_device *dev, ++ unsigned pkts, unsigned bytes) ++{ ++ netdev_tx_completed_queue(netdev_get_tx_queue(dev, 0), pkts, bytes); ++} ++ ++static inline void netdev_tx_reset_queue(struct netdev_queue *q) ++{ ++} ++ ++static inline void netdev_reset_queue(struct net_device *dev_queue) ++{ ++ netdev_tx_reset_queue(netdev_get_tx_queue(dev_queue, 0)); + } + + /** diff --git a/debian/patches/features/all/bql/net-add-queue-state-xoff-flag-for-stack.patch b/debian/patches/features/all/bql/net-add-queue-state-xoff-flag-for-stack.patch new file mode 100644 index 000000000..201369a1d --- /dev/null +++ b/debian/patches/features/all/bql/net-add-queue-state-xoff-flag-for-stack.patch @@ -0,0 +1,279 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:32:44 +0000 +Subject: net: Add queue state xoff flag for stack + +commit 7346649826382b769cfadf4a2fe8a84d060c55e9 upstream. + +Create separate queue state flags so that either the stack or drivers +can turn on XOFF. Added a set of functions used in the stack to determine +if a queue is really stopped (either by stack or driver) + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + include/linux/netdevice.h | 41 ++++++++++++++++++++++++++++++----------- + net/core/dev.c | 4 ++-- + net/core/netpoll.c | 4 ++-- + net/core/pktgen.c | 2 +- + net/sched/sch_generic.c | 8 ++++---- + net/sched/sch_multiq.c | 6 ++++-- + net/sched/sch_teql.c | 6 +++--- + 7 files changed, 46 insertions(+), 25 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index ac9a4b9..d19f932 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -517,11 +517,23 @@ static inline void napi_synchronize(const struct napi_struct *n) + #endif + + enum netdev_queue_state_t { +- __QUEUE_STATE_XOFF, ++ __QUEUE_STATE_DRV_XOFF, ++ __QUEUE_STATE_STACK_XOFF, + __QUEUE_STATE_FROZEN, +-#define QUEUE_STATE_XOFF_OR_FROZEN ((1 << __QUEUE_STATE_XOFF) | \ +- (1 << __QUEUE_STATE_FROZEN)) ++#define QUEUE_STATE_ANY_XOFF ((1 << __QUEUE_STATE_DRV_XOFF) | \ ++ (1 << __QUEUE_STATE_STACK_XOFF)) ++#define QUEUE_STATE_ANY_XOFF_OR_FROZEN (QUEUE_STATE_ANY_XOFF | \ ++ (1 << __QUEUE_STATE_FROZEN)) + }; ++/* ++ * __QUEUE_STATE_DRV_XOFF is used by drivers to stop the transmit queue. The ++ * netif_tx_* functions below are used to manipulate this flag. The ++ * __QUEUE_STATE_STACK_XOFF flag is used by the stack to stop the transmit ++ * queue independently. The netif_xmit_*stopped functions below are called ++ * to check if the queue has been stopped by the driver or stack (either ++ * of the XOFF bits are set in the state). Drivers should not need to call ++ * netif_xmit*stopped functions, they should only be using netif_tx_*. ++ */ + + struct netdev_queue { + /* +@@ -1718,7 +1730,7 @@ extern void __netif_schedule(struct Qdisc *q); + + static inline void netif_schedule_queue(struct netdev_queue *txq) + { +- if (!test_bit(__QUEUE_STATE_XOFF, &txq->state)) ++ if (!(txq->state & QUEUE_STATE_ANY_XOFF)) + __netif_schedule(txq->qdisc); + } + +@@ -1732,7 +1744,7 @@ static inline void netif_tx_schedule_all(struct net_device *dev) + + static inline void netif_tx_start_queue(struct netdev_queue *dev_queue) + { +- clear_bit(__QUEUE_STATE_XOFF, &dev_queue->state); ++ clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); + } + + /** +@@ -1764,7 +1776,7 @@ static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue) + return; + } + #endif +- if (test_and_clear_bit(__QUEUE_STATE_XOFF, &dev_queue->state)) ++ if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)) + __netif_schedule(dev_queue->qdisc); + } + +@@ -1796,7 +1808,7 @@ static inline void netif_tx_stop_queue(struct netdev_queue *dev_queue) + pr_info("netif_stop_queue() cannot be called before register_netdev()\n"); + return; + } +- set_bit(__QUEUE_STATE_XOFF, &dev_queue->state); ++ set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); + } + + /** +@@ -1823,7 +1835,7 @@ static inline void netif_tx_stop_all_queues(struct net_device *dev) + + static inline int netif_tx_queue_stopped(const struct netdev_queue *dev_queue) + { +- return test_bit(__QUEUE_STATE_XOFF, &dev_queue->state); ++ return test_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); + } + + /** +@@ -1837,9 +1849,16 @@ static inline int netif_queue_stopped(const struct net_device *dev) + return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0)); + } + +-static inline int netif_tx_queue_frozen_or_stopped(const struct netdev_queue *dev_queue) ++static inline int netif_xmit_stopped(const struct netdev_queue *dev_queue) + { +- return dev_queue->state & QUEUE_STATE_XOFF_OR_FROZEN; ++ return dev_queue->state & QUEUE_STATE_ANY_XOFF; ++} ++ ++static inline int netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_queue) ++{ ++ return dev_queue->state & QUEUE_STATE_ANY_XOFF_OR_FROZEN; ++} ++ + } + + /** +@@ -1926,7 +1945,7 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) + if (netpoll_trap()) + return; + #endif +- if (test_and_clear_bit(__QUEUE_STATE_XOFF, &txq->state)) ++ if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state)) + __netif_schedule(txq->qdisc); + } + +diff --git a/net/core/dev.c b/net/core/dev.c +index c7ef6c5..cb8f753 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2270,7 +2270,7 @@ gso: + return rc; + } + txq_trans_update(txq); +- if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) ++ if (unlikely(netif_xmit_stopped(txq) && skb->next)) + return NETDEV_TX_BUSY; + } while (skb->next); + +@@ -2558,7 +2558,7 @@ int dev_queue_xmit(struct sk_buff *skb) + + HARD_TX_LOCK(dev, txq, cpu); + +- if (!netif_tx_queue_stopped(txq)) { ++ if (!netif_xmit_stopped(txq)) { + __this_cpu_inc(xmit_recursion); + rc = dev_hard_start_xmit(skb, dev, txq); + __this_cpu_dec(xmit_recursion); +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index 1a7d8e2..0d38808 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -76,7 +76,7 @@ static void queue_process(struct work_struct *work) + + local_irq_save(flags); + __netif_tx_lock(txq, smp_processor_id()); +- if (netif_tx_queue_frozen_or_stopped(txq) || ++ if (netif_xmit_frozen_or_stopped(txq) || + ops->ndo_start_xmit(skb, dev) != NETDEV_TX_OK) { + skb_queue_head(&npinfo->txq, skb); + __netif_tx_unlock(txq); +@@ -317,7 +317,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb, + for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; + tries > 0; --tries) { + if (__netif_tx_trylock(txq)) { +- if (!netif_tx_queue_stopped(txq)) { ++ if (!netif_xmit_stopped(txq)) { + status = ops->ndo_start_xmit(skb, dev); + if (status == NETDEV_TX_OK) + txq_trans_update(txq); +diff --git a/net/core/pktgen.c b/net/core/pktgen.c +index aa53a35..449fe0f 100644 +--- a/net/core/pktgen.c ++++ b/net/core/pktgen.c +@@ -3342,7 +3342,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) + + __netif_tx_lock_bh(txq); + +- if (unlikely(netif_tx_queue_frozen_or_stopped(txq))) { ++ if (unlikely(netif_xmit_frozen_or_stopped(txq))) { + ret = NETDEV_TX_BUSY; + pkt_dev->last_ok = 0; + goto unlock; +diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c +index 79ac145..67fc573 100644 +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -60,7 +60,7 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q) + + /* check the reason of requeuing without tx lock first */ + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); +- if (!netif_tx_queue_frozen_or_stopped(txq)) { ++ if (!netif_xmit_frozen_or_stopped(txq)) { + q->gso_skb = NULL; + q->q.qlen--; + } else +@@ -121,7 +121,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, + spin_unlock(root_lock); + + HARD_TX_LOCK(dev, txq, smp_processor_id()); +- if (!netif_tx_queue_frozen_or_stopped(txq)) ++ if (!netif_xmit_frozen_or_stopped(txq)) + ret = dev_hard_start_xmit(skb, dev, txq); + + HARD_TX_UNLOCK(dev, txq); +@@ -143,7 +143,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, + ret = dev_requeue_skb(skb, q); + } + +- if (ret && netif_tx_queue_frozen_or_stopped(txq)) ++ if (ret && netif_xmit_frozen_or_stopped(txq)) + ret = 0; + + return ret; +@@ -242,7 +242,7 @@ static void dev_watchdog(unsigned long arg) + * old device drivers set dev->trans_start + */ + trans_start = txq->trans_start ? : dev->trans_start; +- if (netif_tx_queue_stopped(txq) && ++ if (netif_xmit_stopped(txq) && + time_after(jiffies, (trans_start + + dev->watchdog_timeo))) { + some_queue_timedout = 1; +diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c +index edc1950..49131d7 100644 +--- a/net/sched/sch_multiq.c ++++ b/net/sched/sch_multiq.c +@@ -107,7 +107,8 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch) + /* Check that target subqueue is available before + * pulling an skb to avoid head-of-line blocking. + */ +- if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) { ++ if (!netif_xmit_stopped( ++ netdev_get_tx_queue(qdisc_dev(sch), q->curband))) { + qdisc = q->queues[q->curband]; + skb = qdisc->dequeue(qdisc); + if (skb) { +@@ -138,7 +139,8 @@ static struct sk_buff *multiq_peek(struct Qdisc *sch) + /* Check that target subqueue is available before + * pulling an skb to avoid head-of-line blocking. + */ +- if (!__netif_subqueue_stopped(qdisc_dev(sch), curband)) { ++ if (!netif_xmit_stopped( ++ netdev_get_tx_queue(qdisc_dev(sch), curband))) { + qdisc = q->queues[curband]; + skb = qdisc->ops->peek(qdisc); + if (skb) +diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c +index a3b7120..283bfe3 100644 +--- a/net/sched/sch_teql.c ++++ b/net/sched/sch_teql.c +@@ -301,7 +301,7 @@ restart: + + if (slave_txq->qdisc_sleeping != q) + continue; +- if (__netif_subqueue_stopped(slave, subq) || ++ if (netif_xmit_stopped(netdev_get_tx_queue(slave, subq)) || + !netif_running(slave)) { + busy = 1; + continue; +@@ -312,7 +312,7 @@ restart: + if (__netif_tx_trylock(slave_txq)) { + unsigned int length = qdisc_pkt_len(skb); + +- if (!netif_tx_queue_frozen_or_stopped(slave_txq) && ++ if (!netif_xmit_frozen_or_stopped(slave_txq) && + slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) { + txq_trans_update(slave_txq); + __netif_tx_unlock(slave_txq); +@@ -324,7 +324,7 @@ restart: + } + __netif_tx_unlock(slave_txq); + } +- if (netif_queue_stopped(dev)) ++ if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) + busy = 1; + break; + case 1: diff --git a/debian/patches/features/all/bql/net-fix-issue-with-netdev_tx_reset_queue-not-resetting-queue-from.patch b/debian/patches/features/all/bql/net-fix-issue-with-netdev_tx_reset_queue-not-resetting-queue-from.patch new file mode 100644 index 000000000..5af240b1a --- /dev/null +++ b/debian/patches/features/all/bql/net-fix-issue-with-netdev_tx_reset_queue-not-resetting-queue-from.patch @@ -0,0 +1,58 @@ +From: Alexander Duyck +Date: Tue, 7 Feb 2012 02:29:01 +0000 +Subject: net: Fix issue with netdev_tx_reset_queue not resetting queue from + XOFF state + +commit 5c4903549c05bbb373479e0ce2992573c120654a upstream. + +We are seeing dev_watchdog hangs on several drivers. I suspect this is due +to the __QUEUE_STATE_STACK_XOFF bit being set prior to a reset for link +change, and then not being cleared by netdev_tx_reset_queue. This change +corrects that. + +In addition we were seeing dev_watchdog hangs on igb after running the +ethtool tests. We found this to be due to the fact that the ethtool test +runs the same logic as ndo_start_xmit, but we were never clearing the XOFF +flag since the loopback test in ethtool does not do byte queue accounting. + +Signed-off-by: Alexander Duyck +Tested-by: Stephen Ko +Signed-off-by: Jeff Kirsher +--- + drivers/net/ethernet/intel/igb/igb_main.c | 3 ++- + include/linux/netdevice.h | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index fda8247..e96cef8 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -2752,6 +2752,8 @@ void igb_configure_tx_ring(struct igb_adapter *adapter, + + txdctl |= E1000_TXDCTL_QUEUE_ENABLE; + wr32(E1000_TXDCTL(reg_idx), txdctl); ++ ++ netdev_tx_reset_queue(txring_txq(ring)); + } + + /** +@@ -3244,7 +3246,6 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring) + buffer_info = &tx_ring->tx_buffer_info[i]; + igb_unmap_and_free_tx_resource(tx_ring, buffer_info); + } +- netdev_tx_reset_queue(txring_txq(tx_ring)); + + size = sizeof(struct igb_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index b195a34..4bf314f 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1939,6 +1939,7 @@ static inline void netdev_completed_queue(struct net_device *dev, + static inline void netdev_tx_reset_queue(struct netdev_queue *q) + { + #ifdef CONFIG_BQL ++ clear_bit(__QUEUE_STATE_STACK_XOFF, &q->state); + dql_reset(&q->dql); + #endif + } diff --git a/debian/patches/features/all/bql/net-new-counter-for-tx_timeout-errors-in-sysfs.patch b/debian/patches/features/all/bql/net-new-counter-for-tx_timeout-errors-in-sysfs.patch new file mode 100644 index 000000000..06874a684 --- /dev/null +++ b/debian/patches/features/all/bql/net-new-counter-for-tx_timeout-errors-in-sysfs.patch @@ -0,0 +1,189 @@ +From: david decotigny +Date: Wed, 16 Nov 2011 12:15:10 +0000 +Subject: net: new counter for tx_timeout errors in sysfs + +commit ccf5ff69fbbd8d877377f5786369cf5aa78a15fc upstream. + +This adds the /sys/class/net/DEV/queues/Q/tx_timeout attribute +containing the total number of timeout events on the given queue. It +is always available with CONFIG_SYSFS, independently of +CONFIG_RPS/XPS. + +Credits to Stephen Hemminger for a preliminary version of this patch. + +Tested: + without CONFIG_SYSFS (compilation only) + with sysfs and without CONFIG_RPS & CONFIG_XPS + with sysfs and without CONFIG_RPS + with sysfs and without CONFIG_XPS + with defaults + +Signed-off-by: David Decotigny +Signed-off-by: David S. Miller +--- + include/linux/netdevice.h | 12 ++++++++++-- + net/core/net-sysfs.c | 37 +++++++++++++++++++++++++++++++------ + net/sched/sch_generic.c | 1 + + 3 files changed, 42 insertions(+), 8 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 31da3bb..4d5698a 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -532,7 +532,7 @@ struct netdev_queue { + struct Qdisc *qdisc; + unsigned long state; + struct Qdisc *qdisc_sleeping; +-#if defined(CONFIG_RPS) || defined(CONFIG_XPS) ++#ifdef CONFIG_SYSFS + struct kobject kobj; + #endif + #if defined(CONFIG_XPS) && defined(CONFIG_NUMA) +@@ -547,6 +547,12 @@ struct netdev_queue { + * please use this field instead of dev->trans_start + */ + unsigned long trans_start; ++ ++ /* ++ * Number of TX timeouts for this queue ++ * (/sys/class/net/DEV/Q/trans_timeout) ++ */ ++ unsigned long trans_timeout; + } ____cacheline_aligned_in_smp; + + static inline int netdev_queue_numa_node_read(const struct netdev_queue *q) +@@ -1109,9 +1115,11 @@ struct net_device { + + unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ + +-#if defined(CONFIG_RPS) || defined(CONFIG_XPS) ++#ifdef CONFIG_SYSFS + struct kset *queues_kset; ++#endif + ++#ifdef CONFIG_RPS + struct netdev_rx_queue *_rx; + + /* Number of RX queues allocated at register_netdev() time */ +diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c +index a64382f..602b141 100644 +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -780,7 +780,7 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) + #endif + } + +-#ifdef CONFIG_XPS ++#ifdef CONFIG_SYSFS + /* + * netdev_queue sysfs structures and functions. + */ +@@ -826,6 +826,23 @@ static const struct sysfs_ops netdev_queue_sysfs_ops = { + .store = netdev_queue_attr_store, + }; + ++static ssize_t show_trans_timeout(struct netdev_queue *queue, ++ struct netdev_queue_attribute *attribute, ++ char *buf) ++{ ++ unsigned long trans_timeout; ++ ++ spin_lock_irq(&queue->_xmit_lock); ++ trans_timeout = queue->trans_timeout; ++ spin_unlock_irq(&queue->_xmit_lock); ++ ++ return sprintf(buf, "%lu", trans_timeout); ++} ++ ++static struct netdev_queue_attribute queue_trans_timeout = ++ __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL); ++ ++#ifdef CONFIG_XPS + static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue) + { + struct net_device *dev = queue->dev; +@@ -1020,12 +1037,17 @@ error: + + static struct netdev_queue_attribute xps_cpus_attribute = + __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map); ++#endif /* CONFIG_XPS */ + + static struct attribute *netdev_queue_default_attrs[] = { ++ &queue_trans_timeout.attr, ++#ifdef CONFIG_XPS + &xps_cpus_attribute.attr, ++#endif + NULL + }; + ++#ifdef CONFIG_XPS + static void netdev_queue_release(struct kobject *kobj) + { + struct netdev_queue *queue = to_netdev_queue(kobj); +@@ -1076,10 +1098,13 @@ static void netdev_queue_release(struct kobject *kobj) + memset(kobj, 0, sizeof(*kobj)); + dev_put(queue->dev); + } ++#endif /* CONFIG_XPS */ + + static struct kobj_type netdev_queue_ktype = { + .sysfs_ops = &netdev_queue_sysfs_ops, ++#ifdef CONFIG_XPS + .release = netdev_queue_release, ++#endif + .default_attrs = netdev_queue_default_attrs, + }; + +@@ -1102,12 +1127,12 @@ static int netdev_queue_add_kobject(struct net_device *net, int index) + + return error; + } +-#endif /* CONFIG_XPS */ ++#endif /* CONFIG_SYSFS */ + + int + netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) + { +-#ifdef CONFIG_XPS ++#ifdef CONFIG_SYSFS + int i; + int error = 0; + +@@ -1125,14 +1150,14 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) + return error; + #else + return 0; +-#endif ++#endif /* CONFIG_SYSFS */ + } + + static int register_queue_kobjects(struct net_device *net) + { + int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; + +-#if defined(CONFIG_RPS) || defined(CONFIG_XPS) ++#ifdef CONFIG_SYSFS + net->queues_kset = kset_create_and_add("queues", + NULL, &net->dev.kobj); + if (!net->queues_kset) +@@ -1173,7 +1198,7 @@ static void remove_queue_kobjects(struct net_device *net) + + net_rx_queue_update_kobjects(net, real_rx, 0); + netdev_queue_update_kobjects(net, real_tx, 0); +-#if defined(CONFIG_RPS) || defined(CONFIG_XPS) ++#ifdef CONFIG_SYSFS + kset_unregister(net->queues_kset); + #endif + } +diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c +index 69fca27..79ac145 100644 +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -246,6 +246,7 @@ static void dev_watchdog(unsigned long arg) + time_after(jiffies, (trans_start + + dev->watchdog_timeo))) { + some_queue_timedout = 1; ++ txq->trans_timeout++; + break; + } + } diff --git a/debian/patches/features/all/bql/r8169-add-byte-queue-limit-support.patch b/debian/patches/features/all/bql/r8169-add-byte-queue-limit-support.patch new file mode 100644 index 000000000..6ea3c4b52 --- /dev/null +++ b/debian/patches/features/all/bql/r8169-add-byte-queue-limit-support.patch @@ -0,0 +1,85 @@ +From: Igor Maravic +Date: Mon, 5 Mar 2012 00:01:25 +0100 +Subject: r8169: add byte queue limit support. + +commit 036dafa28da1e2565a8529de2ae663c37b7a0060 upstream. + +Nothing fancy: +- sent bytes count is notified in the start_xmit path right before + updating the owner bit in the hardware Tx descriptor (E. Dumazet) +- avoid useless tp->dev dereferencing in start_xmit (E. Dumazet) + +Use of netdev_reset_queue is favored over proper accounting in +rtl8169_tx_clear_range since the latter would need more work for the +same result (nb: said accounting degenerates to nothing in xmit_frags). + +Signed-off-by: Igor Maravic +Signed-off-by: Francois Romieu +Acked-by: Eric Dumazet +[bwh: Backported to 3.2: + - Adjust context + - Don't use 64-bit stats] +--- +--- a/drivers/net/ethernet/realtek/r8169.c ++++ b/drivers/net/ethernet/realtek/r8169.c +@@ -5340,6 +5340,7 @@ + { + rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC); + tp->cur_tx = tp->dirty_tx = 0; ++ netdev_reset_queue(tp->dev); + } + + static void rtl8169_schedule_work(struct net_device *dev, work_func_t task) +@@ -5552,6 +5553,8 @@ + + txd->opts2 = cpu_to_le32(opts[1]); + ++ netdev_sent_queue(dev, skb->len); ++ + wmb(); + + /* Anti gcc 2.95.3 bugware (sic) */ +@@ -5644,11 +5647,17 @@ + rtl8169_schedule_work(dev, rtl8169_reinit_task); + } + ++struct rtl_txc { ++ int packets; ++ int bytes; ++}; ++ + static void rtl8169_tx_interrupt(struct net_device *dev, + struct rtl8169_private *tp, + void __iomem *ioaddr) + { + unsigned int dirty_tx, tx_left; ++ struct rtl_txc txc = { 0, 0 }; + + dirty_tx = tp->dirty_tx; + smp_rmb(); +@@ -5667,15 +5676,22 @@ + rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb, + tp->TxDescArray + entry); + if (status & LastFrag) { +- dev->stats.tx_packets++; +- dev->stats.tx_bytes += tx_skb->skb->len; +- dev_kfree_skb(tx_skb->skb); ++ struct sk_buff *skb = tx_skb->skb; ++ ++ txc.packets++; ++ txc.bytes += skb->len; ++ dev_kfree_skb(skb); + tx_skb->skb = NULL; + } + dirty_tx++; + tx_left--; + } + ++ dev->stats.tx_packets += txc.packets; ++ dev->stats.tx_bytes += txc.bytes; ++ ++ netdev_completed_queue(dev, txc.packets, txc.bytes); ++ + if (tp->dirty_tx != dirty_tx) { + tp->dirty_tx = dirty_tx; + /* Sync with rtl8169_start_xmit: diff --git a/debian/patches/features/all/bql/sfc-fix-race-in-efx_enqueue_skb_tso.patch b/debian/patches/features/all/bql/sfc-fix-race-in-efx_enqueue_skb_tso.patch new file mode 100644 index 000000000..e21fda039 --- /dev/null +++ b/debian/patches/features/all/bql/sfc-fix-race-in-efx_enqueue_skb_tso.patch @@ -0,0 +1,33 @@ +From: Eric Dumazet +Date: Wed, 30 Nov 2011 17:12:27 -0500 +Subject: sfc: fix race in efx_enqueue_skb_tso() + +commit 449fa023bca5b53bd924d91a27ffd34807fdeb80 upstream. + +As soon as skb is pushed to hardware, it can be completed and freed, so +we should not dereference skb anymore. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/sfc/tx.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c +index ab4c635..e0e00b3 100644 +--- a/drivers/net/ethernet/sfc/tx.c ++++ b/drivers/net/ethernet/sfc/tx.c +@@ -1173,11 +1173,11 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, + goto mem_err; + } + ++ netdev_tx_sent_queue(tx_queue->core_txq, skb->len); ++ + /* Pass off to hardware */ + efx_nic_push_buffers(tx_queue); + +- netdev_tx_sent_queue(tx_queue->core_txq, skb->len); +- + tx_queue->tso_bursts++; + return NETDEV_TX_OK; + diff --git a/debian/patches/features/all/bql/sfc-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/sfc-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..8752b910b --- /dev/null +++ b/debian/patches/features/all/bql/sfc-support-for-byte-queue-limits.patch @@ -0,0 +1,121 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:43 +0000 +Subject: sfc: Support for byte queue limits + +commit c3940999b29ca7d6ad9b37b827a058c90fd51992 upstream. + +Changes to sfc to use byte queue limits. + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/sfc/tx.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c +index df88c543..ab4c635 100644 +--- a/drivers/net/ethernet/sfc/tx.c ++++ b/drivers/net/ethernet/sfc/tx.c +@@ -31,7 +31,9 @@ + #define EFX_TXQ_THRESHOLD(_efx) ((_efx)->txq_entries / 2u) + + static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, +- struct efx_tx_buffer *buffer) ++ struct efx_tx_buffer *buffer, ++ unsigned int *pkts_compl, ++ unsigned int *bytes_compl) + { + if (buffer->unmap_len) { + struct pci_dev *pci_dev = tx_queue->efx->pci_dev; +@@ -48,6 +50,8 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, + } + + if (buffer->skb) { ++ (*pkts_compl)++; ++ (*bytes_compl) += buffer->skb->len; + dev_kfree_skb_any((struct sk_buff *) buffer->skb); + buffer->skb = NULL; + netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev, +@@ -250,6 +254,8 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) + buffer->skb = skb; + buffer->continuation = false; + ++ netdev_tx_sent_queue(tx_queue->core_txq, skb->len); ++ + /* Pass off to hardware */ + efx_nic_push_buffers(tx_queue); + +@@ -267,10 +273,11 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) + unwind: + /* Work backwards until we hit the original insert pointer value */ + while (tx_queue->insert_count != tx_queue->write_count) { ++ unsigned int pkts_compl = 0, bytes_compl = 0; + --tx_queue->insert_count; + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; + buffer = &tx_queue->buffer[insert_ptr]; +- efx_dequeue_buffer(tx_queue, buffer); ++ efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl); + buffer->len = 0; + } + +@@ -293,7 +300,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) + * specified index. + */ + static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, +- unsigned int index) ++ unsigned int index, ++ unsigned int *pkts_compl, ++ unsigned int *bytes_compl) + { + struct efx_nic *efx = tx_queue->efx; + unsigned int stop_index, read_ptr; +@@ -311,7 +320,7 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, + return; + } + +- efx_dequeue_buffer(tx_queue, buffer); ++ efx_dequeue_buffer(tx_queue, buffer, pkts_compl, bytes_compl); + buffer->continuation = true; + buffer->len = 0; + +@@ -422,10 +431,12 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) + { + unsigned fill_level; + struct efx_nic *efx = tx_queue->efx; ++ unsigned int pkts_compl = 0, bytes_compl = 0; + + EFX_BUG_ON_PARANOID(index > tx_queue->ptr_mask); + +- efx_dequeue_buffers(tx_queue, index); ++ efx_dequeue_buffers(tx_queue, index, &pkts_compl, &bytes_compl); ++ netdev_tx_completed_queue(tx_queue->core_txq, pkts_compl, bytes_compl); + + /* See if we need to restart the netif queue. This barrier + * separates the update of read_count from the test of the +@@ -515,13 +526,15 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) + + /* Free any buffers left in the ring */ + while (tx_queue->read_count != tx_queue->write_count) { ++ unsigned int pkts_compl = 0, bytes_compl = 0; + buffer = &tx_queue->buffer[tx_queue->read_count & tx_queue->ptr_mask]; +- efx_dequeue_buffer(tx_queue, buffer); ++ efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl); + buffer->continuation = true; + buffer->len = 0; + + ++tx_queue->read_count; + } ++ netdev_tx_reset_queue(tx_queue->core_txq); + } + + void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) +@@ -1163,6 +1176,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, + /* Pass off to hardware */ + efx_nic_push_buffers(tx_queue); + ++ netdev_tx_sent_queue(tx_queue->core_txq, skb->len); ++ + tx_queue->tso_bursts++; + return NETDEV_TX_OK; + diff --git a/debian/patches/features/all/bql/skge-add-byte-queue-limit-support.patch b/debian/patches/features/all/bql/skge-add-byte-queue-limit-support.patch new file mode 100644 index 000000000..7f7b0a306 --- /dev/null +++ b/debian/patches/features/all/bql/skge-add-byte-queue-limit-support.patch @@ -0,0 +1,104 @@ +From: stephen hemminger +Date: Sun, 22 Jan 2012 09:40:40 +0000 +Subject: skge: add byte queue limit support + +commit da057fb7d272c7e7609465a54bcac8ec8072ead5 upstream. + +This also changes the cleanup logic slightly to aggregate +completed notifications for multiple packets. + +Signed-off-by: Stephen Hemminger +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/skge.c | 37 +++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c +index 299c33b..edb9bda 100644 +--- a/drivers/net/ethernet/marvell/skge.c ++++ b/drivers/net/ethernet/marvell/skge.c +@@ -2817,6 +2817,8 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, + td->control = BMU_OWN | BMU_SW | BMU_STF | control | len; + wmb(); + ++ netdev_sent_queue(dev, skb->len); ++ + skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START); + + netif_printk(skge, tx_queued, KERN_DEBUG, skge->netdev, +@@ -2858,11 +2860,9 @@ mapping_error: + + + /* Free resources associated with this reing element */ +-static void skge_tx_free(struct skge_port *skge, struct skge_element *e, +- u32 control) ++static inline void skge_tx_unmap(struct pci_dev *pdev, struct skge_element *e, ++ u32 control) + { +- struct pci_dev *pdev = skge->hw->pdev; +- + /* skb header vs. fragment */ + if (control & BMU_STF) + pci_unmap_single(pdev, dma_unmap_addr(e, mapaddr), +@@ -2872,13 +2872,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, + pci_unmap_page(pdev, dma_unmap_addr(e, mapaddr), + dma_unmap_len(e, maplen), + PCI_DMA_TODEVICE); +- +- if (control & BMU_EOF) { +- netif_printk(skge, tx_done, KERN_DEBUG, skge->netdev, +- "tx done slot %td\n", e - skge->tx_ring.start); +- +- dev_kfree_skb(e->skb); +- } + } + + /* Free all buffers in transmit ring */ +@@ -2889,10 +2882,15 @@ static void skge_tx_clean(struct net_device *dev) + + for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) { + struct skge_tx_desc *td = e->desc; +- skge_tx_free(skge, e, td->control); ++ ++ skge_tx_unmap(skge->hw->pdev, e, td->control); ++ ++ if (td->control & BMU_EOF) ++ dev_kfree_skb(e->skb); + td->control = 0; + } + ++ netdev_reset_queue(dev); + skge->tx_ring.to_clean = e; + } + +@@ -3157,6 +3155,7 @@ static void skge_tx_done(struct net_device *dev) + struct skge_port *skge = netdev_priv(dev); + struct skge_ring *ring = &skge->tx_ring; + struct skge_element *e; ++ unsigned int bytes_compl = 0, pkts_compl = 0; + + skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); + +@@ -3166,8 +3165,20 @@ static void skge_tx_done(struct net_device *dev) + if (control & BMU_OWN) + break; + +- skge_tx_free(skge, e, control); ++ skge_tx_unmap(skge->hw->pdev, e, control); ++ ++ if (control & BMU_EOF) { ++ netif_printk(skge, tx_done, KERN_DEBUG, skge->netdev, ++ "tx done slot %td\n", ++ e - skge->tx_ring.start); ++ ++ pkts_compl++; ++ bytes_compl += e->skb->len; ++ ++ dev_kfree_skb(e->skb); ++ } + } ++ netdev_completed_queue(dev, pkts_compl, bytes_compl); + skge->tx_ring.to_clean = e; + + /* Can run lockless until we need to synchronize to restart queue. */ diff --git a/debian/patches/features/all/bql/sky2-add-bql-support.patch b/debian/patches/features/all/bql/sky2-add-bql-support.patch new file mode 100644 index 000000000..318bcbe45 --- /dev/null +++ b/debian/patches/features/all/bql/sky2-add-bql-support.patch @@ -0,0 +1,72 @@ +From: stephen hemminger +Date: Tue, 29 Nov 2011 15:15:33 +0000 +Subject: sky2: add bql support + +commit ec2a5466b3ce680c92e8e05617b020fd825854b9 upstream. + +This adds support for byte queue limits and aggregates statistics +update (suggestion from Eric). + +Signed-off-by: Stephen Hemminger +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/sky2.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c +index 29adc78..760c2b1 100644 +--- a/drivers/net/ethernet/marvell/sky2.c ++++ b/drivers/net/ethernet/marvell/sky2.c +@@ -1110,6 +1110,7 @@ static void tx_init(struct sky2_port *sky2) + sky2->tx_prod = sky2->tx_cons = 0; + sky2->tx_tcpsum = 0; + sky2->tx_last_mss = 0; ++ netdev_reset_queue(sky2->netdev); + + le = get_tx_le(sky2, &sky2->tx_prod); + le->addr = 0; +@@ -1971,6 +1972,7 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb, + if (tx_avail(sky2) <= MAX_SKB_TX_LE) + netif_stop_queue(dev); + ++ netdev_sent_queue(dev, skb->len); + sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); + + return NETDEV_TX_OK; +@@ -2002,7 +2004,8 @@ mapping_error: + static void sky2_tx_complete(struct sky2_port *sky2, u16 done) + { + struct net_device *dev = sky2->netdev; +- unsigned idx; ++ u16 idx; ++ unsigned int bytes_compl = 0, pkts_compl = 0; + + BUG_ON(done >= sky2->tx_ring_size); + +@@ -2017,10 +2020,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) + netif_printk(sky2, tx_done, KERN_DEBUG, dev, + "tx done %u\n", idx); + +- u64_stats_update_begin(&sky2->tx_stats.syncp); +- ++sky2->tx_stats.packets; +- sky2->tx_stats.bytes += skb->len; +- u64_stats_update_end(&sky2->tx_stats.syncp); ++ pkts_compl++; ++ bytes_compl += skb->len; + + re->skb = NULL; + dev_kfree_skb_any(skb); +@@ -2031,6 +2032,13 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) + + sky2->tx_cons = idx; + smp_mb(); ++ ++ netdev_completed_queue(dev, pkts_compl, bytes_compl); ++ ++ u64_stats_update_begin(&sky2->tx_stats.syncp); ++ sky2->tx_stats.packets += pkts_compl; ++ sky2->tx_stats.bytes += bytes_compl; ++ u64_stats_update_end(&sky2->tx_stats.syncp); + } + + static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) diff --git a/debian/patches/features/all/bql/tg3-fix-to-use-multi-queue-bql-interfaces.patch b/debian/patches/features/all/bql/tg3-fix-to-use-multi-queue-bql-interfaces.patch new file mode 100644 index 000000000..366e9bb37 --- /dev/null +++ b/debian/patches/features/all/bql/tg3-fix-to-use-multi-queue-bql-interfaces.patch @@ -0,0 +1,49 @@ +From: Tom Herbert +Date: Mon, 5 Mar 2012 19:53:50 +0000 +Subject: tg3: Fix to use multi queue BQL interfaces + +commit 5cb917bc4f3882ecee87064483111023086757d3 upstream. + +Fix tg3 to use BQL multi queue related netdev interfaces since the +device supports multi queue. + +Signed-off-by: Tom Herbert +Reported-by: Christoph Lameter +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/tg3.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index 423d023..35c2a20 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -5352,7 +5352,7 @@ static void tg3_tx(struct tg3_napi *tnapi) + } + } + +- netdev_completed_queue(tp->dev, pkts_compl, bytes_compl); ++ netdev_tx_completed_queue(txq, pkts_compl, bytes_compl); + + tnapi->tx_cons = sw_idx; + +@@ -6793,7 +6793,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) + } + + skb_tx_timestamp(skb); +- netdev_sent_queue(tp->dev, skb->len); ++ netdev_tx_sent_queue(txq, skb->len); + + /* Packets are ready, update Tx producer idx local and on card. */ + tw32_tx_mbox(tnapi->prodmbox, entry); +@@ -7275,8 +7275,8 @@ static void tg3_free_rings(struct tg3 *tp) + + dev_kfree_skb_any(skb); + } ++ netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j)); + } +- netdev_reset_queue(tp->dev); + } + + /* Initialize tx/rx rings for packet processing. diff --git a/debian/patches/features/all/bql/tg3-support-for-byte-queue-limits.patch b/debian/patches/features/all/bql/tg3-support-for-byte-queue-limits.patch new file mode 100644 index 000000000..d34684d15 --- /dev/null +++ b/debian/patches/features/all/bql/tg3-support-for-byte-queue-limits.patch @@ -0,0 +1,62 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:30 +0000 +Subject: tg3: Support for byte queue limits + +commit 298376d3e8f00147548c426959ce79efc47b669a upstream. + +Changes to tg3 to use byte queue limits. + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/tg3.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index aa413d6..cf36312 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -5302,6 +5302,7 @@ static void tg3_tx(struct tg3_napi *tnapi) + u32 sw_idx = tnapi->tx_cons; + struct netdev_queue *txq; + int index = tnapi - tp->napi; ++ unsigned int pkts_compl = 0, bytes_compl = 0; + + if (tg3_flag(tp, ENABLE_TSS)) + index--; +@@ -5352,6 +5353,9 @@ static void tg3_tx(struct tg3_napi *tnapi) + sw_idx = NEXT_TX(sw_idx); + } + ++ pkts_compl++; ++ bytes_compl += skb->len; ++ + dev_kfree_skb(skb); + + if (unlikely(tx_bug)) { +@@ -5360,6 +5364,8 @@ static void tg3_tx(struct tg3_napi *tnapi) + } + } + ++ netdev_completed_queue(tp->dev, pkts_compl, bytes_compl); ++ + tnapi->tx_cons = sw_idx; + + /* Need to make the tx_cons update visible to tg3_start_xmit() +@@ -6804,6 +6810,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) + } + + skb_tx_timestamp(skb); ++ netdev_sent_queue(tp->dev, skb->len); + + /* Packets are ready, update Tx producer idx local and on card. */ + tw32_tx_mbox(tnapi->prodmbox, entry); +@@ -7286,6 +7293,7 @@ static void tg3_free_rings(struct tg3 *tp) + dev_kfree_skb_any(skb); + } + } ++ netdev_reset_queue(tp->dev); + } + + /* Initialize tx/rx rings for packet processing. diff --git a/debian/patches/features/all/bql/xps-add-xps_queue_release-function.patch b/debian/patches/features/all/bql/xps-add-xps_queue_release-function.patch new file mode 100644 index 000000000..52313eab5 --- /dev/null +++ b/debian/patches/features/all/bql/xps-add-xps_queue_release-function.patch @@ -0,0 +1,126 @@ +From: Tom Herbert +Date: Mon, 28 Nov 2011 16:33:02 +0000 +Subject: xps: Add xps_queue_release function + +commit 927fbec13e40648d3c87cbb1daaac5b1fb9c8775 upstream. + +This patch moves the xps specific parts in netdev_queue_release into +its own function which netdev_queue_release can call. This allows +netdev_queue_release to be more generic (for adding new attributes +to tx queues). + +Signed-off-by: Tom Herbert +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + net/core/net-sysfs.c | 89 ++++++++++++++++++++++++++------------------------ + 1 file changed, 47 insertions(+), 42 deletions(-) + +diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c +index db6c2f8..b17c14a 100644 +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -910,6 +910,52 @@ static DEFINE_MUTEX(xps_map_mutex); + #define xmap_dereference(P) \ + rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex)) + ++static void xps_queue_release(struct netdev_queue *queue) ++{ ++ struct net_device *dev = queue->dev; ++ struct xps_dev_maps *dev_maps; ++ struct xps_map *map; ++ unsigned long index; ++ int i, pos, nonempty = 0; ++ ++ index = get_netdev_queue_index(queue); ++ ++ mutex_lock(&xps_map_mutex); ++ dev_maps = xmap_dereference(dev->xps_maps); ++ ++ if (dev_maps) { ++ for_each_possible_cpu(i) { ++ map = xmap_dereference(dev_maps->cpu_map[i]); ++ if (!map) ++ continue; ++ ++ for (pos = 0; pos < map->len; pos++) ++ if (map->queues[pos] == index) ++ break; ++ ++ if (pos < map->len) { ++ if (map->len > 1) ++ map->queues[pos] = ++ map->queues[--map->len]; ++ else { ++ RCU_INIT_POINTER(dev_maps->cpu_map[i], ++ NULL); ++ kfree_rcu(map, rcu); ++ map = NULL; ++ } ++ } ++ if (map) ++ nonempty = 1; ++ } ++ ++ if (!nonempty) { ++ RCU_INIT_POINTER(dev->xps_maps, NULL); ++ kfree_rcu(dev_maps, rcu); ++ } ++ } ++ mutex_unlock(&xps_map_mutex); ++} ++ + static ssize_t store_xps_map(struct netdev_queue *queue, + struct netdev_queue_attribute *attribute, + const char *buf, size_t len) +@@ -1054,49 +1100,8 @@ static struct attribute *netdev_queue_default_attrs[] = { + static void netdev_queue_release(struct kobject *kobj) + { + struct netdev_queue *queue = to_netdev_queue(kobj); +- struct net_device *dev = queue->dev; +- struct xps_dev_maps *dev_maps; +- struct xps_map *map; +- unsigned long index; +- int i, pos, nonempty = 0; +- +- index = get_netdev_queue_index(queue); +- +- mutex_lock(&xps_map_mutex); +- dev_maps = xmap_dereference(dev->xps_maps); + +- if (dev_maps) { +- for_each_possible_cpu(i) { +- map = xmap_dereference(dev_maps->cpu_map[i]); +- if (!map) +- continue; +- +- for (pos = 0; pos < map->len; pos++) +- if (map->queues[pos] == index) +- break; +- +- if (pos < map->len) { +- if (map->len > 1) +- map->queues[pos] = +- map->queues[--map->len]; +- else { +- RCU_INIT_POINTER(dev_maps->cpu_map[i], +- NULL); +- kfree_rcu(map, rcu); +- map = NULL; +- } +- } +- if (map) +- nonempty = 1; +- } +- +- if (!nonempty) { +- RCU_INIT_POINTER(dev->xps_maps, NULL); +- kfree_rcu(dev_maps, rcu); +- } +- } +- +- mutex_unlock(&xps_map_mutex); ++ xps_queue_release(queue); + + memset(kobj, 0, sizeof(*kobj)); + dev_put(queue->dev); diff --git a/debian/patches/series b/debian/patches/series index a06f1c660..9680edde9 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -357,3 +357,36 @@ bugfix/all/cipso-don-t-follow-a-NULL-pointer-when-setsockopt-is.patch features/all/debugfs-add-mode-uid-and-gid-options.patch debian/debugfs-set-default-mode-to-700.patch + +# Byte Queue Limits from 3.3; fixes and additional driver support from 3.4, 3.5 +features/all/bql/net-new-counter-for-tx_timeout-errors-in-sysfs.patch +features/all/bql/dql-dynamic-queue-limits.patch +features/all/bql/net-add-queue-state-xoff-flag-for-stack.patch +features/all/bql/net-add-netdev-interfaces-for-recording-sends-comp.patch +features/all/bql/xps-add-xps_queue_release-function.patch +features/all/bql/bql-byte-queue-limits.patch +features/all/bql/bql-fix-config_xps-n-build.patch +features/all/bql/bql-fix-inconsistency-between-file-mode-and-attr-method.patch +features/all/bql/dql-fix-undefined-jiffies.patch +features/all/bql/bql-fix-posdiff-to-integer-overflow-aware.patch +features/all/bql/bql-avoid-unneeded-limit-decrement.patch +features/all/bql/bql-avoid-possible-inconsistent-calculation.patch +features/all/bql/e1000e-support-for-byte-queue-limits.patch +features/all/bql/forcedeth-support-for-byte-queue-limits.patch +features/all/bql/forcedeath-fix-bql-support-for-forcedeath.patch +features/all/bql/tg3-support-for-byte-queue-limits.patch +features/all/bql/tg3-fix-to-use-multi-queue-bql-interfaces.patch +features/all/bql/bnx2x-remove-unused-variable.patch +features/all/bql/bnx2x-support-for-byte-queue-limits.patch +features/all/bql/bnx2x-fix-crash-while-ethtool-t.patch +features/all/bql/sfc-support-for-byte-queue-limits.patch +features/all/bql/sfc-fix-race-in-efx_enqueue_skb_tso.patch +features/all/bql/sky2-add-bql-support.patch +features/all/bql/bnx2-support-for-byte-queue-limits.patch +features/all/bql/igb-add-support-for-byte-queue-limits.patch +features/all/bql/igb-fix-ethtool-offline-test.patch +features/all/bql/net-fix-issue-with-netdev_tx_reset_queue-not-resetting-queue-from.patch +features/all/bql/ixgbe-add-support-for-byte-queue-limits.patch +features/all/bql/igb-ixgbe-netdev_tx_reset_queue-incorrectly-called-from-tx-init.patch +features/all/bql/skge-add-byte-queue-limit-support.patch +features/all/bql/r8169-add-byte-queue-limit-support.patch