The rng, net, blk and scsi drivers all use virtio_reset() as their
remove() method.

virtio_reset() only uses the transport's reset() operation, leaving the
virtual queues still allocated (12 KB per virtqueue). Every probe/remove
cycle of a virtio device therefore fails to free its queues.

Add a remove() method to delete the queues before resetting. Update the
four drivers to use it.

Signed-off-by: Simon Glass <[email protected]>
---

 drivers/virtio/virtio-uclass.c | 7 +++++++
 drivers/virtio/virtio_blk.c    | 2 +-
 drivers/virtio/virtio_net.c    | 2 +-
 drivers/virtio/virtio_rng.c    | 2 +-
 include/virtio.h               | 8 ++++++++
 5 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
index 7003f30cb85..532d50ea088 100644
--- a/drivers/virtio/virtio-uclass.c
+++ b/drivers/virtio/virtio-uclass.c
@@ -90,6 +90,13 @@ int virtio_reset(struct udevice *vdev)
        return ops->reset(vdev->parent);
 }
 
+int virtio_remove(struct udevice *vdev)
+{
+       virtio_del_vqs(vdev);
+
+       return virtio_reset(vdev);
+}
+
 int virtio_get_features(struct udevice *vdev, u64 *features)
 {
        struct dm_virtio_ops *ops;
diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
index 404d9140cb2..fe06135a7ac 100644
--- a/drivers/virtio/virtio_blk.c
+++ b/drivers/virtio/virtio_blk.c
@@ -296,7 +296,7 @@ U_BOOT_DRIVER(virtio_blk) = {
        .ops    = &virtio_blk_ops,
        .bind   = virtio_blk_bind,
        .probe  = virtio_blk_probe,
-       .remove = virtio_reset,
+       .remove = virtio_remove,
        .priv_auto      = sizeof(struct virtio_blk_priv),
        .flags  = DM_FLAG_ACTIVE_DMA,
 };
diff --git a/drivers/virtio/virtio_net.c b/drivers/virtio/virtio_net.c
index 7a94c8a528f..d49dab3a6ed 100644
--- a/drivers/virtio/virtio_net.c
+++ b/drivers/virtio/virtio_net.c
@@ -233,7 +233,7 @@ U_BOOT_DRIVER(virtio_net) = {
        .id     = UCLASS_ETH,
        .bind   = virtio_net_bind,
        .probe  = virtio_net_probe,
-       .remove = virtio_reset,
+       .remove = virtio_remove,
        .ops    = &virtio_net_ops,
        .priv_auto      = sizeof(struct virtio_net_priv),
        .plat_auto      = sizeof(struct eth_pdata),
diff --git a/drivers/virtio/virtio_rng.c b/drivers/virtio/virtio_rng.c
index c6de62142bb..9a5db5f3930 100644
--- a/drivers/virtio/virtio_rng.c
+++ b/drivers/virtio/virtio_rng.c
@@ -89,7 +89,7 @@ U_BOOT_DRIVER(virtio_rng) = {
        .id     = UCLASS_RNG,
        .bind   = virtio_rng_bind,
        .probe  = virtio_rng_probe,
-       .remove = virtio_reset,
+       .remove = virtio_remove,
        .ops    = &virtio_rng_ops,
        .priv_auto      = sizeof(struct virtio_rng_priv),
        .flags  = DM_FLAG_ACTIVE_DMA,
diff --git a/include/virtio.h b/include/virtio.h
index 3edf023463d..5c580e59779 100644
--- a/include/virtio.h
+++ b/include/virtio.h
@@ -285,6 +285,14 @@ int virtio_set_status(struct udevice *vdev, u8 status);
  */
 int virtio_reset(struct udevice *vdev);
 
+/**
+ * virtio_remove() - remove a virtio device by deleting its vqs and resetting 
it
+ *
+ * @vdev:      the real virtio device
+ * Return: 0 if OK, -ve on error
+ */
+int virtio_remove(struct udevice *vdev);
+
 /**
  * virtio_get_features() - get the array of feature bits for this device
  *
-- 
2.43.0

Reply via email to