Skip to content

Commit

Permalink
netdev: Allocate multiple queues for TX.
Browse files Browse the repository at this point in the history
alloc_netdev_mq() now allocates an array of netdev_queue
structures for TX, based upon the queue_count argument.

Furthermore, all accesses to the TX queues are now vectored
through the netdev_get_tx_queue() and netdev_for_each_tx_queue()
interfaces.  This makes it easy to grep the tree for all
things that want to get to a TX queue of a net device.

Problem spots which are not really multiqueue aware yet, and
only work with one queue, can easily be spotted by grepping
for all netdev_get_tx_queue() calls that pass in a zero index.

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jul 18, 2008
1 parent 070825b commit e8a0464
Show file tree
Hide file tree
Showing 18 changed files with 320 additions and 137 deletions.
6 changes: 4 additions & 2 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5042,15 +5042,17 @@ static int bond_check_params(struct bond_params *params)

static struct lock_class_key bonding_netdev_xmit_lock_key;

static void bond_set_lockdep_class_one(struct netdev_queue *txq)
static void bond_set_lockdep_class_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
lockdep_set_class(&txq->_xmit_lock,
&bonding_netdev_xmit_lock_key);
}

static void bond_set_lockdep_class(struct net_device *dev)
{
bond_set_lockdep_class_one(&dev->tx_queue);
netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL);
}

/* Create a new bond based on the specified name and bonding parameters.
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/hamradio/bpqether.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,16 @@ static LIST_HEAD(bpq_devices);
*/
static struct lock_class_key bpq_netdev_xmit_lock_key;

static void bpq_set_lockdep_class_one(struct netdev_queue *txq)
static void bpq_set_lockdep_class_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
lockdep_set_class(&txq->_xmit_lock, &bpq_netdev_xmit_lock_key);
}

static void bpq_set_lockdep_class(struct net_device *dev)
{
bpq_set_lockdep_class_one(&dev->tx_queue);
netdev_for_each_tx_queue(dev, bpq_set_lockdep_class_one, NULL);
}

/* ------------------------------------------------------------------------ */
Expand Down
12 changes: 9 additions & 3 deletions drivers/net/ifb.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,20 @@ module_param(numifbs, int, 0);
MODULE_PARM_DESC(numifbs, "Number of ifb devices");

/*
* dev_ifb->tx_queue.lock is usually taken after dev->rx_queue.lock,
* dev_ifb's TX queue lock is usually taken after dev->rx_queue.lock,
* reversely to e.g. qdisc_lock_tree(). It should be safe until
* ifb doesn't take dev->tx_queue.lock with dev_ifb->rx_queue.lock.
* ifb doesn't take dev's TX queue lock with dev_ifb->rx_queue.lock.
* But lockdep should know that ifb has different locks from dev.
*/
static struct lock_class_key ifb_tx_queue_lock_key;
static struct lock_class_key ifb_rx_queue_lock_key;

static void set_tx_lockdep_key(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
lockdep_set_class(&txq->lock, &ifb_tx_queue_lock_key);
}

static int __init ifb_init_one(int index)
{
Expand All @@ -258,7 +264,7 @@ static int __init ifb_init_one(int index)
if (err < 0)
goto err;

lockdep_set_class(&dev_ifb->tx_queue.lock, &ifb_tx_queue_lock_key);
netdev_for_each_tx_queue(dev_ifb, set_tx_lockdep_key, NULL);
lockdep_set_class(&dev_ifb->rx_queue.lock, &ifb_rx_queue_lock_key);

return 0;
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/macvlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,17 @@ static struct lock_class_key macvlan_netdev_xmit_lock_key;
#define MACVLAN_STATE_MASK \
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))

static void macvlan_set_lockdep_class_one(struct netdev_queue *txq)
static void macvlan_set_lockdep_class_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
lockdep_set_class(&txq->_xmit_lock,
&macvlan_netdev_xmit_lock_key);
}

static void macvlan_set_lockdep_class(struct net_device *dev)
{
macvlan_set_lockdep_class_one(&dev->tx_queue);
netdev_for_each_tx_queue(dev, macvlan_set_lockdep_class_one, NULL);
}

static int macvlan_init(struct net_device *dev)
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/wireless/hostap/hostap_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -3102,15 +3102,17 @@ static void prism2_clear_set_tim_queue(local_info_t *local)
*/
static struct lock_class_key hostap_netdev_xmit_lock_key;

static void prism2_set_lockdep_class_one(struct netdev_queue *txq)
static void prism2_set_lockdep_class_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
lockdep_set_class(&txq->_xmit_lock,
&hostap_netdev_xmit_lock_key);
}

static void prism2_set_lockdep_class(struct net_device *dev)
{
prism2_set_lockdep_class_one(&dev->tx_queue);
netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL);
}

static struct net_device *
Expand Down
69 changes: 46 additions & 23 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ struct netdev_queue {
struct Qdisc *qdisc_sleeping;
struct list_head qdisc_list;
struct netdev_queue *next_sched;
};
} ____cacheline_aligned_in_smp;

/*
* The DEVICE structure.
Expand Down Expand Up @@ -641,7 +641,9 @@ struct net_device
unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */

struct netdev_queue rx_queue;
struct netdev_queue tx_queue ____cacheline_aligned_in_smp;

struct netdev_queue *_tx ____cacheline_aligned_in_smp;
unsigned int num_tx_queues;
unsigned long tx_queue_len; /* Max frames per queue allowed */

/*
Expand Down Expand Up @@ -764,6 +766,25 @@ struct net_device
#define NETDEV_ALIGN 32
#define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1)

static inline
struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
unsigned int index)
{
return &dev->_tx[index];
}

static inline void netdev_for_each_tx_queue(struct net_device *dev,
void (*f)(struct net_device *,
struct netdev_queue *,
void *),
void *arg)
{
unsigned int i;

for (i = 0; i < dev->num_tx_queues; i++)
f(dev, &dev->_tx[i], arg);
}

/*
* Net namespace inlines
*/
Expand Down Expand Up @@ -977,7 +998,7 @@ static inline void netif_schedule_queue(struct netdev_queue *txq)

static inline void netif_schedule(struct net_device *dev)
{
netif_schedule_queue(&dev->tx_queue);
netif_schedule_queue(netdev_get_tx_queue(dev, 0));
}

/**
Expand All @@ -993,7 +1014,7 @@ static inline void netif_tx_start_queue(struct netdev_queue *dev_queue)

static inline void netif_start_queue(struct net_device *dev)
{
netif_tx_start_queue(&dev->tx_queue);
netif_tx_start_queue(netdev_get_tx_queue(dev, 0));
}

/**
Expand All @@ -1017,7 +1038,7 @@ static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue)

static inline void netif_wake_queue(struct net_device *dev)
{
netif_tx_wake_queue(&dev->tx_queue);
netif_tx_wake_queue(netdev_get_tx_queue(dev, 0));
}

/**
Expand All @@ -1034,7 +1055,7 @@ static inline void netif_tx_stop_queue(struct netdev_queue *dev_queue)

static inline void netif_stop_queue(struct net_device *dev)
{
netif_tx_stop_queue(&dev->tx_queue);
netif_tx_stop_queue(netdev_get_tx_queue(dev, 0));
}

/**
Expand All @@ -1050,7 +1071,7 @@ static inline int netif_tx_queue_stopped(const struct netdev_queue *dev_queue)

static inline int netif_queue_stopped(const struct net_device *dev)
{
return netif_tx_queue_stopped(&dev->tx_queue);
return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0));
}

/**
Expand Down Expand Up @@ -1134,7 +1155,7 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
#endif
if (test_and_clear_bit(__QUEUE_STATE_XOFF,
&dev->egress_subqueue[queue_index].state))
__netif_schedule(&dev->tx_queue);
__netif_schedule(netdev_get_tx_queue(dev, 0));
}

/**
Expand Down Expand Up @@ -1430,18 +1451,19 @@ static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)

static inline void netif_tx_lock(struct net_device *dev)
{
__netif_tx_lock(&dev->tx_queue, smp_processor_id());
}
int cpu = smp_processor_id();
unsigned int i;

static inline void __netif_tx_lock_bh(struct netdev_queue *txq)
{
spin_lock_bh(&txq->_xmit_lock);
txq->xmit_lock_owner = smp_processor_id();
for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
__netif_tx_lock(txq, cpu);
}
}

static inline void netif_tx_lock_bh(struct net_device *dev)
{
__netif_tx_lock_bh(&dev->tx_queue);
local_bh_disable();
netif_tx_lock(dev);
}

static inline int __netif_tx_trylock(struct netdev_queue *txq)
Expand All @@ -1454,7 +1476,7 @@ static inline int __netif_tx_trylock(struct netdev_queue *txq)

static inline int netif_tx_trylock(struct net_device *dev)
{
return __netif_tx_trylock(&dev->tx_queue);
return __netif_tx_trylock(netdev_get_tx_queue(dev, 0));
}

static inline void __netif_tx_unlock(struct netdev_queue *txq)
Expand All @@ -1465,18 +1487,19 @@ static inline void __netif_tx_unlock(struct netdev_queue *txq)

static inline void netif_tx_unlock(struct net_device *dev)
{
__netif_tx_unlock(&dev->tx_queue);
}
unsigned int i;

for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
__netif_tx_unlock(txq);
}

static inline void __netif_tx_unlock_bh(struct netdev_queue *txq)
{
txq->xmit_lock_owner = -1;
spin_unlock_bh(&txq->_xmit_lock);
}

static inline void netif_tx_unlock_bh(struct net_device *dev)
{
__netif_tx_unlock_bh(&dev->tx_queue);
netif_tx_unlock(dev);
local_bh_enable();
}

#define HARD_TX_LOCK(dev, txq, cpu) { \
Expand Down
37 changes: 26 additions & 11 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,32 +230,47 @@ extern void tcf_destroy_chain(struct tcf_proto **fl);
/* Reset all TX qdiscs of a device. */
static inline void qdisc_reset_all_tx(struct net_device *dev)
{
qdisc_reset(dev->tx_queue.qdisc);
unsigned int i;
for (i = 0; i < dev->num_tx_queues; i++)
qdisc_reset(netdev_get_tx_queue(dev, i)->qdisc);
}

/* Are all TX queues of the device empty? */
static inline bool qdisc_all_tx_empty(const struct net_device *dev)
{
const struct netdev_queue *txq = &dev->tx_queue;
const struct Qdisc *q = txq->qdisc;
unsigned int i;
for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
const struct Qdisc *q = txq->qdisc;

return (q->q.qlen == 0);
if (q->q.qlen)
return false;
}
return true;
}

/* Are any of the TX qdiscs changing? */
static inline bool qdisc_tx_changing(struct net_device *dev)
{
struct netdev_queue *txq = &dev->tx_queue;

return (txq->qdisc != txq->qdisc_sleeping);
unsigned int i;
for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
if (txq->qdisc != txq->qdisc_sleeping)
return true;
}
return false;
}

/* Is the device using the noop qdisc? */
/* Is the device using the noop qdisc on all queues? */
static inline bool qdisc_tx_is_noop(const struct net_device *dev)
{
const struct netdev_queue *txq = &dev->tx_queue;

return (txq->qdisc == &noop_qdisc);
unsigned int i;
for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
if (txq->qdisc != &noop_qdisc)
return false;
}
return true;
}

static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
Expand Down
10 changes: 6 additions & 4 deletions net/8021q/vlan_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,16 +570,18 @@ static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
*/
static struct lock_class_key vlan_netdev_xmit_lock_key;

static void vlan_dev_set_lockdep_one(struct netdev_queue *txq,
int subclass)
static void vlan_dev_set_lockdep_one(struct net_device *dev,
struct netdev_queue *txq,
void *_subclass)
{
lockdep_set_class_and_subclass(&txq->_xmit_lock,
&vlan_netdev_xmit_lock_key, subclass);
&vlan_netdev_xmit_lock_key,
*(int *)_subclass);
}

static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass)
{
vlan_dev_set_lockdep_one(&dev->tx_queue, subclass);
netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, &subclass);
}

static const struct header_ops vlan_header_ops = {
Expand Down
Loading

0 comments on commit e8a0464

Please sign in to comment.