aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-09-27 04:24:33 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-28 01:09:49 -0400
commit62fe0b40abb3484413800edaef9b087a20059acf (patch)
tree1fbd745de235b3a1d97931412fa9ff3e7228fd88
parentf91ff5b9ff529be8aac2039af63b2c8ea6cd6ebe (diff)
net: Allow changing number of RX queues after device allocation
For RPS, we create a kobject for each RX queue based on the number of queues passed to alloc_netdev_mq(). However, drivers generally do not determine the numbers of hardware queues to use until much later, so this usually represents the maximum number the driver may use and not the actual number in use. For TX queues, drivers can update the actual number using netif_set_real_num_tx_queues(). Add a corresponding function for RX queues, netif_set_real_num_rx_queues(). Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h16
-rw-r--r--net/core/dev.c45
-rw-r--r--net/core/net-sysfs.c32
-rw-r--r--net/core/net-sysfs.h4
4 files changed, 78 insertions, 19 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 83de0eb7a071..b15732e22eee 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -976,8 +976,11 @@ struct net_device {
976 976
977 struct netdev_rx_queue *_rx; 977 struct netdev_rx_queue *_rx;
978 978
979 /* Number of RX queues allocated at alloc_netdev_mq() time */ 979 /* Number of RX queues allocated at register_netdev() time */
980 unsigned int num_rx_queues; 980 unsigned int num_rx_queues;
981
982 /* Number of RX queues currently active in device */
983 unsigned int real_num_rx_queues;
981#endif 984#endif
982 985
983 rx_handler_func_t *rx_handler; 986 rx_handler_func_t *rx_handler;
@@ -1685,6 +1688,17 @@ static inline int netif_is_multiqueue(const struct net_device *dev)
1685extern void netif_set_real_num_tx_queues(struct net_device *dev, 1688extern void netif_set_real_num_tx_queues(struct net_device *dev,
1686 unsigned int txq); 1689 unsigned int txq);
1687 1690
1691#ifdef CONFIG_RPS
1692extern int netif_set_real_num_rx_queues(struct net_device *dev,
1693 unsigned int rxq);
1694#else
1695static inline int netif_set_real_num_rx_queues(struct net_device *dev,
1696 unsigned int rxq)
1697{
1698 return 0;
1699}
1700#endif
1701
1688/* Use this variant when it is known for sure that it 1702/* Use this variant when it is known for sure that it
1689 * is executing from hardware interrupt context or with hardware interrupts 1703 * is executing from hardware interrupt context or with hardware interrupts
1690 * disabled. 1704 * disabled.
diff --git a/net/core/dev.c b/net/core/dev.c
index 42b200fdf12e..48ad47f402ad 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1567,6 +1567,41 @@ void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
1567} 1567}
1568EXPORT_SYMBOL(netif_set_real_num_tx_queues); 1568EXPORT_SYMBOL(netif_set_real_num_tx_queues);
1569 1569
1570#ifdef CONFIG_RPS
1571/**
1572 * netif_set_real_num_rx_queues - set actual number of RX queues used
1573 * @dev: Network device
1574 * @rxq: Actual number of RX queues
1575 *
1576 * This must be called either with the rtnl_lock held or before
1577 * registration of the net device. Returns 0 on success, or a
1578 * negative error code. If called before registration, it also
1579 * sets the maximum number of queues, and always succeeds.
1580 */
1581int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq)
1582{
1583 int rc;
1584
1585 if (dev->reg_state == NETREG_REGISTERED) {
1586 ASSERT_RTNL();
1587
1588 if (rxq > dev->num_rx_queues)
1589 return -EINVAL;
1590
1591 rc = net_rx_queue_update_kobjects(dev, dev->real_num_rx_queues,
1592 rxq);
1593 if (rc)
1594 return rc;
1595 } else {
1596 dev->num_rx_queues = rxq;
1597 }
1598
1599 dev->real_num_rx_queues = rxq;
1600 return 0;
1601}
1602EXPORT_SYMBOL(netif_set_real_num_rx_queues);
1603#endif
1604
1570static inline void __netif_reschedule(struct Qdisc *q) 1605static inline void __netif_reschedule(struct Qdisc *q)
1571{ 1606{
1572 struct softnet_data *sd; 1607 struct softnet_data *sd;
@@ -2352,10 +2387,11 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
2352 2387
2353 if (skb_rx_queue_recorded(skb)) { 2388 if (skb_rx_queue_recorded(skb)) {
2354 u16 index = skb_get_rx_queue(skb); 2389 u16 index = skb_get_rx_queue(skb);
2355 if (unlikely(index >= dev->num_rx_queues)) { 2390 if (unlikely(index >= dev->real_num_rx_queues)) {
2356 WARN_ONCE(dev->num_rx_queues > 1, "%s received packet " 2391 WARN_ONCE(dev->real_num_rx_queues > 1,
2357 "on queue %u, but number of RX queues is %u\n", 2392 "%s received packet on queue %u, but number "
2358 dev->name, index, dev->num_rx_queues); 2393 "of RX queues is %u\n",
2394 dev->name, index, dev->real_num_rx_queues);
2359 goto done; 2395 goto done;
2360 } 2396 }
2361 rxqueue = dev->_rx + index; 2397 rxqueue = dev->_rx + index;
@@ -5472,6 +5508,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
5472 5508
5473#ifdef CONFIG_RPS 5509#ifdef CONFIG_RPS
5474 dev->num_rx_queues = queue_count; 5510 dev->num_rx_queues = queue_count;
5511 dev->real_num_rx_queues = queue_count;
5475#endif 5512#endif
5476 5513
5477 dev->gso_max_size = GSO_MAX_SIZE; 5514 dev->gso_max_size = GSO_MAX_SIZE;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 76485a3f910b..fa81fd0a488f 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -742,34 +742,38 @@ static int rx_queue_add_kobject(struct net_device *net, int index)
742 return error; 742 return error;
743} 743}
744 744
745static int rx_queue_register_kobjects(struct net_device *net) 745int
746net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
746{ 747{
747 int i; 748 int i;
748 int error = 0; 749 int error = 0;
749 750
750 net->queues_kset = kset_create_and_add("queues", 751 for (i = old_num; i < new_num; i++) {
751 NULL, &net->dev.kobj);
752 if (!net->queues_kset)
753 return -ENOMEM;
754 for (i = 0; i < net->num_rx_queues; i++) {
755 error = rx_queue_add_kobject(net, i); 752 error = rx_queue_add_kobject(net, i);
756 if (error) 753 if (error) {
754 new_num = old_num;
757 break; 755 break;
756 }
758 } 757 }
759 758
760 if (error) 759 while (--i >= new_num)
761 while (--i >= 0) 760 kobject_put(&net->_rx[i].kobj);
762 kobject_put(&net->_rx[i].kobj);
763 761
764 return error; 762 return error;
765} 763}
766 764
767static void rx_queue_remove_kobjects(struct net_device *net) 765static int rx_queue_register_kobjects(struct net_device *net)
768{ 766{
769 int i; 767 net->queues_kset = kset_create_and_add("queues",
768 NULL, &net->dev.kobj);
769 if (!net->queues_kset)
770 return -ENOMEM;
771 return net_rx_queue_update_kobjects(net, 0, net->real_num_rx_queues);
772}
770 773
771 for (i = 0; i < net->num_rx_queues; i++) 774static void rx_queue_remove_kobjects(struct net_device *net)
772 kobject_put(&net->_rx[i].kobj); 775{
776 net_rx_queue_update_kobjects(net, net->real_num_rx_queues, 0);
773 kset_unregister(net->queues_kset); 777 kset_unregister(net->queues_kset);
774} 778}
775#endif /* CONFIG_RPS */ 779#endif /* CONFIG_RPS */
diff --git a/net/core/net-sysfs.h b/net/core/net-sysfs.h
index 805555e8b187..778e1571548d 100644
--- a/net/core/net-sysfs.h
+++ b/net/core/net-sysfs.h
@@ -4,4 +4,8 @@
4int netdev_kobject_init(void); 4int netdev_kobject_init(void);
5int netdev_register_kobject(struct net_device *); 5int netdev_register_kobject(struct net_device *);
6void netdev_unregister_kobject(struct net_device *); 6void netdev_unregister_kobject(struct net_device *);
7#ifdef CONFIG_RPS
8int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num);
9#endif
10
7#endif 11#endif