diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 409a8e180918..ffff323dcef0 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -251,6 +251,11 @@ struct padded_vnet_hdr {
char padding[4];
};
+static void virtnet_sq_free_unused_bufs(struct virtnet_info *vi,
+ struct send_queue *sq);
+static void virtnet_rq_free_unused_bufs(struct virtnet_info *vi,
+ struct receive_queue *rq);
+
static bool is_xdp_frame(void *ptr)
{
return (unsigned long)ptr & VIRTIO_XDP_FLAG;@@ -1369,6 +1374,9 @@ static void virtnet_napi_enable(struct virtqueue *vq, struct napi_struct *napi)
{
napi_enable(napi);
+ if (vq->reset)
+ return;
+
/* If all buffers were filled by other side before we napi_enabled, we
* won't get another interrupt, so process any outstanding packets now.
* Call local_bh_enable after to trigger softIRQ processing.@@ -1413,6 +1421,10 @@ static void refill_work(struct work_struct *work)
struct receive_queue *rq = &vi->rq[i];
napi_disable(&rq->napi);
+ if (rq->vq->reset) {
+ virtnet_napi_enable(rq->vq, &rq->napi);
+ continue;
+ }
still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
virtnet_napi_enable(rq->vq, &rq->napi);
@@ -1523,6 +1535,9 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)
if (!sq->napi.weight || is_xdp_raw_buffer_queue(vi, index))
return;
+ if (sq->vq->reset)
+ return;
+
if (__netif_tx_trylock(txq)) {
do {
virtqueue_disable_cb(sq->vq);@@ -1769,6 +1784,98 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+static int virtnet_rx_vq_reset(struct virtnet_info *vi,
+ struct receive_queue *rq, u32 ring_num)
+{
+ int err;
+
+ /* stop napi */
+ napi_disable(&rq->napi);
+
+ /* reset the queue */
+ err = virtio_reset_vq(rq->vq);
+ if (err)
+ goto err;
+
+ /* free bufs */
+ virtnet_rq_free_unused_bufs(vi, rq);
+
+ /* reset vring. */
+ err = virtqueue_reset_vring(rq->vq, ring_num);
+ if (err)
+ goto err;
+
+ /* enable reset queue */
+ err = virtio_enable_resetq(rq->vq);
+ if (err)
+ goto err;
+
+ /* fill recv */
+ if (!try_fill_recv(vi, rq, GFP_KERNEL))
+ schedule_delayed_work(&vi->refill, 0);
+
+ /* enable napi */
+ virtnet_napi_enable(rq->vq, &rq->napi);
+ return 0;
+
+err:
+ netdev_err(vi->dev,
+ "reset rx reset vq fail: rx queue index: %ld err: %d\n",
+ rq - vi->rq, err);
+ virtnet_napi_enable(rq->vq, &rq->napi);
+ return err;
+}
+
+static int virtnet_tx_vq_reset(struct virtnet_info *vi,
+ struct send_queue *sq, u32 ring_num)
+{
+ struct netdev_queue *txq;
+ int err, qindex;
+
+ qindex = sq - vi->sq;
+
+ txq = netdev_get_tx_queue(vi->dev, qindex);
+ __netif_tx_lock_bh(txq);
+
+ /* stop tx queue and napi */
+ netif_stop_subqueue(vi->dev, qindex);
+ virtnet_napi_tx_disable(&sq->napi);
+
+ __netif_tx_unlock_bh(txq);
+
+ /* reset the queue */
+ err = virtio_reset_vq(sq->vq);
+ if (err) {
+ netif_start_subqueue(vi->dev, qindex);
+ goto err;
+ }
+
+ /* free bufs */
+ virtnet_sq_free_unused_bufs(vi, sq);
+
+ /* reset vring. */
+ err = virtqueue_reset_vring(sq->vq, ring_num);
+ if (err)
+ goto err;
+
+ /* enable reset queue */
+ err = virtio_enable_resetq(sq->vq);
+ if (err)
+ goto err;
+
+ /* start tx queue and napi */
+ netif_start_subqueue(vi->dev, qindex);
+ virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+ return 0;
+
+err:
+ netdev_err(vi->dev,
+ "reset tx reset vq fail: tx queue index: %ld err: %d\n",
+ sq - vi->sq, err);
+ virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+ return err;
+}
+
/*
* Send command via the control virtqueue and check status. Commands
* supported by the hypervisor, as indicated by feature bits, should--
2.31.0
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization