aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/virtio_net.c
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2012-04-11 16:43:52 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-15 03:23:31 -0400
commit586d17c5a01bf1ae4e215adc6c48457eee5482bc (patch)
tree20738485061d7965712bc711035883501d02bcc5 /drivers/net/virtio_net.c
parent8831a3f2c9ee7d952e6d7a018d11c0c9c5b56749 (diff)
virtio-net: send gratuitous packets when needed
As hypervior does not have the knowledge of guest network configuration, it's better to ask guest to send gratuitous packets when needed. This patch implements VIRTIO_NET_F_GUEST_ANNOUNCE feature: hypervisor would notice the guest when it thinks it's time for guest to announce the link presnece. Guest tests VIRTIO_NET_S_ANNOUNCE bit during config change interrupt and woule send gratuitous packets through netif_notify_peers() and ack the notification through ctrl vq. We need to make sure the atomicy of read and ack in guest otherwise we may ack more times than being notified. This is done through handling the whole config change interrupt in an non-reentrant workqueue. Signed-off-by: Jason Wang <jasowang@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r--drivers/net/virtio_net.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index af8acc85f4bb..fa58c7869954 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -66,12 +66,21 @@ struct virtnet_info {
66 /* Host will merge rx buffers for big packets (shake it! shake it!) */ 66 /* Host will merge rx buffers for big packets (shake it! shake it!) */
67 bool mergeable_rx_bufs; 67 bool mergeable_rx_bufs;
68 68
69 /* enable config space updates */
70 bool config_enable;
71
69 /* Active statistics */ 72 /* Active statistics */
70 struct virtnet_stats __percpu *stats; 73 struct virtnet_stats __percpu *stats;
71 74
72 /* Work struct for refilling if we run low on memory. */ 75 /* Work struct for refilling if we run low on memory. */
73 struct delayed_work refill; 76 struct delayed_work refill;
74 77
78 /* Work struct for config space updates */
79 struct work_struct config_work;
80
81 /* Lock for config space updates */
82 struct mutex config_lock;
83
75 /* Chain pages by the private ptr. */ 84 /* Chain pages by the private ptr. */
76 struct page *pages; 85 struct page *pages;
77 86
@@ -780,6 +789,16 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
780 return status == VIRTIO_NET_OK; 789 return status == VIRTIO_NET_OK;
781} 790}
782 791
792static void virtnet_ack_link_announce(struct virtnet_info *vi)
793{
794 rtnl_lock();
795 if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_ANNOUNCE,
796 VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL,
797 0, 0))
798 dev_warn(&vi->dev->dev, "Failed to ack link announce.\n");
799 rtnl_unlock();
800}
801
783static int virtnet_close(struct net_device *dev) 802static int virtnet_close(struct net_device *dev)
784{ 803{
785 struct virtnet_info *vi = netdev_priv(dev); 804 struct virtnet_info *vi = netdev_priv(dev);
@@ -951,20 +970,31 @@ static const struct net_device_ops virtnet_netdev = {
951#endif 970#endif
952}; 971};
953 972
954static void virtnet_update_status(struct virtnet_info *vi) 973static void virtnet_config_changed_work(struct work_struct *work)
955{ 974{
975 struct virtnet_info *vi =
976 container_of(work, struct virtnet_info, config_work);
956 u16 v; 977 u16 v;
957 978
979 mutex_lock(&vi->config_lock);
980 if (!vi->config_enable)
981 goto done;
982
958 if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS, 983 if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS,
959 offsetof(struct virtio_net_config, status), 984 offsetof(struct virtio_net_config, status),
960 &v) < 0) 985 &v) < 0)
961 return; 986 goto done;
987
988 if (v & VIRTIO_NET_S_ANNOUNCE) {
989 netif_notify_peers(vi->dev);
990 virtnet_ack_link_announce(vi);
991 }
962 992
963 /* Ignore unknown (future) status bits */ 993 /* Ignore unknown (future) status bits */
964 v &= VIRTIO_NET_S_LINK_UP; 994 v &= VIRTIO_NET_S_LINK_UP;
965 995
966 if (vi->status == v) 996 if (vi->status == v)
967 return; 997 goto done;
968 998
969 vi->status = v; 999 vi->status = v;
970 1000
@@ -975,13 +1005,15 @@ static void virtnet_update_status(struct virtnet_info *vi)
975 netif_carrier_off(vi->dev); 1005 netif_carrier_off(vi->dev);
976 netif_stop_queue(vi->dev); 1006 netif_stop_queue(vi->dev);
977 } 1007 }
1008done:
1009 mutex_unlock(&vi->config_lock);
978} 1010}
979 1011
980static void virtnet_config_changed(struct virtio_device *vdev) 1012static void virtnet_config_changed(struct virtio_device *vdev)
981{ 1013{
982 struct virtnet_info *vi = vdev->priv; 1014 struct virtnet_info *vi = vdev->priv;
983 1015
984 virtnet_update_status(vi); 1016 queue_work(system_nrt_wq, &vi->config_work);
985} 1017}
986 1018
987static int init_vqs(struct virtnet_info *vi) 1019static int init_vqs(struct virtnet_info *vi)
@@ -1075,6 +1107,9 @@ static int virtnet_probe(struct virtio_device *vdev)
1075 goto free; 1107 goto free;
1076 1108
1077 INIT_DELAYED_WORK(&vi->refill, refill_work); 1109 INIT_DELAYED_WORK(&vi->refill, refill_work);
1110 mutex_init(&vi->config_lock);
1111 vi->config_enable = true;
1112 INIT_WORK(&vi->config_work, virtnet_config_changed_work);
1078 sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg)); 1113 sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
1079 sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg)); 1114 sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
1080 1115
@@ -1110,7 +1145,7 @@ static int virtnet_probe(struct virtio_device *vdev)
1110 otherwise get link status from config. */ 1145 otherwise get link status from config. */
1111 if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { 1146 if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
1112 netif_carrier_off(dev); 1147 netif_carrier_off(dev);
1113 virtnet_update_status(vi); 1148 queue_work(system_nrt_wq, &vi->config_work);
1114 } else { 1149 } else {
1115 vi->status = VIRTIO_NET_S_LINK_UP; 1150 vi->status = VIRTIO_NET_S_LINK_UP;
1116 netif_carrier_on(dev); 1151 netif_carrier_on(dev);
@@ -1169,10 +1204,17 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
1169{ 1204{
1170 struct virtnet_info *vi = vdev->priv; 1205 struct virtnet_info *vi = vdev->priv;
1171 1206
1207 /* Prevent config work handler from accessing the device. */
1208 mutex_lock(&vi->config_lock);
1209 vi->config_enable = false;
1210 mutex_unlock(&vi->config_lock);
1211
1172 unregister_netdev(vi->dev); 1212 unregister_netdev(vi->dev);
1173 1213
1174 remove_vq_common(vi); 1214 remove_vq_common(vi);
1175 1215
1216 flush_work(&vi->config_work);
1217
1176 free_percpu(vi->stats); 1218 free_percpu(vi->stats);
1177 free_netdev(vi->dev); 1219 free_netdev(vi->dev);
1178} 1220}
@@ -1182,6 +1224,11 @@ static int virtnet_freeze(struct virtio_device *vdev)
1182{ 1224{
1183 struct virtnet_info *vi = vdev->priv; 1225 struct virtnet_info *vi = vdev->priv;
1184 1226
1227 /* Prevent config work handler from accessing the device */
1228 mutex_lock(&vi->config_lock);
1229 vi->config_enable = false;
1230 mutex_unlock(&vi->config_lock);
1231
1185 virtqueue_disable_cb(vi->rvq); 1232 virtqueue_disable_cb(vi->rvq);
1186 virtqueue_disable_cb(vi->svq); 1233 virtqueue_disable_cb(vi->svq);
1187 if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) 1234 if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
@@ -1195,6 +1242,8 @@ static int virtnet_freeze(struct virtio_device *vdev)
1195 1242
1196 remove_vq_common(vi); 1243 remove_vq_common(vi);
1197 1244
1245 flush_work(&vi->config_work);
1246
1198 return 0; 1247 return 0;
1199} 1248}
1200 1249
@@ -1215,6 +1264,10 @@ static int virtnet_restore(struct virtio_device *vdev)
1215 if (!try_fill_recv(vi, GFP_KERNEL)) 1264 if (!try_fill_recv(vi, GFP_KERNEL))
1216 queue_delayed_work(system_nrt_wq, &vi->refill, 0); 1265 queue_delayed_work(system_nrt_wq, &vi->refill, 0);
1217 1266
1267 mutex_lock(&vi->config_lock);
1268 vi->config_enable = true;
1269 mutex_unlock(&vi->config_lock);
1270
1218 return 0; 1271 return 0;
1219} 1272}
1220#endif 1273#endif
@@ -1232,6 +1285,7 @@ static unsigned int features[] = {
1232 VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, 1285 VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
1233 VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, 1286 VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
1234 VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, 1287 VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
1288 VIRTIO_NET_F_GUEST_ANNOUNCE,
1235}; 1289};
1236 1290
1237static struct virtio_driver virtio_net_driver = { 1291static struct virtio_driver virtio_net_driver = {