From: Sungho Bae <[email protected]> After a device reset in noirq context the existing vrings must be re-initialized without any memory allocation, because GFP_KERNEL is not available.
The internal helpers virtqueue_reset_split() and virtqueue_reset_packed() already reset vring indices and descriptor state in place. Add a thin exported wrapper, virtqueue_reinit_vring(), that dispatches to the appropriate helper based on the ring layout. This will be used by a subsequent patch that adds noirq system-sleep PM callbacks for virtio-mmio. Signed-off-by: Sungho Bae <[email protected]> --- drivers/virtio/virtio_ring.c | 30 ++++++++++++++++++++++++++++++ include/linux/virtio_ring.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index fbca7ce1c6bf..528157b1211d 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -3936,5 +3936,35 @@ void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq, } EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device); +/** + * virtqueue_reinit_vring - reinitialize vring state without reallocation + * @_vq: the virtqueue + * + * Reset the avail/used indices and descriptor state of an existing + * virtqueue so it can be reused after a device reset. No memory is + * allocated or freed, making this safe for use in noirq context. + * + * The caller must ensure that all in-flight buffers have been completed + * or detached before invoking this function. Calling it with outstanding + * descriptors will corrupt the free-list state because num_free is + * unconditionally restored to the ring's maximum capacity while the + * desc_extra next-chain and free_head reflect only the partial free list + * that existed at reset time. + */ +void virtqueue_reinit_vring(struct virtqueue *_vq) +{ + struct vring_virtqueue *vq = to_vvq(_vq); + unsigned int num = virtqueue_is_packed(vq) ? + vq->packed.vring.num : vq->split.vring.num; + + WARN_ON(vq->vq.num_free != num); + + if (virtqueue_is_packed(vq)) + virtqueue_reset_packed(vq); + else + virtqueue_reset_split(vq); +} +EXPORT_SYMBOL_GPL(virtqueue_reinit_vring); + MODULE_DESCRIPTION("Virtio ring implementation"); MODULE_LICENSE("GPL"); diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index c97a12c1cda3..26c7c9d0a151 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -118,6 +118,9 @@ void vring_del_virtqueue(struct virtqueue *vq); /* Filter out transport-specific feature bits. */ void vring_transport_features(struct virtio_device *vdev); +/* Reinitialize a virtqueue without reallocation (safe in noirq context) */ +void virtqueue_reinit_vring(struct virtqueue *_vq); + irqreturn_t vring_interrupt(int irq, void *_vq); u32 vring_notification_data(struct virtqueue *_vq); -- 2.43.0

