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
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
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
© 2016 - 2023 Red Hat, Inc.