aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/virtio_net.c63
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
230static int start_xmit(struct sk_buff *skb, struct net_device *dev) 233static 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
281static int start_xmit(struct sk_buff *skb, struct net_device *dev)
282{
283 struct virtnet_info *vi = netdev_priv(dev);
276 284
277again: 285again:
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 }
306done:
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
310stop_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