aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/virtio_net.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r--drivers/net/virtio_net.c118
1 files changed, 98 insertions, 20 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index a6fcf15adc4f..35c00c5ea02a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -26,6 +26,7 @@
26#include <linux/scatterlist.h> 26#include <linux/scatterlist.h>
27#include <linux/if_vlan.h> 27#include <linux/if_vlan.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/cpu.h>
29 30
30static int napi_weight = 128; 31static int napi_weight = 128;
31module_param(napi_weight, int, 0444); 32module_param(napi_weight, int, 0444);
@@ -123,6 +124,12 @@ struct virtnet_info {
123 124
124 /* Does the affinity hint is set for virtqueues? */ 125 /* Does the affinity hint is set for virtqueues? */
125 bool affinity_hint_set; 126 bool affinity_hint_set;
127
128 /* Per-cpu variable to show the mapping from CPU to virtqueue */
129 int __percpu *vq_index;
130
131 /* CPU hot plug notifier */
132 struct notifier_block nb;
126}; 133};
127 134
128struct skb_vnet_hdr { 135struct skb_vnet_hdr {
@@ -1013,32 +1020,75 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
1013 return 0; 1020 return 0;
1014} 1021}
1015 1022
1016static void virtnet_set_affinity(struct virtnet_info *vi, bool set) 1023static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
1017{ 1024{
1018 int i; 1025 int i;
1026 int cpu;
1027
1028 if (vi->affinity_hint_set) {
1029 for (i = 0; i < vi->max_queue_pairs; i++) {
1030 virtqueue_set_affinity(vi->rq[i].vq, -1);
1031 virtqueue_set_affinity(vi->sq[i].vq, -1);
1032 }
1033
1034 vi->affinity_hint_set = false;
1035 }
1036
1037 i = 0;
1038 for_each_online_cpu(cpu) {
1039 if (cpu == hcpu) {
1040 *per_cpu_ptr(vi->vq_index, cpu) = -1;
1041 } else {
1042 *per_cpu_ptr(vi->vq_index, cpu) =
1043 ++i % vi->curr_queue_pairs;
1044 }
1045 }
1046}
1047
1048static void virtnet_set_affinity(struct virtnet_info *vi)
1049{
1050 int i;
1051 int cpu;
1019 1052
1020 /* In multiqueue mode, when the number of cpu is equal to the number of 1053 /* In multiqueue mode, when the number of cpu is equal to the number of
1021 * queue pairs, we let the queue pairs to be private to one cpu by 1054 * queue pairs, we let the queue pairs to be private to one cpu by
1022 * setting the affinity hint to eliminate the contention. 1055 * setting the affinity hint to eliminate the contention.
1023 */ 1056 */
1024 if ((vi->curr_queue_pairs == 1 || 1057 if (vi->curr_queue_pairs == 1 ||
1025 vi->max_queue_pairs != num_online_cpus()) && set) { 1058 vi->max_queue_pairs != num_online_cpus()) {
1026 if (vi->affinity_hint_set) 1059 virtnet_clean_affinity(vi, -1);
1027 set = false; 1060 return;
1028 else
1029 return;
1030 } 1061 }
1031 1062
1032 for (i = 0; i < vi->max_queue_pairs; i++) { 1063 i = 0;
1033 int cpu = set ? i : -1; 1064 for_each_online_cpu(cpu) {
1034 virtqueue_set_affinity(vi->rq[i].vq, cpu); 1065 virtqueue_set_affinity(vi->rq[i].vq, cpu);
1035 virtqueue_set_affinity(vi->sq[i].vq, cpu); 1066 virtqueue_set_affinity(vi->sq[i].vq, cpu);
1067 *per_cpu_ptr(vi->vq_index, cpu) = i;
1068 i++;
1036 } 1069 }
1037 1070
1038 if (set) 1071 vi->affinity_hint_set = true;
1039 vi->affinity_hint_set = true; 1072}
1040 else 1073
1041 vi->affinity_hint_set = false; 1074static int virtnet_cpu_callback(struct notifier_block *nfb,
1075 unsigned long action, void *hcpu)
1076{
1077 struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
1078
1079 switch(action & ~CPU_TASKS_FROZEN) {
1080 case CPU_ONLINE:
1081 case CPU_DOWN_FAILED:
1082 case CPU_DEAD:
1083 virtnet_set_affinity(vi);
1084 break;
1085 case CPU_DOWN_PREPARE:
1086 virtnet_clean_affinity(vi, (long)hcpu);
1087 break;
1088 default:
1089 break;
1090 }
1091 return NOTIFY_OK;
1042} 1092}
1043 1093
1044static void virtnet_get_ringparam(struct net_device *dev, 1094static void virtnet_get_ringparam(struct net_device *dev,
@@ -1082,13 +1132,15 @@ static int virtnet_set_channels(struct net_device *dev,
1082 if (queue_pairs > vi->max_queue_pairs) 1132 if (queue_pairs > vi->max_queue_pairs)
1083 return -EINVAL; 1133 return -EINVAL;
1084 1134
1135 get_online_cpus();
1085 err = virtnet_set_queues(vi, queue_pairs); 1136 err = virtnet_set_queues(vi, queue_pairs);
1086 if (!err) { 1137 if (!err) {
1087 netif_set_real_num_tx_queues(dev, queue_pairs); 1138 netif_set_real_num_tx_queues(dev, queue_pairs);
1088 netif_set_real_num_rx_queues(dev, queue_pairs); 1139 netif_set_real_num_rx_queues(dev, queue_pairs);
1089 1140
1090 virtnet_set_affinity(vi, true); 1141 virtnet_set_affinity(vi);
1091 } 1142 }
1143 put_online_cpus();
1092 1144
1093 return err; 1145 return err;
1094} 1146}
@@ -1127,12 +1179,19 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
1127 1179
1128/* To avoid contending a lock hold by a vcpu who would exit to host, select the 1180/* To avoid contending a lock hold by a vcpu who would exit to host, select the
1129 * txq based on the processor id. 1181 * txq based on the processor id.
1130 * TODO: handle cpu hotplug.
1131 */ 1182 */
1132static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb) 1183static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb)
1133{ 1184{
1134 int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 1185 int txq;
1135 smp_processor_id(); 1186 struct virtnet_info *vi = netdev_priv(dev);
1187
1188 if (skb_rx_queue_recorded(skb)) {
1189 txq = skb_get_rx_queue(skb);
1190 } else {
1191 txq = *__this_cpu_ptr(vi->vq_index);
1192 if (txq == -1)
1193 txq = 0;
1194 }
1136 1195
1137 while (unlikely(txq >= dev->real_num_tx_queues)) 1196 while (unlikely(txq >= dev->real_num_tx_queues))
1138 txq -= dev->real_num_tx_queues; 1197 txq -= dev->real_num_tx_queues;
@@ -1248,7 +1307,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
1248{ 1307{
1249 struct virtio_device *vdev = vi->vdev; 1308 struct virtio_device *vdev = vi->vdev;
1250 1309
1251 virtnet_set_affinity(vi, false); 1310 virtnet_clean_affinity(vi, -1);
1252 1311
1253 vdev->config->del_vqs(vdev); 1312 vdev->config->del_vqs(vdev);
1254 1313
@@ -1371,7 +1430,10 @@ static int init_vqs(struct virtnet_info *vi)
1371 if (ret) 1430 if (ret)
1372 goto err_free; 1431 goto err_free;
1373 1432
1374 virtnet_set_affinity(vi, true); 1433 get_online_cpus();
1434 virtnet_set_affinity(vi);
1435 put_online_cpus();
1436
1375 return 0; 1437 return 0;
1376 1438
1377err_free: 1439err_free:
@@ -1453,6 +1515,10 @@ static int virtnet_probe(struct virtio_device *vdev)
1453 if (vi->stats == NULL) 1515 if (vi->stats == NULL)
1454 goto free; 1516 goto free;
1455 1517
1518 vi->vq_index = alloc_percpu(int);
1519 if (vi->vq_index == NULL)
1520 goto free_stats;
1521
1456 mutex_init(&vi->config_lock); 1522 mutex_init(&vi->config_lock);
1457 vi->config_enable = true; 1523 vi->config_enable = true;
1458 INIT_WORK(&vi->config_work, virtnet_config_changed_work); 1524 INIT_WORK(&vi->config_work, virtnet_config_changed_work);
@@ -1476,7 +1542,7 @@ static int virtnet_probe(struct virtio_device *vdev)
1476 /* Allocate/initialize the rx/tx queues, and invoke find_vqs */ 1542 /* Allocate/initialize the rx/tx queues, and invoke find_vqs */
1477 err = init_vqs(vi); 1543 err = init_vqs(vi);
1478 if (err) 1544 if (err)
1479 goto free_stats; 1545 goto free_index;
1480 1546
1481 netif_set_real_num_tx_queues(dev, 1); 1547 netif_set_real_num_tx_queues(dev, 1);
1482 netif_set_real_num_rx_queues(dev, 1); 1548 netif_set_real_num_rx_queues(dev, 1);
@@ -1499,6 +1565,13 @@ static int virtnet_probe(struct virtio_device *vdev)
1499 } 1565 }
1500 } 1566 }
1501 1567
1568 vi->nb.notifier_call = &virtnet_cpu_callback;
1569 err = register_hotcpu_notifier(&vi->nb);
1570 if (err) {
1571 pr_debug("virtio_net: registering cpu notifier failed\n");
1572 goto free_recv_bufs;
1573 }
1574
1502 /* Assume link up if device can't report link status, 1575 /* Assume link up if device can't report link status,
1503 otherwise get link status from config. */ 1576 otherwise get link status from config. */
1504 if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { 1577 if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1520,6 +1593,8 @@ free_recv_bufs:
1520free_vqs: 1593free_vqs:
1521 cancel_delayed_work_sync(&vi->refill); 1594 cancel_delayed_work_sync(&vi->refill);
1522 virtnet_del_vqs(vi); 1595 virtnet_del_vqs(vi);
1596free_index:
1597 free_percpu(vi->vq_index);
1523free_stats: 1598free_stats:
1524 free_percpu(vi->stats); 1599 free_percpu(vi->stats);
1525free: 1600free:
@@ -1543,6 +1618,8 @@ static void virtnet_remove(struct virtio_device *vdev)
1543{ 1618{
1544 struct virtnet_info *vi = vdev->priv; 1619 struct virtnet_info *vi = vdev->priv;
1545 1620
1621 unregister_hotcpu_notifier(&vi->nb);
1622
1546 /* Prevent config work handler from accessing the device. */ 1623 /* Prevent config work handler from accessing the device. */
1547 mutex_lock(&vi->config_lock); 1624 mutex_lock(&vi->config_lock);
1548 vi->config_enable = false; 1625 vi->config_enable = false;
@@ -1554,6 +1631,7 @@ static void virtnet_remove(struct virtio_device *vdev)
1554 1631
1555 flush_work(&vi->config_work); 1632 flush_work(&vi->config_work);
1556 1633
1634 free_percpu(vi->vq_index);
1557 free_percpu(vi->stats); 1635 free_percpu(vi->stats);
1558 free_netdev(vi->dev); 1636 free_netdev(vi->dev);
1559} 1637}