diff options
Diffstat (limited to 'drivers/net/xen-netfront.c')
-rw-r--r-- | drivers/net/xen-netfront.c | 109 |
1 files changed, 75 insertions, 34 deletions
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 5a7872ac3566..2ccb4a02368b 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -1287,7 +1287,7 @@ static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id) | |||
1287 | 1287 | ||
1288 | if (likely(netif_carrier_ok(dev) && | 1288 | if (likely(netif_carrier_ok(dev) && |
1289 | RING_HAS_UNCONSUMED_RESPONSES(&queue->rx))) | 1289 | RING_HAS_UNCONSUMED_RESPONSES(&queue->rx))) |
1290 | napi_schedule(&queue->napi); | 1290 | napi_schedule(&queue->napi); |
1291 | 1291 | ||
1292 | return IRQ_HANDLED; | 1292 | return IRQ_HANDLED; |
1293 | } | 1293 | } |
@@ -1437,10 +1437,11 @@ static void xennet_end_access(int ref, void *page) | |||
1437 | static void xennet_disconnect_backend(struct netfront_info *info) | 1437 | static void xennet_disconnect_backend(struct netfront_info *info) |
1438 | { | 1438 | { |
1439 | unsigned int i = 0; | 1439 | unsigned int i = 0; |
1440 | struct netfront_queue *queue = NULL; | ||
1441 | unsigned int num_queues = info->netdev->real_num_tx_queues; | 1440 | unsigned int num_queues = info->netdev->real_num_tx_queues; |
1442 | 1441 | ||
1443 | for (i = 0; i < num_queues; ++i) { | 1442 | for (i = 0; i < num_queues; ++i) { |
1443 | struct netfront_queue *queue = &info->queues[i]; | ||
1444 | |||
1444 | /* Stop old i/f to prevent errors whilst we rebuild the state. */ | 1445 | /* Stop old i/f to prevent errors whilst we rebuild the state. */ |
1445 | spin_lock_bh(&queue->rx_lock); | 1446 | spin_lock_bh(&queue->rx_lock); |
1446 | spin_lock_irq(&queue->tx_lock); | 1447 | spin_lock_irq(&queue->tx_lock); |
@@ -1698,8 +1699,6 @@ static int xennet_init_queue(struct netfront_queue *queue) | |||
1698 | goto exit_free_tx; | 1699 | goto exit_free_tx; |
1699 | } | 1700 | } |
1700 | 1701 | ||
1701 | netif_napi_add(queue->info->netdev, &queue->napi, xennet_poll, 64); | ||
1702 | |||
1703 | return 0; | 1702 | return 0; |
1704 | 1703 | ||
1705 | exit_free_tx: | 1704 | exit_free_tx: |
@@ -1790,6 +1789,70 @@ error: | |||
1790 | return err; | 1789 | return err; |
1791 | } | 1790 | } |
1792 | 1791 | ||
1792 | static void xennet_destroy_queues(struct netfront_info *info) | ||
1793 | { | ||
1794 | unsigned int i; | ||
1795 | |||
1796 | rtnl_lock(); | ||
1797 | |||
1798 | for (i = 0; i < info->netdev->real_num_tx_queues; i++) { | ||
1799 | struct netfront_queue *queue = &info->queues[i]; | ||
1800 | |||
1801 | if (netif_running(info->netdev)) | ||
1802 | napi_disable(&queue->napi); | ||
1803 | netif_napi_del(&queue->napi); | ||
1804 | } | ||
1805 | |||
1806 | rtnl_unlock(); | ||
1807 | |||
1808 | kfree(info->queues); | ||
1809 | info->queues = NULL; | ||
1810 | } | ||
1811 | |||
1812 | static int xennet_create_queues(struct netfront_info *info, | ||
1813 | unsigned int num_queues) | ||
1814 | { | ||
1815 | unsigned int i; | ||
1816 | int ret; | ||
1817 | |||
1818 | info->queues = kcalloc(num_queues, sizeof(struct netfront_queue), | ||
1819 | GFP_KERNEL); | ||
1820 | if (!info->queues) | ||
1821 | return -ENOMEM; | ||
1822 | |||
1823 | rtnl_lock(); | ||
1824 | |||
1825 | for (i = 0; i < num_queues; i++) { | ||
1826 | struct netfront_queue *queue = &info->queues[i]; | ||
1827 | |||
1828 | queue->id = i; | ||
1829 | queue->info = info; | ||
1830 | |||
1831 | ret = xennet_init_queue(queue); | ||
1832 | if (ret < 0) { | ||
1833 | dev_warn(&info->netdev->dev, "only created %d queues\n", | ||
1834 | num_queues); | ||
1835 | num_queues = i; | ||
1836 | break; | ||
1837 | } | ||
1838 | |||
1839 | netif_napi_add(queue->info->netdev, &queue->napi, | ||
1840 | xennet_poll, 64); | ||
1841 | if (netif_running(info->netdev)) | ||
1842 | napi_enable(&queue->napi); | ||
1843 | } | ||
1844 | |||
1845 | netif_set_real_num_tx_queues(info->netdev, num_queues); | ||
1846 | |||
1847 | rtnl_unlock(); | ||
1848 | |||
1849 | if (num_queues == 0) { | ||
1850 | dev_err(&info->netdev->dev, "no queues\n"); | ||
1851 | return -EINVAL; | ||
1852 | } | ||
1853 | return 0; | ||
1854 | } | ||
1855 | |||
1793 | /* Common code used when first setting up, and when resuming. */ | 1856 | /* Common code used when first setting up, and when resuming. */ |
1794 | static int talk_to_netback(struct xenbus_device *dev, | 1857 | static int talk_to_netback(struct xenbus_device *dev, |
1795 | struct netfront_info *info) | 1858 | struct netfront_info *info) |
@@ -1826,42 +1889,20 @@ static int talk_to_netback(struct xenbus_device *dev, | |||
1826 | goto out; | 1889 | goto out; |
1827 | } | 1890 | } |
1828 | 1891 | ||
1829 | /* Allocate array of queues */ | 1892 | if (info->queues) |
1830 | info->queues = kcalloc(num_queues, sizeof(struct netfront_queue), GFP_KERNEL); | 1893 | xennet_destroy_queues(info); |
1831 | if (!info->queues) { | 1894 | |
1832 | err = -ENOMEM; | 1895 | err = xennet_create_queues(info, num_queues); |
1833 | goto out; | 1896 | if (err < 0) |
1834 | } | 1897 | goto destroy_ring; |
1835 | rtnl_lock(); | ||
1836 | netif_set_real_num_tx_queues(info->netdev, num_queues); | ||
1837 | rtnl_unlock(); | ||
1838 | 1898 | ||
1839 | /* Create shared ring, alloc event channel -- for each queue */ | 1899 | /* Create shared ring, alloc event channel -- for each queue */ |
1840 | for (i = 0; i < num_queues; ++i) { | 1900 | for (i = 0; i < num_queues; ++i) { |
1841 | queue = &info->queues[i]; | 1901 | queue = &info->queues[i]; |
1842 | queue->id = i; | ||
1843 | queue->info = info; | ||
1844 | err = xennet_init_queue(queue); | ||
1845 | if (err) { | ||
1846 | /* xennet_init_queue() cleans up after itself on failure, | ||
1847 | * but we still have to clean up any previously initialised | ||
1848 | * queues. If i > 0, set num_queues to i, then goto | ||
1849 | * destroy_ring, which calls xennet_disconnect_backend() | ||
1850 | * to tidy up. | ||
1851 | */ | ||
1852 | if (i > 0) { | ||
1853 | rtnl_lock(); | ||
1854 | netif_set_real_num_tx_queues(info->netdev, i); | ||
1855 | rtnl_unlock(); | ||
1856 | goto destroy_ring; | ||
1857 | } else { | ||
1858 | goto out; | ||
1859 | } | ||
1860 | } | ||
1861 | err = setup_netfront(dev, queue, feature_split_evtchn); | 1902 | err = setup_netfront(dev, queue, feature_split_evtchn); |
1862 | if (err) { | 1903 | if (err) { |
1863 | /* As for xennet_init_queue(), setup_netfront() will tidy | 1904 | /* setup_netfront() will tidy up the current |
1864 | * up the current queue on error, but we need to clean up | 1905 | * queue on error, but we need to clean up |
1865 | * those already allocated. | 1906 | * those already allocated. |
1866 | */ | 1907 | */ |
1867 | if (i > 0) { | 1908 | if (i > 0) { |