This was added as of v2.6.35. We implement a slightly
modified version given that this was later changed
to return int through commit
e6484930. The changes
on
e6484930 however were added due to some internal
changes on core networking, we'll leave in place
a simpler implementation for older kernels.
Note that for older kernels than 2.6.27 we use
the netdev egress_subqueue_count to set the TX
queue count. Commit
fd2ea0a7 added real_num_tx_queues
to the netdevice when Multiqueue was added.
mcgrof@frijol ~/linux-next (git::master)$ git describe --contains
f0796d5c73e59786d09a1e617689d1d415f2db44
v2.6.35-rc5~14^2~14
mcgrof@frijol ~/linux-next (git::master)$ git describe --contains
3171d026
v2.6.37-rc1~147^2~339
mcgrof@frijol ~/linux-next (git::master)$ git describe --contains
fd2ea0a7
v2.6.27-rc1~964^2~78
commit
f0796d5c73e59786d09a1e617689d1d415f2db44
Author: John Fastabend <john.r.fastabend@intel.com>
Date: Thu Jul 1 13:21:57 2010 +0000
net: decreasing real_num_tx_queues needs to flush qdisc
Reducing real_num_queues needs to flush the qdisc otherwise
skbs with queue_mappings greater then real_num_tx_queues can
be sent to the underlying driver.
The flow for this is,
dev_queue_xmit()
dev_pick_tx()
skb_tx_hash() => hash using real_num_tx_queues
skb_set_queue_mapping()
...
qdisc_enqueue_root() => enqueue skb on txq from hash
...
dev->real_num_tx_queues -= n
...
sch_direct_xmit()
dev_hard_start_xmit()
ndo_start_xmit(skb,dev) => skb queue set with old hash
skbs are enqueued on the qdisc with skb->queue_mapping set
0 < queue_mappings < real_num_tx_queues. When the driver
decreases real_num_tx_queues skb's may be dequeued from the
qdisc with a queue_mapping greater then real_num_tx_queues.
This fixes a case in ixgbe where this was occurring with DCB
and FCoE. Because the driver is using queue_mapping to map
skbs to tx descriptor rings we can potentially map skbs to
rings that no longer exist.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
commit
e6484930d7c73d324bccda7d43d131088da697b9
Author: Tom Herbert <therbert@google.com>
Date: Mon Oct 18 18:04:39 2010 +0000
net: allocate tx queues in register_netdevice
This patch introduces netif_alloc_netdev_queues which is called from
register_device instead of alloc_netdev_mq. This makes TX queue
allocation symmetric with RX allocation. Also, queue locks allocation
is done in netdev_init_one_queue. Change set_real_num_tx_queues to
fail if requested number < 1 or greater than number of allocated
queues.
Signed-off-by: Tom Herbert <therbert@google.com>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
commit
fd2ea0a79faad824258af5dcec1927aa24d81c16
Author: David S. Miller <davem@davemloft.net>
Date: Thu Jul 17 01:56:23 2008 -0700
net: Use queue aware tests throughout.
This effectively "flips the switch" by making the core networking
and multiqueue-aware drivers use the new TX multiqueue structures.
Non-multiqueue drivers need no changes. The interfaces they use such
as netif_stop_queue() degenerate into an operation on TX queue zero.
So everything "just works" for them.
Code that really wants to do "X" to all TX queues now invokes a
routine that does so, such as netif_tx_wake_all_queues(),
netif_tx_stop_all_queues(), etc.
pktgen and netpoll required a little bit more surgery than the others.
In particular the pktgen changes, whilst functional, could be largely
improved. The initial check in pktgen_xmit() will sometimes check the
wrong queue, which is mostly harmless. The thing to do is probably to
invoke fill_packet() earlier.
The bulk of the netpoll changes is to make the code operate solely on
the TX queue indicated by by the SKB queue mapping.
Setting of the SKB queue mapping is entirely confined inside of
net/core/dev.c:dev_pick_tx(). If we end up needing any kind of
special semantics (drops, for example) it will be implemented here.
Finally, we now have a "real_num_tx_queues" which is where the driver
indicates how many TX queues are actually active.
With IGB changes from Jeff Kirsher.
Signed-off-by: David S. Miller <davem@davemloft.net>
mcgrof@drvbp1 ~/compat (git::master)$ time ckmake
Trying kernel 3.6.5-030605-generic [OK]
Trying kernel 3.5.7-030507-generic [OK]
Trying kernel 3.4.17-030417-generic [OK]
Trying kernel 3.3.8-030308-generic [OK]
Trying kernel 3.2.33-030233-generic [OK]
Trying kernel 3.1.10-030110-generic [OK]
Trying kernel 3.0.50-030050-generic [OK]
Trying kernel 2.6.39-
02063904-generic [OK]
Trying kernel 2.6.38-
02063808-generic [OK]
Trying kernel 2.6.37-
02063706-generic [OK]
Trying kernel 2.6.36-
02063604-generic [OK]
Trying kernel 2.6.35-
02063513-generic [OK]
Trying kernel 2.6.34-
02063413-generic [OK]
Trying kernel 2.6.33-
02063320-generic [OK]
Trying kernel 2.6.32-
02063260-generic [OK]
Trying kernel 2.6.31-
02063113-generic [OK]
Trying kernel 2.6.30-
02063010-generic [OK]
Trying kernel 2.6.29-
02062906-generic [OK]
Trying kernel 2.6.28-
02062810-generic [OK]
Trying kernel 2.6.27-020627-generic [OK]
Trying kernel 2.6.26-020626-generic [OK]
Trying kernel 2.6.25-020625-generic [OK]
Trying kernel 2.6.24-020624-generic [OK]
real 1m51.110s
user 4m58.571s
sys 1m39.282s
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
/*
* Copyright 2010 Kshitij Kulshreshtha <kkhere.geo@gmail.com>
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <linux/compat.h>
#include <linux/ctype.h>
+/*
+ * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
+ * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+{
+ unsigned int real_num = dev->real_num_tx_queues;
+
+ if (unlikely(txq > dev->num_tx_queues))
+ return -EINVAL;
+ else if (txq > real_num)
+ dev->real_num_tx_queues = txq;
+ else if (txq < real_num) {
+ dev->real_num_tx_queues = txq;
+ qdisc_reset_all_tx_gt(dev, txq);
+ }
+}
+#else
+int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+{
+ dev->egress_subqueue_count = txq;
+ /* XXX: consider qdisc reset for older kernels */
+}
+#endif
+EXPORT_SYMBOL_GPL(netif_set_real_num_tx_queues);
+
/**
* hex_to_bin - convert a hex digit to its real value
* @ch: ascii character represents hex digit
#include <net/sock.h>
#include <linux/types.h>
#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <net/sch_generic.h>
/* added on linux/kernel.h */
#define USHRT_MAX ((u16)(~0U))
#define netdev_hw_addr dev_mc_list
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+/* Reset all TX qdiscs greater then index of a device. */
+static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
+{
+ struct Qdisc *qdisc;
+
+ for (; i < dev->num_tx_queues; i++) {
+ qdisc = netdev_get_tx_queue(dev, i)->qdisc;
+ if (qdisc) {
+ spin_lock_bh(qdisc_lock(qdisc));
+ qdisc_reset(qdisc);
+ spin_unlock_bh(qdisc_lock(qdisc));
+ }
+ }
+}
+#else
+static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
+{
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */
+
+extern int netif_set_real_num_tx_queues(struct net_device *dev,
+ unsigned int txq);
+
/* mask irq_set_affinity_hint as RHEL6 backports this */
#define irq_set_affinity_hint(a,b) compat_irq_set_affinity_hint(a,b)
/*