Commit 99ffc696 authored by Rusty Russell's avatar Rusty Russell

virtio: wean net driver off NETDEV_TX_BUSY

Herbert tells me that returning NETDEV_TX_BUSY from hard_start_xmit is
seen as a poor thing to do; we should cache the packet and stop the queue.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 2e895e4c
...@@ -41,6 +41,9 @@ struct virtnet_info ...@@ -41,6 +41,9 @@ struct virtnet_info
struct net_device *dev; struct net_device *dev;
struct napi_struct napi; struct napi_struct napi;
/* The skb we couldn't send because buffers were full. */
struct sk_buff *last_xmit_skb;
/* Number of input buffers, and max we've ever had. */ /* Number of input buffers, and max we've ever had. */
unsigned int num, max; unsigned int num, max;
...@@ -227,17 +230,16 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) ...@@ -227,17 +230,16 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
} }
} }
static int start_xmit(struct sk_buff *skb, struct net_device *dev) static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
{ {
struct virtnet_info *vi = netdev_priv(dev); int num;
int num, err;
struct scatterlist sg[2+MAX_SKB_FRAGS]; struct scatterlist sg[2+MAX_SKB_FRAGS];
struct virtio_net_hdr *hdr; struct virtio_net_hdr *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
sg_init_table(sg, 2+MAX_SKB_FRAGS); sg_init_table(sg, 2+MAX_SKB_FRAGS);
pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb, pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb,
dest[0], dest[1], dest[2], dest[0], dest[1], dest[2],
dest[3], dest[4], dest[5]); dest[3], dest[4], dest[5]);
...@@ -272,13 +274,40 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -272,13 +274,40 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
vnet_hdr_to_sg(sg, skb); vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
__skb_queue_head(&vi->send, skb);
return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
}
static int start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
again: again:
/* Free up any pending old buffers before queueing new ones. */ /* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(vi); free_old_xmit_skbs(vi);
err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
if (err) { /* If we has a buffer left over from last time, send it now. */
if (vi->last_xmit_skb) {
if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
/* Drop this skb: we only queue one. */
vi->dev->stats.tx_dropped++;
kfree_skb(skb);
goto stop_queue;
}
vi->last_xmit_skb = NULL;
}
/* Put new one in send queue and do transmit */
__skb_queue_head(&vi->send, skb);
if (xmit_skb(vi, skb) != 0) {
vi->last_xmit_skb = skb;
goto stop_queue;
}
done:
vi->svq->vq_ops->kick(vi->svq);
return NETDEV_TX_OK;
stop_queue:
pr_debug("%s: virtio not prepared to send\n", dev->name); pr_debug("%s: virtio not prepared to send\n", dev->name);
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -289,13 +318,7 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -289,13 +318,7 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev); netif_start_queue(dev);
goto again; goto again;
} }
__skb_unlink(skb, &vi->send); goto done;
return NETDEV_TX_BUSY;
}
vi->svq->vq_ops->kick(vi->svq);
return 0;
} }
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment