diff options
| -rw-r--r-- | drivers/net/virtio_net.c | 63 |
1 files changed, 43 insertions, 20 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index fc7eeaa1f1b6..e44116452b7b 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
| @@ -41,6 +41,9 @@ struct virtnet_info | |||
| 41 | struct net_device *dev; | 41 | struct net_device *dev; |
| 42 | struct napi_struct napi; | 42 | struct napi_struct napi; |
| 43 | 43 | ||
| 44 | /* The skb we couldn't send because buffers were full. */ | ||
| 45 | struct sk_buff *last_xmit_skb; | ||
| 46 | |||
| 44 | /* Number of input buffers, and max we've ever had. */ | 47 | /* Number of input buffers, and max we've ever had. */ |
| 45 | unsigned int num, max; | 48 | unsigned int num, max; |
| 46 | 49 | ||
| @@ -227,17 +230,16 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) | |||
| 227 | } | 230 | } |
| 228 | } | 231 | } |
| 229 | 232 | ||
| 230 | static int start_xmit(struct sk_buff *skb, struct net_device *dev) | 233 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) |
| 231 | { | 234 | { |
| 232 | struct virtnet_info *vi = netdev_priv(dev); | 235 | int num; |
| 233 | int num, err; | ||
| 234 | struct scatterlist sg[2+MAX_SKB_FRAGS]; | 236 | struct scatterlist sg[2+MAX_SKB_FRAGS]; |
| 235 | struct virtio_net_hdr *hdr; | 237 | struct virtio_net_hdr *hdr; |
| 236 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; | 238 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; |
| 237 | 239 | ||
| 238 | sg_init_table(sg, 2+MAX_SKB_FRAGS); | 240 | sg_init_table(sg, 2+MAX_SKB_FRAGS); |
| 239 | 241 | ||
| 240 | pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb, | 242 | pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb, |
| 241 | dest[0], dest[1], dest[2], | 243 | dest[0], dest[1], dest[2], |
| 242 | dest[3], dest[4], dest[5]); | 244 | dest[3], dest[4], dest[5]); |
| 243 | 245 | ||
| @@ -272,30 +274,51 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 272 | 274 | ||
| 273 | vnet_hdr_to_sg(sg, skb); | 275 | vnet_hdr_to_sg(sg, skb); |
| 274 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; | 276 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; |
| 275 | __skb_queue_head(&vi->send, skb); | 277 | |
| 278 | return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); | ||
| 279 | } | ||
| 280 | |||
| 281 | static int start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
| 282 | { | ||
| 283 | struct virtnet_info *vi = netdev_priv(dev); | ||
| 276 | 284 | ||
| 277 | again: | 285 | again: |
| 278 | /* Free up any pending old buffers before queueing new ones. */ | 286 | /* Free up any pending old buffers before queueing new ones. */ |
| 279 | free_old_xmit_skbs(vi); | 287 | free_old_xmit_skbs(vi); |
| 280 | err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); | 288 | |
| 281 | if (err) { | 289 | /* If we has a buffer left over from last time, send it now. */ |
| 282 | pr_debug("%s: virtio not prepared to send\n", dev->name); | 290 | if (vi->last_xmit_skb) { |
| 283 | netif_stop_queue(dev); | 291 | if (xmit_skb(vi, vi->last_xmit_skb) != 0) { |
| 284 | 292 | /* Drop this skb: we only queue one. */ | |
| 285 | /* Activate callback for using skbs: if this returns false it | 293 | vi->dev->stats.tx_dropped++; |
| 286 | * means some were used in the meantime. */ | 294 | kfree_skb(skb); |
| 287 | if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { | 295 | goto stop_queue; |
| 288 | vi->svq->vq_ops->disable_cb(vi->svq); | ||
| 289 | netif_start_queue(dev); | ||
| 290 | goto again; | ||
| 291 | } | 296 | } |
| 292 | __skb_unlink(skb, &vi->send); | 297 | vi->last_xmit_skb = NULL; |
| 298 | } | ||
| 293 | 299 | ||
| 294 | return NETDEV_TX_BUSY; | 300 | /* Put new one in send queue and do transmit */ |
| 301 | __skb_queue_head(&vi->send, skb); | ||
| 302 | if (xmit_skb(vi, skb) != 0) { | ||
| 303 | vi->last_xmit_skb = skb; | ||
| 304 | goto stop_queue; | ||
| 295 | } | 305 | } |
| 306 | done: | ||
| 296 | vi->svq->vq_ops->kick(vi->svq); | 307 | vi->svq->vq_ops->kick(vi->svq); |
| 297 | 308 | return NETDEV_TX_OK; | |
| 298 | return 0; | 309 | |
| 310 | stop_queue: | ||
| 311 | pr_debug("%s: virtio not prepared to send\n", dev->name); | ||
| 312 | netif_stop_queue(dev); | ||
| 313 | |||
| 314 | /* Activate callback for using skbs: if this returns false it | ||
| 315 | * means some were used in the meantime. */ | ||
| 316 | if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { | ||
| 317 | vi->svq->vq_ops->disable_cb(vi->svq); | ||
| 318 | netif_start_queue(dev); | ||
| 319 | goto again; | ||
| 320 | } | ||
| 321 | goto done; | ||
| 299 | } | 322 | } |
| 300 | 323 | ||
| 301 | #ifdef CONFIG_NET_POLL_CONTROLLER | 324 | #ifdef CONFIG_NET_POLL_CONTROLLER |
