diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 125 |
1 files changed, 92 insertions, 33 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 76fe14efb2b5..4880aa8b4c28 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -370,7 +370,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) | |||
370 | 370 | ||
371 | skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len); | 371 | skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len); |
372 | 372 | ||
373 | err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp); | 373 | err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb, gfp); |
374 | if (err < 0) | 374 | if (err < 0) |
375 | dev_kfree_skb(skb); | 375 | dev_kfree_skb(skb); |
376 | 376 | ||
@@ -415,8 +415,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) | |||
415 | 415 | ||
416 | /* chain first in list head */ | 416 | /* chain first in list head */ |
417 | first->private = (unsigned long)list; | 417 | first->private = (unsigned long)list; |
418 | err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, | 418 | err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, |
419 | first, gfp); | 419 | first, gfp); |
420 | if (err < 0) | 420 | if (err < 0) |
421 | give_pages(vi, first); | 421 | give_pages(vi, first); |
422 | 422 | ||
@@ -434,7 +434,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) | |||
434 | 434 | ||
435 | sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE); | 435 | sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE); |
436 | 436 | ||
437 | err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp); | 437 | err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page, gfp); |
438 | if (err < 0) | 438 | if (err < 0) |
439 | give_pages(vi, page); | 439 | give_pages(vi, page); |
440 | 440 | ||
@@ -609,7 +609,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | |||
609 | 609 | ||
610 | hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1; | 610 | hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1; |
611 | return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg, | 611 | return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg, |
612 | 0, skb); | 612 | 0, skb, GFP_ATOMIC); |
613 | } | 613 | } |
614 | 614 | ||
615 | static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) | 615 | static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) |
@@ -767,7 +767,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, | |||
767 | sg_set_buf(&sg[i + 1], sg_virt(s), s->length); | 767 | sg_set_buf(&sg[i + 1], sg_virt(s), s->length); |
768 | sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); | 768 | sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); |
769 | 769 | ||
770 | BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi) < 0); | 770 | BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0); |
771 | 771 | ||
772 | virtqueue_kick(vi->cvq); | 772 | virtqueue_kick(vi->cvq); |
773 | 773 | ||
@@ -985,15 +985,38 @@ static void virtnet_config_changed(struct virtio_device *vdev) | |||
985 | virtnet_update_status(vi); | 985 | virtnet_update_status(vi); |
986 | } | 986 | } |
987 | 987 | ||
988 | static int init_vqs(struct virtnet_info *vi) | ||
989 | { | ||
990 | struct virtqueue *vqs[3]; | ||
991 | vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL}; | ||
992 | const char *names[] = { "input", "output", "control" }; | ||
993 | int nvqs, err; | ||
994 | |||
995 | /* We expect two virtqueues, receive then send, | ||
996 | * and optionally control. */ | ||
997 | nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2; | ||
998 | |||
999 | err = vi->vdev->config->find_vqs(vi->vdev, nvqs, vqs, callbacks, names); | ||
1000 | if (err) | ||
1001 | return err; | ||
1002 | |||
1003 | vi->rvq = vqs[0]; | ||
1004 | vi->svq = vqs[1]; | ||
1005 | |||
1006 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { | ||
1007 | vi->cvq = vqs[2]; | ||
1008 | |||
1009 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) | ||
1010 | vi->dev->features |= NETIF_F_HW_VLAN_FILTER; | ||
1011 | } | ||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
988 | static int virtnet_probe(struct virtio_device *vdev) | 1015 | static int virtnet_probe(struct virtio_device *vdev) |
989 | { | 1016 | { |
990 | int err; | 1017 | int err; |
991 | struct net_device *dev; | 1018 | struct net_device *dev; |
992 | struct virtnet_info *vi; | 1019 | struct virtnet_info *vi; |
993 | struct virtqueue *vqs[3]; | ||
994 | vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL}; | ||
995 | const char *names[] = { "input", "output", "control" }; | ||
996 | int nvqs; | ||
997 | 1020 | ||
998 | /* Allocate ourselves a network device with room for our info */ | 1021 | /* Allocate ourselves a network device with room for our info */ |
999 | dev = alloc_etherdev(sizeof(struct virtnet_info)); | 1022 | dev = alloc_etherdev(sizeof(struct virtnet_info)); |
@@ -1065,24 +1088,10 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
1065 | if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) | 1088 | if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) |
1066 | vi->mergeable_rx_bufs = true; | 1089 | vi->mergeable_rx_bufs = true; |
1067 | 1090 | ||
1068 | /* We expect two virtqueues, receive then send, | 1091 | err = init_vqs(vi); |
1069 | * and optionally control. */ | ||
1070 | nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2; | ||
1071 | |||
1072 | err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names); | ||
1073 | if (err) | 1092 | if (err) |
1074 | goto free_stats; | 1093 | goto free_stats; |
1075 | 1094 | ||
1076 | vi->rvq = vqs[0]; | ||
1077 | vi->svq = vqs[1]; | ||
1078 | |||
1079 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { | ||
1080 | vi->cvq = vqs[2]; | ||
1081 | |||
1082 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) | ||
1083 | dev->features |= NETIF_F_HW_VLAN_FILTER; | ||
1084 | } | ||
1085 | |||
1086 | err = register_netdev(dev); | 1095 | err = register_netdev(dev); |
1087 | if (err) { | 1096 | if (err) { |
1088 | pr_debug("virtio_net: registering device failed\n"); | 1097 | pr_debug("virtio_net: registering device failed\n"); |
@@ -1144,27 +1153,73 @@ static void free_unused_bufs(struct virtnet_info *vi) | |||
1144 | BUG_ON(vi->num != 0); | 1153 | BUG_ON(vi->num != 0); |
1145 | } | 1154 | } |
1146 | 1155 | ||
1147 | static void __devexit virtnet_remove(struct virtio_device *vdev) | 1156 | static void remove_vq_common(struct virtnet_info *vi) |
1148 | { | 1157 | { |
1149 | struct virtnet_info *vi = vdev->priv; | 1158 | vi->vdev->config->reset(vi->vdev); |
1150 | |||
1151 | /* Stop all the virtqueues. */ | ||
1152 | vdev->config->reset(vdev); | ||
1153 | |||
1154 | unregister_netdev(vi->dev); | ||
1155 | 1159 | ||
1156 | /* Free unused buffers in both send and recv, if any. */ | 1160 | /* Free unused buffers in both send and recv, if any. */ |
1157 | free_unused_bufs(vi); | 1161 | free_unused_bufs(vi); |
1158 | 1162 | ||
1159 | vdev->config->del_vqs(vi->vdev); | 1163 | vi->vdev->config->del_vqs(vi->vdev); |
1160 | 1164 | ||
1161 | while (vi->pages) | 1165 | while (vi->pages) |
1162 | __free_pages(get_a_page(vi, GFP_KERNEL), 0); | 1166 | __free_pages(get_a_page(vi, GFP_KERNEL), 0); |
1167 | } | ||
1168 | |||
1169 | static void __devexit virtnet_remove(struct virtio_device *vdev) | ||
1170 | { | ||
1171 | struct virtnet_info *vi = vdev->priv; | ||
1172 | |||
1173 | unregister_netdev(vi->dev); | ||
1174 | |||
1175 | remove_vq_common(vi); | ||
1163 | 1176 | ||
1164 | free_percpu(vi->stats); | 1177 | free_percpu(vi->stats); |
1165 | free_netdev(vi->dev); | 1178 | free_netdev(vi->dev); |
1166 | } | 1179 | } |
1167 | 1180 | ||
1181 | #ifdef CONFIG_PM | ||
1182 | static int virtnet_freeze(struct virtio_device *vdev) | ||
1183 | { | ||
1184 | struct virtnet_info *vi = vdev->priv; | ||
1185 | |||
1186 | virtqueue_disable_cb(vi->rvq); | ||
1187 | virtqueue_disable_cb(vi->svq); | ||
1188 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) | ||
1189 | virtqueue_disable_cb(vi->cvq); | ||
1190 | |||
1191 | netif_device_detach(vi->dev); | ||
1192 | cancel_delayed_work_sync(&vi->refill); | ||
1193 | |||
1194 | if (netif_running(vi->dev)) | ||
1195 | napi_disable(&vi->napi); | ||
1196 | |||
1197 | remove_vq_common(vi); | ||
1198 | |||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static int virtnet_restore(struct virtio_device *vdev) | ||
1203 | { | ||
1204 | struct virtnet_info *vi = vdev->priv; | ||
1205 | int err; | ||
1206 | |||
1207 | err = init_vqs(vi); | ||
1208 | if (err) | ||
1209 | return err; | ||
1210 | |||
1211 | if (netif_running(vi->dev)) | ||
1212 | virtnet_napi_enable(vi); | ||
1213 | |||
1214 | netif_device_attach(vi->dev); | ||
1215 | |||
1216 | if (!try_fill_recv(vi, GFP_KERNEL)) | ||
1217 | queue_delayed_work(system_nrt_wq, &vi->refill, 0); | ||
1218 | |||
1219 | return 0; | ||
1220 | } | ||
1221 | #endif | ||
1222 | |||
1168 | static struct virtio_device_id id_table[] = { | 1223 | static struct virtio_device_id id_table[] = { |
1169 | { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, | 1224 | { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, |
1170 | { 0 }, | 1225 | { 0 }, |
@@ -1189,6 +1244,10 @@ static struct virtio_driver virtio_net_driver = { | |||
1189 | .probe = virtnet_probe, | 1244 | .probe = virtnet_probe, |
1190 | .remove = __devexit_p(virtnet_remove), | 1245 | .remove = __devexit_p(virtnet_remove), |
1191 | .config_changed = virtnet_config_changed, | 1246 | .config_changed = virtnet_config_changed, |
1247 | #ifdef CONFIG_PM | ||
1248 | .freeze = virtnet_freeze, | ||
1249 | .restore = virtnet_restore, | ||
1250 | #endif | ||
1192 | }; | 1251 | }; |
1193 | 1252 | ||
1194 | static int __init init(void) | 1253 | static int __init init(void) |