#include <linux/virtio_net.h>
#include <linux/scatterlist.h>
+static int napi_weight = 128;
+module_param(napi_weight, int, 0444);
+
static int csum = 1, gso = 1;
module_param(csum, bool, 0444);
module_param(gso, bool, 0444);
sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
}
-static void skb_xmit_done(struct virtqueue *rvq)
+static void skb_xmit_done(struct virtqueue *svq)
{
- struct virtnet_info *vi = rvq->vdev->priv;
+ struct virtnet_info *vi = svq->vdev->priv;
- /* In case we were waiting for output buffers. */
+ /* Suppress further interrupts. */
+ svq->vq_ops->disable_cb(svq);
+ /* We were waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
- free_old_xmit_skbs(vi);
-
/* Encode metadata header at front. */
hdr = skb_vnet_hdr(skb);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
__skb_queue_head(&vi->send, skb);
+
+again:
+ /* Free up any pending old buffers before queueing new ones. */
+ free_old_xmit_skbs(vi);
err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
if (err) {
pr_debug("%s: virtio not prepared to send\n", dev->name);
- skb_unlink(skb, &vi->send);
netif_stop_queue(dev);
+
+ /* Activate callback for using skbs: if this fails it
+ * means some were used in the meantime. */
+ if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+ printk("Unlikely: restart svq failed\n");
+ netif_start_queue(dev);
+ goto again;
+ }
+ __skb_unlink(skb, &vi->send);
+
return NETDEV_TX_BUSY;
}
vi->svq->vq_ops->kick(vi->svq);
struct virtnet_info *vi = netdev_priv(dev);
napi_enable(&vi->napi);
+
+ /* If all buffers were filled by other side before we napi_enabled, we
+ * won't get another interrupt, so process any outstanding packets
+ * now. virtnet_poll wants re-enable the queue, so we disable here.
+ * We synchronize against interrupts via NAPI_STATE_SCHED */
+ if (netif_rx_schedule_prep(dev, &vi->napi)) {
+ vi->rvq->vq_ops->disable_cb(vi->rvq);
+ __netif_rx_schedule(dev, &vi->napi);
+ }
return 0;
}
/* Set up our device-specific information */
vi = netdev_priv(dev);
- netif_napi_add(dev, &vi->napi, virtnet_poll, 16);
+ netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight);
vi->dev = dev;
vi->vdev = vdev;
+ vdev->priv = vi;
/* We expect two virtqueues, receive then send. */
vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
}
pr_debug("virtnet: registered device %s\n", dev->name);
- vdev->priv = vi;
return 0;
unregister: