diff options
author | Andrew J. Bennieston <andrew.bennieston@citrix.com> | 2014-06-04 05:30:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-04 17:48:17 -0400 |
commit | 50ee60611bf0c7328e5cae438ea5c26590f3f747 (patch) | |
tree | 25c371c319d39bee985cc50dd378bff191e7e2d4 /drivers/net/xen-netfront.c | |
parent | 2688fcb79498246d45a0fa5900e415bc97661b6f (diff) |
xen-netfront: Add support for multiple queues
Build on the refactoring of the previous patch to implement multiple
queues between xen-netfront and xen-netback.
Check XenStore for multi-queue support, and set up the rings and event
channels accordingly.
Write ring references and event channels to XenStore in a queue
hierarchy if appropriate, or flat when using only one queue.
Update the xennet_select_queue() function to choose the queue on which
to transmit a packet based on the skb hash result.
Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netfront.c')
-rw-r--r-- | drivers/net/xen-netfront.c | 170 |
1 files changed, 134 insertions, 36 deletions
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index af8cd95ec76b..55bf834d6a8c 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -57,6 +57,12 @@ | |||
57 | #include <xen/interface/memory.h> | 57 | #include <xen/interface/memory.h> |
58 | #include <xen/interface/grant_table.h> | 58 | #include <xen/interface/grant_table.h> |
59 | 59 | ||
60 | /* Module parameters */ | ||
61 | static unsigned int xennet_max_queues; | ||
62 | module_param_named(max_queues, xennet_max_queues, uint, 0644); | ||
63 | MODULE_PARM_DESC(max_queues, | ||
64 | "Maximum number of queues per virtual interface"); | ||
65 | |||
60 | static const struct ethtool_ops xennet_ethtool_ops; | 66 | static const struct ethtool_ops xennet_ethtool_ops; |
61 | 67 | ||
62 | struct netfront_cb { | 68 | struct netfront_cb { |
@@ -565,10 +571,22 @@ static int xennet_count_skb_frag_slots(struct sk_buff *skb) | |||
565 | return pages; | 571 | return pages; |
566 | } | 572 | } |
567 | 573 | ||
568 | static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb) | 574 | static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb, |
575 | void *accel_priv, select_queue_fallback_t fallback) | ||
569 | { | 576 | { |
570 | /* Stub for later implementation of queue selection */ | 577 | unsigned int num_queues = dev->real_num_tx_queues; |
571 | return 0; | 578 | u32 hash; |
579 | u16 queue_idx; | ||
580 | |||
581 | /* First, check if there is only one queue */ | ||
582 | if (num_queues == 1) { | ||
583 | queue_idx = 0; | ||
584 | } else { | ||
585 | hash = skb_get_hash(skb); | ||
586 | queue_idx = hash % num_queues; | ||
587 | } | ||
588 | |||
589 | return queue_idx; | ||
572 | } | 590 | } |
573 | 591 | ||
574 | static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) | 592 | static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) |
@@ -1316,7 +1334,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) | |||
1316 | struct net_device *netdev; | 1334 | struct net_device *netdev; |
1317 | struct netfront_info *np; | 1335 | struct netfront_info *np; |
1318 | 1336 | ||
1319 | netdev = alloc_etherdev_mq(sizeof(struct netfront_info), 1); | 1337 | netdev = alloc_etherdev_mq(sizeof(struct netfront_info), xennet_max_queues); |
1320 | if (!netdev) | 1338 | if (!netdev) |
1321 | return ERR_PTR(-ENOMEM); | 1339 | return ERR_PTR(-ENOMEM); |
1322 | 1340 | ||
@@ -1687,6 +1705,88 @@ static int xennet_init_queue(struct netfront_queue *queue) | |||
1687 | return err; | 1705 | return err; |
1688 | } | 1706 | } |
1689 | 1707 | ||
1708 | static int write_queue_xenstore_keys(struct netfront_queue *queue, | ||
1709 | struct xenbus_transaction *xbt, int write_hierarchical) | ||
1710 | { | ||
1711 | /* Write the queue-specific keys into XenStore in the traditional | ||
1712 | * way for a single queue, or in a queue subkeys for multiple | ||
1713 | * queues. | ||
1714 | */ | ||
1715 | struct xenbus_device *dev = queue->info->xbdev; | ||
1716 | int err; | ||
1717 | const char *message; | ||
1718 | char *path; | ||
1719 | size_t pathsize; | ||
1720 | |||
1721 | /* Choose the correct place to write the keys */ | ||
1722 | if (write_hierarchical) { | ||
1723 | pathsize = strlen(dev->nodename) + 10; | ||
1724 | path = kzalloc(pathsize, GFP_KERNEL); | ||
1725 | if (!path) { | ||
1726 | err = -ENOMEM; | ||
1727 | message = "out of memory while writing ring references"; | ||
1728 | goto error; | ||
1729 | } | ||
1730 | snprintf(path, pathsize, "%s/queue-%u", | ||
1731 | dev->nodename, queue->id); | ||
1732 | } else { | ||
1733 | path = (char *)dev->nodename; | ||
1734 | } | ||
1735 | |||
1736 | /* Write ring references */ | ||
1737 | err = xenbus_printf(*xbt, path, "tx-ring-ref", "%u", | ||
1738 | queue->tx_ring_ref); | ||
1739 | if (err) { | ||
1740 | message = "writing tx-ring-ref"; | ||
1741 | goto error; | ||
1742 | } | ||
1743 | |||
1744 | err = xenbus_printf(*xbt, path, "rx-ring-ref", "%u", | ||
1745 | queue->rx_ring_ref); | ||
1746 | if (err) { | ||
1747 | message = "writing rx-ring-ref"; | ||
1748 | goto error; | ||
1749 | } | ||
1750 | |||
1751 | /* Write event channels; taking into account both shared | ||
1752 | * and split event channel scenarios. | ||
1753 | */ | ||
1754 | if (queue->tx_evtchn == queue->rx_evtchn) { | ||
1755 | /* Shared event channel */ | ||
1756 | err = xenbus_printf(*xbt, path, | ||
1757 | "event-channel", "%u", queue->tx_evtchn); | ||
1758 | if (err) { | ||
1759 | message = "writing event-channel"; | ||
1760 | goto error; | ||
1761 | } | ||
1762 | } else { | ||
1763 | /* Split event channels */ | ||
1764 | err = xenbus_printf(*xbt, path, | ||
1765 | "event-channel-tx", "%u", queue->tx_evtchn); | ||
1766 | if (err) { | ||
1767 | message = "writing event-channel-tx"; | ||
1768 | goto error; | ||
1769 | } | ||
1770 | |||
1771 | err = xenbus_printf(*xbt, path, | ||
1772 | "event-channel-rx", "%u", queue->rx_evtchn); | ||
1773 | if (err) { | ||
1774 | message = "writing event-channel-rx"; | ||
1775 | goto error; | ||
1776 | } | ||
1777 | } | ||
1778 | |||
1779 | if (write_hierarchical) | ||
1780 | kfree(path); | ||
1781 | return 0; | ||
1782 | |||
1783 | error: | ||
1784 | if (write_hierarchical) | ||
1785 | kfree(path); | ||
1786 | xenbus_dev_fatal(dev, err, "%s", message); | ||
1787 | return err; | ||
1788 | } | ||
1789 | |||
1690 | /* Common code used when first setting up, and when resuming. */ | 1790 | /* Common code used when first setting up, and when resuming. */ |
1691 | static int talk_to_netback(struct xenbus_device *dev, | 1791 | static int talk_to_netback(struct xenbus_device *dev, |
1692 | struct netfront_info *info) | 1792 | struct netfront_info *info) |
@@ -1696,11 +1796,19 @@ static int talk_to_netback(struct xenbus_device *dev, | |||
1696 | int err; | 1796 | int err; |
1697 | unsigned int feature_split_evtchn; | 1797 | unsigned int feature_split_evtchn; |
1698 | unsigned int i = 0; | 1798 | unsigned int i = 0; |
1799 | unsigned int max_queues = 0; | ||
1699 | struct netfront_queue *queue = NULL; | 1800 | struct netfront_queue *queue = NULL; |
1700 | unsigned int num_queues = 1; | 1801 | unsigned int num_queues = 1; |
1701 | 1802 | ||
1702 | info->netdev->irq = 0; | 1803 | info->netdev->irq = 0; |
1703 | 1804 | ||
1805 | /* Check if backend supports multiple queues */ | ||
1806 | err = xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
1807 | "multi-queue-max-queues", "%u", &max_queues); | ||
1808 | if (err < 0) | ||
1809 | max_queues = 1; | ||
1810 | num_queues = min(max_queues, xennet_max_queues); | ||
1811 | |||
1704 | /* Check feature-split-event-channels */ | 1812 | /* Check feature-split-event-channels */ |
1705 | err = xenbus_scanf(XBT_NIL, info->xbdev->otherend, | 1813 | err = xenbus_scanf(XBT_NIL, info->xbdev->otherend, |
1706 | "feature-split-event-channels", "%u", | 1814 | "feature-split-event-channels", "%u", |
@@ -1765,49 +1873,35 @@ static int talk_to_netback(struct xenbus_device *dev, | |||
1765 | } | 1873 | } |
1766 | 1874 | ||
1767 | again: | 1875 | again: |
1768 | queue = &info->queues[0]; /* Use first queue only */ | ||
1769 | |||
1770 | err = xenbus_transaction_start(&xbt); | 1876 | err = xenbus_transaction_start(&xbt); |
1771 | if (err) { | 1877 | if (err) { |
1772 | xenbus_dev_fatal(dev, err, "starting transaction"); | 1878 | xenbus_dev_fatal(dev, err, "starting transaction"); |
1773 | goto destroy_ring; | 1879 | goto destroy_ring; |
1774 | } | 1880 | } |
1775 | 1881 | ||
1776 | err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u", | 1882 | if (num_queues == 1) { |
1777 | queue->tx_ring_ref); | 1883 | err = write_queue_xenstore_keys(&info->queues[0], &xbt, 0); /* flat */ |
1778 | if (err) { | 1884 | if (err) |
1779 | message = "writing tx ring-ref"; | 1885 | goto abort_transaction_no_dev_fatal; |
1780 | goto abort_transaction; | ||
1781 | } | ||
1782 | err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u", | ||
1783 | queue->rx_ring_ref); | ||
1784 | if (err) { | ||
1785 | message = "writing rx ring-ref"; | ||
1786 | goto abort_transaction; | ||
1787 | } | ||
1788 | |||
1789 | if (queue->tx_evtchn == queue->rx_evtchn) { | ||
1790 | err = xenbus_printf(xbt, dev->nodename, | ||
1791 | "event-channel", "%u", queue->tx_evtchn); | ||
1792 | if (err) { | ||
1793 | message = "writing event-channel"; | ||
1794 | goto abort_transaction; | ||
1795 | } | ||
1796 | } else { | 1886 | } else { |
1797 | err = xenbus_printf(xbt, dev->nodename, | 1887 | /* Write the number of queues */ |
1798 | "event-channel-tx", "%u", queue->tx_evtchn); | 1888 | err = xenbus_printf(xbt, dev->nodename, "multi-queue-num-queues", |
1889 | "%u", num_queues); | ||
1799 | if (err) { | 1890 | if (err) { |
1800 | message = "writing event-channel-tx"; | 1891 | message = "writing multi-queue-num-queues"; |
1801 | goto abort_transaction; | 1892 | goto abort_transaction_no_dev_fatal; |
1802 | } | 1893 | } |
1803 | err = xenbus_printf(xbt, dev->nodename, | 1894 | |
1804 | "event-channel-rx", "%u", queue->rx_evtchn); | 1895 | /* Write the keys for each queue */ |
1805 | if (err) { | 1896 | for (i = 0; i < num_queues; ++i) { |
1806 | message = "writing event-channel-rx"; | 1897 | queue = &info->queues[i]; |
1807 | goto abort_transaction; | 1898 | err = write_queue_xenstore_keys(queue, &xbt, 1); /* hierarchical */ |
1899 | if (err) | ||
1900 | goto abort_transaction_no_dev_fatal; | ||
1808 | } | 1901 | } |
1809 | } | 1902 | } |
1810 | 1903 | ||
1904 | /* The remaining keys are not queue-specific */ | ||
1811 | err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", | 1905 | err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", |
1812 | 1); | 1906 | 1); |
1813 | if (err) { | 1907 | if (err) { |
@@ -1857,8 +1951,9 @@ again: | |||
1857 | return 0; | 1951 | return 0; |
1858 | 1952 | ||
1859 | abort_transaction: | 1953 | abort_transaction: |
1860 | xenbus_transaction_end(xbt, 1); | ||
1861 | xenbus_dev_fatal(dev, err, "%s", message); | 1954 | xenbus_dev_fatal(dev, err, "%s", message); |
1955 | abort_transaction_no_dev_fatal: | ||
1956 | xenbus_transaction_end(xbt, 1); | ||
1862 | destroy_ring: | 1957 | destroy_ring: |
1863 | xennet_disconnect_backend(info); | 1958 | xennet_disconnect_backend(info); |
1864 | kfree(info->queues); | 1959 | kfree(info->queues); |
@@ -2264,6 +2359,9 @@ static int __init netif_init(void) | |||
2264 | 2359 | ||
2265 | pr_info("Initialising Xen virtual ethernet driver\n"); | 2360 | pr_info("Initialising Xen virtual ethernet driver\n"); |
2266 | 2361 | ||
2362 | /* Allow as many queues as there are CPUs, by default */ | ||
2363 | xennet_max_queues = num_online_cpus(); | ||
2364 | |||
2267 | return xenbus_register_frontend(&netfront_driver); | 2365 | return xenbus_register_frontend(&netfront_driver); |
2268 | } | 2366 | } |
2269 | module_init(netif_init); | 2367 | module_init(netif_init); |