[SeaBIOS] [PATCH] virtio-blk: segment large IO according to size_max

Andy Pei posted 1 patch 2 years, 5 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/seabios tags/patchew/1638364244-270270-1-git-send-email-andy.pei@intel.com
src/hw/virtio-blk.c | 92 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 78 insertions(+), 14 deletions(-)
[SeaBIOS] [PATCH] virtio-blk: segment large IO according to size_max
Posted by Andy Pei 2 years, 5 months ago
if driver reads data larger than VIRTIO_BLK_F_SIZE_MAX,
it will cause some issue to the DMA engine.

Signed-off-by: Andy Pei <andy.pei@intel.com>
Signed-off-by: Ding Limin <dinglimin@cmss.chinamobile.com>
---
 src/hw/virtio-blk.c | 92 +++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 78 insertions(+), 14 deletions(-)

diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c
index 7935f0f..2068823 100644
--- a/src/hw/virtio-blk.c
+++ b/src/hw/virtio-blk.c
@@ -30,6 +30,33 @@ struct virtiodrive_s {
     struct vp_device vp;
 };
 
+void
+virtio_blk_op_one_segment(struct virtiodrive_s *vdrive,
+    int write, struct vring_list sg[])
+{
+    struct vring_virtqueue *vq = vdrive->vq;
+
+    /* Add to virtqueue and kick host */
+    if (write)
+        vring_add_buf(vq, sg, 2, 1, 0, 0);
+    else
+        vring_add_buf(vq, sg, 1, 2, 0, 0);
+    vring_kick(&vdrive->vp, vq, 1);
+
+    /* Wait for reply */
+    while (!vring_more_used(vq))
+        usleep(5);
+
+    /* Reclaim virtqueue element */
+        vring_get_buf(vq, NULL);
+
+    /**
+    ** Clear interrupt status register. Avoid leaving interrupts stuck
+    ** if VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+    **/
+    vp_get_isr(&vdrive->vp);
+}
+
 static int
 virtio_blk_op(struct disk_op_s *op, int write)
 {
@@ -56,26 +83,63 @@ virtio_blk_op(struct disk_op_s *op, int write)
             .length     = sizeof(status),
         },
     };
+    u32 max_io_size =
+        vdrive->drive.max_segment_size * vdrive->drive.max_segments;
+    u16 blk_num_max;
 
-    /* Add to virtqueue and kick host */
-    if (write)
-        vring_add_buf(vq, sg, 2, 1, 0, 0);
+    if (vdrive->drive.blksize != 0 && max_io_size != 0)
+        blk_num_max = (u16)max_io_size / vdrive->drive.blksize;
     else
-        vring_add_buf(vq, sg, 1, 2, 0, 0);
-    vring_kick(&vdrive->vp, vq, 1);
+        /* default blk_num_max if hardware doesnot advise a proper value */
+        blk_num_max = 8;
 
-    /* Wait for reply */
-    while (!vring_more_used(vq))
-        usleep(5);
+    if (op->count <= blk_num_max) {
+        /* Add to virtqueue and kick host */
+        if (write)
+            vring_add_buf(vq, sg, 2, 1, 0, 0);
+        else
+            vring_add_buf(vq, sg, 1, 2, 0, 0);
+        vring_kick(&vdrive->vp, vq, 1);
 
-    /* Reclaim virtqueue element */
-    vring_get_buf(vq, NULL);
+        /* Wait for reply */
+        while (!vring_more_used(vq))
+            usleep(5);
 
-    /* Clear interrupt status register.  Avoid leaving interrupts stuck if
-     * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
-     */
-    vp_get_isr(&vdrive->vp);
+        /* Reclaim virtqueue element */
+        vring_get_buf(vq, NULL);
+
+        /* Clear interrupt status register.  Avoid leaving interrupts stuck if
+         * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+        */
+        vp_get_isr(&vdrive->vp);
+    } else {
+        struct vring_list *p_sg = &sg[1];
+        void *p  = op->buf_fl;
+        u16 count = op->count;
+
+        while (count > blk_num_max) {
+            p_sg->addr = p;
+            p_sg->length = vdrive->drive.blksize * blk_num_max;
+            virtio_blk_op_one_segment(vdrive, write, sg);
+            if (status == VIRTIO_BLK_S_OK) {
+                hdr.sector += blk_num_max;
+                p += p_sg->length;
+                count -= blk_num_max;
+            } else {
+                break;
+            }
+        }
 
+        if (status != VIRTIO_BLK_S_OK)
+            return DISK_RET_EBADTRACK;
+
+        if (count > 0) {
+            p_sg->addr = p;
+            p_sg->length = vdrive->drive.blksize * count;
+            virtio_blk_op_one_segment(vdrive, write, sg);
+        }
+
+    }
     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
 }
 
-- 
1.8.3.1

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] [PATCH] virtio-blk: segment large IO to 4K IO.
Posted by Andy Pei 2 years, 5 months ago
Signed-off-by: Andy Pei <andy.pei@intel.com>
---
 src/hw/virtio-blk.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 70 insertions(+), 1 deletion(-)

diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c
index 3b19896..4f9b1e7 100644
--- a/src/hw/virtio-blk.c
+++ b/src/hw/virtio-blk.c
@@ -30,6 +30,44 @@ struct virtiodrive_s {
     struct vp_device vp;
 };
 
+#define BLK_NUM_MAX    8
+
+void dump(unsigned char *buf, int len)
+{
+	int i;
+	for (i = 0; i < len;) {
+		printf(" %2x", 0xff & buf[i++]);
+		if (i % 32 == 0)
+			printf("\n");
+	}
+	printf("\n");
+}
+
+void
+segment(struct virtiodrive_s *vdrive, int write, struct vring_list sg[])
+{
+	struct vring_virtqueue *vq = vdrive->vq;
+	
+	/* Add to virtqueue and kick host */
+	if (write)
+		vring_add_buf(vq, sg, 2, 1, 0, 0);
+	else
+		vring_add_buf(vq, sg, 1, 2, 0, 0);
+	vring_kick(&vdrive->vp, vq, 1);
+	
+	/* Wait for reply */
+	while (!vring_more_used(vq))
+		usleep(5);
+	
+	/* Reclaim virtqueue element */
+	vring_get_buf(vq, NULL);
+	
+	/* Clear interrupt status register.  Avoid leaving interrupts stuck if
+	 * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+	 */
+	vp_get_isr(&vdrive->vp);
+}
+
 static int
 virtio_blk_op(struct disk_op_s *op, int write)
 {
@@ -57,6 +95,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
         },
     };
 
+    if (op->count <= BLK_NUM_MAX) {/* added by andy */
     /* Add to virtqueue and kick host */
     if (write)
         vring_add_buf(vq, sg, 2, 1, 0, 0);
@@ -75,7 +114,37 @@ virtio_blk_op(struct disk_op_s *op, int write)
      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
      */
     vp_get_isr(&vdrive->vp);
-
+    } else {/* added by Andy */
+	struct vring_list *p_sg = &sg[1];
+	void *p  = op->buf_fl;
+	u16 count = op->count;
+
+	while (count > BLK_NUM_MAX) {
+		p_sg->addr = p;
+		p_sg->length = vdrive->drive.blksize * BLK_NUM_MAX;
+		segment(vdrive, write, sg);
+		//dump(p, p_sg->length);
+		if (status == VIRTIO_BLK_S_OK) {
+			hdr.sector += BLK_NUM_MAX;
+			p += p_sg->length;
+			count -= BLK_NUM_MAX;
+		} else {
+			break;
+		}
+	}
+
+	if (status != VIRTIO_BLK_S_OK) {
+		return DISK_RET_EBADTRACK;
+	}
+
+	if(count > 0) {
+		p_sg->addr = p;
+		p_sg->length = vdrive->drive.blksize * count;
+		segment(vdrive, write, sg);
+		//dump(p, p_sg->length);
+	}
+
+    }/* end of modification from Andy */
     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
 }
 
-- 
1.8.3.1

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH] virtio-blk: segment large IO to 4K IO.
Posted by Pei, Andy 2 years, 5 months ago
Hi,

Terribly sorry for sending out a wrong patch.
A V2 series will be sent, please ignore this patch set.
Sorry for confusing.

-----Original Message-----
From: Pei, Andy <andy.pei@intel.com> 
Sent: Wednesday, December 1, 2021 9:11 PM
To: seabios@seabios.org
Cc: kraxel@redhat.com; kevin@koconnor.net; Pei, Andy <andy.pei@intel.com>
Subject: [PATCH] virtio-blk: segment large IO to 4K IO.

Signed-off-by: Andy Pei <andy.pei@intel.com>
---
 src/hw/virtio-blk.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 70 insertions(+), 1 deletion(-)

diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 3b19896..4f9b1e7 100644
--- a/src/hw/virtio-blk.c
+++ b/src/hw/virtio-blk.c
@@ -30,6 +30,44 @@ struct virtiodrive_s {
     struct vp_device vp;
 };
 
+#define BLK_NUM_MAX    8
+
+void dump(unsigned char *buf, int len)
+{
+	int i;
+	for (i = 0; i < len;) {
+		printf(" %2x", 0xff & buf[i++]);
+		if (i % 32 == 0)
+			printf("\n");
+	}
+	printf("\n");
+}
+
+void
+segment(struct virtiodrive_s *vdrive, int write, struct vring_list 
+sg[]) {
+	struct vring_virtqueue *vq = vdrive->vq;
+	
+	/* Add to virtqueue and kick host */
+	if (write)
+		vring_add_buf(vq, sg, 2, 1, 0, 0);
+	else
+		vring_add_buf(vq, sg, 1, 2, 0, 0);
+	vring_kick(&vdrive->vp, vq, 1);
+	
+	/* Wait for reply */
+	while (!vring_more_used(vq))
+		usleep(5);
+	
+	/* Reclaim virtqueue element */
+	vring_get_buf(vq, NULL);
+	
+	/* Clear interrupt status register.  Avoid leaving interrupts stuck if
+	 * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+	 */
+	vp_get_isr(&vdrive->vp);
+}
+
 static int
 virtio_blk_op(struct disk_op_s *op, int write)  { @@ -57,6 +95,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
         },
     };
 
+    if (op->count <= BLK_NUM_MAX) {/* added by andy */
     /* Add to virtqueue and kick host */
     if (write)
         vring_add_buf(vq, sg, 2, 1, 0, 0); @@ -75,7 +114,37 @@ virtio_blk_op(struct disk_op_s *op, int write)
      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
      */
     vp_get_isr(&vdrive->vp);
-
+    } else {/* added by Andy */
+	struct vring_list *p_sg = &sg[1];
+	void *p  = op->buf_fl;
+	u16 count = op->count;
+
+	while (count > BLK_NUM_MAX) {
+		p_sg->addr = p;
+		p_sg->length = vdrive->drive.blksize * BLK_NUM_MAX;
+		segment(vdrive, write, sg);
+		//dump(p, p_sg->length);
+		if (status == VIRTIO_BLK_S_OK) {
+			hdr.sector += BLK_NUM_MAX;
+			p += p_sg->length;
+			count -= BLK_NUM_MAX;
+		} else {
+			break;
+		}
+	}
+
+	if (status != VIRTIO_BLK_S_OK) {
+		return DISK_RET_EBADTRACK;
+	}
+
+	if(count > 0) {
+		p_sg->addr = p;
+		p_sg->length = vdrive->drive.blksize * count;
+		segment(vdrive, write, sg);
+		//dump(p, p_sg->length);
+	}
+
+    }/* end of modification from Andy */
     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;  }
 
--
1.8.3.1

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org