From 734457162d02f6b4d66b8eb82da0717765fceebe Mon Sep 17 00:00:00 2001 From: Adttil <2429917001@qq.com> Date: Fri, 29 Nov 2024 09:04:13 +0800 Subject: [PATCH 3/3] VirtioBlk: split large IO according to segment_size_max When the VirtioBlk device is initialized, the value of SegmentSizeMax is obtained based on the feature capability. Then delivere the requests based on the value of SegmentSizeMax. Signed-off-by: jiangdongxu --- MdePkg/Include/Protocol/BlockIo.h | 10 ++ OvmfPkg/VirtioBlkDxe/VirtioBlk.c | 148 +++++++++++++++++++++--------- 2 files changed, 117 insertions(+), 41 deletions(-) diff --git a/MdePkg/Include/Protocol/BlockIo.h b/MdePkg/Include/Protocol/BlockIo.h index ac9adf7a..ac5e1c2a 100644 --- a/MdePkg/Include/Protocol/BlockIo.h +++ b/MdePkg/Include/Protocol/BlockIo.h @@ -197,6 +197,16 @@ typedef struct { /// granularity as a number of logical blocks. /// UINT32 OptimalTransferLengthGranularity; + + /// + /// Maximum size of any single segment + /// + UINT32 MaxSegmentSize; + + /// + /// Maximum number of segments in a request + /// + UINT32 MaxSegments; } EFI_BLOCK_IO_MEDIA; #define EFI_BLOCK_IO_PROTOCOL_REVISION 0x00010000 diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c index eed56994..6d7c7aef 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c @@ -31,6 +31,8 @@ #define MAX_RETRY_TIMES 1000 #define DEVICE_WAIT_INTVL 1000 +#define DEFAULT_MAX_SEGMENTS 32 + /** Convenience macros to read and write region 0 IO space elements of the @@ -460,6 +462,68 @@ FreeHostStatusBuffer: return Status; } +STATIC +EFI_STATUS +EFIAPI +VirtioBlkReadWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN OUT VOID *Buffer, + IN BOOLEAN RequestIsWrite + ) +{ + VBLK_DEV *Dev; + EFI_STATUS Status; + UINT32 SizeMax; + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + Dev = VIRTIO_BLK_FROM_BLOCK_IO (This); + Status = VerifyReadWriteRequest ( + &Dev->BlockIoMedia, + Lba, + BufferSize, + RequestIsWrite + ); + if (EFI_ERROR (Status)) { + return Status; + } + + SizeMax = Dev->BlockIoMedia.MaxSegmentSize; + while (BufferSize >= SizeMax) { + Status = SynchronousRequest ( + Dev, + Lba, + SizeMax, + Buffer, + RequestIsWrite + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba += SizeMax / Dev->BlockIoMedia.BlockSize; + BufferSize -= SizeMax; + Buffer = (CHAR8 *)Buffer + SizeMax; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + return SynchronousRequest ( + Dev, + Lba, + BufferSize, + Buffer, + RequestIsWrite + ); +} + /** ReadBlocks() operation for virtio-blk. @@ -487,30 +551,13 @@ VirtioBlkReadBlocks ( OUT VOID *Buffer ) { - VBLK_DEV *Dev; - EFI_STATUS Status; - - if (BufferSize == 0) { - return EFI_SUCCESS; - } - - Dev = VIRTIO_BLK_FROM_BLOCK_IO (This); - Status = VerifyReadWriteRequest ( - &Dev->BlockIoMedia, - Lba, - BufferSize, - FALSE // RequestIsWrite - ); - if (EFI_ERROR (Status)) { - return Status; - } - - return SynchronousRequest ( - Dev, + return VirtioBlkReadWriteBlocks( + This, + MediaId, Lba, BufferSize, Buffer, - FALSE // RequestIsWrite + FALSE // RequestIsRead ); } @@ -541,26 +588,9 @@ VirtioBlkWriteBlocks ( IN VOID *Buffer ) { - VBLK_DEV *Dev; - EFI_STATUS Status; - - if (BufferSize == 0) { - return EFI_SUCCESS; - } - - Dev = VIRTIO_BLK_FROM_BLOCK_IO (This); - Status = VerifyReadWriteRequest ( - &Dev->BlockIoMedia, - Lba, - BufferSize, - TRUE // RequestIsWrite - ); - if (EFI_ERROR (Status)) { - return Status; - } - - return SynchronousRequest ( - Dev, + return VirtioBlkReadWriteBlocks( + This, + MediaId, Lba, BufferSize, Buffer, @@ -716,6 +746,8 @@ VirtioBlkInit ( UINT8 NextDevStat; EFI_STATUS Status; + UINT32 MaxSegmentSize; + UINT32 MaxSegments; UINT64 Features; UINT64 NumSectors; UINT32 BlockSize; @@ -814,6 +846,36 @@ VirtioBlkInit ( BlockSize = 512; } + if (Features & VIRTIO_BLK_F_SIZE_MAX) { + Status = VIRTIO_CFG_READ (Dev, SizeMax, &MaxSegmentSize); + if (EFI_ERROR (Status)) { + goto Failed; + } + if (MaxSegmentSize == 0) { + // + // We need at least one 4KB page. + // + MaxSegmentSize = SIZE_4KB; + } + } else { + MaxSegmentSize = SIZE_512KB; + } + + if (Features & VIRTIO_BLK_F_SEG_MAX) { + Status = VIRTIO_CFG_READ (Dev, SegMax, &MaxSegments); + if (EFI_ERROR (Status)) { + goto Failed; + } + if (MaxSegments == 0) { + // + // We need at least one SG element, whatever they say. + // + MaxSegments = 1; + } + } else { + MaxSegments = DEFAULT_MAX_SEGMENTS; + } + if (Features & VIRTIO_BLK_F_TOPOLOGY) { Status = VIRTIO_CFG_READ ( Dev, @@ -955,6 +1017,8 @@ VirtioBlkInit ( Dev->BlockIoMedia.ReadOnly = (BOOLEAN)((Features & VIRTIO_BLK_F_RO) != 0); Dev->BlockIoMedia.WriteCaching = (BOOLEAN)((Features & VIRTIO_BLK_F_FLUSH) != 0); Dev->BlockIoMedia.BlockSize = BlockSize; + Dev->BlockIoMedia.MaxSegments = MaxSegments; + Dev->BlockIoMedia.MaxSegmentSize = MaxSegmentSize; Dev->BlockIoMedia.IoAlign = 0; Dev->BlockIoMedia.LastBlock = DivU64x32 ( NumSectors, @@ -968,6 +1032,8 @@ VirtioBlkInit ( Dev->BlockIoMedia.BlockSize, Dev->BlockIoMedia.LastBlock + 1 )); + DEBUG ((DEBUG_INFO, "%a: MaxSegments=0x%x[B] MaxSegmentSize=0x%x[B]\n", + __FUNCTION__, Dev->BlockIoMedia.MaxSegments, Dev->BlockIoMedia.MaxSegmentSize)); if (Features & VIRTIO_BLK_F_TOPOLOGY) { Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; -- 2.43.0