summaryrefslogtreecommitdiff
path: root/OvmfPkg
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2012-10-12 18:54:35 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2012-10-12 18:54:35 +0000
commite371e7e545b266ce4ae8ff76da6c98616214599f (patch)
treea84a0cfda267c9077772bc8ec20fcf8cb65741da /OvmfPkg
parent7fcacd6c92616fd993a5befd93bcc9cad2610c90 (diff)
OvmfPkg: librarize reusable bits from VirtioBlkDxe's SynchronousRequest()
new VirtioLib functions: - VirtioPrepare(): prepare for appending descriptors - VirtioFlush(): submit descriptor chain and await host answer Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13844 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'OvmfPkg')
-rw-r--r--OvmfPkg/Include/Library/VirtioLib.h76
-rw-r--r--OvmfPkg/Library/VirtioLib/VirtioLib.c135
-rw-r--r--OvmfPkg/Library/VirtioLib/VirtioLib.inf2
-rw-r--r--OvmfPkg/VirtioBlkDxe/VirtioBlk.c58
4 files changed, 205 insertions, 66 deletions
diff --git a/OvmfPkg/Include/Library/VirtioLib.h b/OvmfPkg/Include/Library/VirtioLib.h
index eff66da6b3..07e4add784 100644
--- a/OvmfPkg/Include/Library/VirtioLib.h
+++ b/OvmfPkg/Include/Library/VirtioLib.h
@@ -135,6 +135,36 @@ VirtioRingUninit (
);
+//
+// Internal use structure for tracking the submission of a multi-descriptor
+// request.
+//
+typedef struct {
+ UINT16 HeadIdx;
+ UINT16 NextAvailIdx;
+} DESC_INDICES;
+
+
+/**
+
+ Turn off interrupt notifications from the host, and prepare for appending
+ multiple descriptors to the virtio ring.
+
+ The calling driver must be in VSTAT_DRIVER_OK state.
+
+ @param[in out] Ring The virtio ring we intend to append descriptors to.
+
+ @param[out] Indices The DESC_INDICES structure to initialize.
+
+**/
+VOID
+EFIAPI
+VirtioPrepare (
+ IN OUT VRING *Ring,
+ OUT DESC_INDICES *Indices
+ );
+
+
/**
Append a contiguous buffer for transmission / reception via the virtio ring.
@@ -148,6 +178,9 @@ VirtioRingUninit (
request submission. It is the calling driver's responsibility to verify the
ring size in advance.
+ The caller is responsible for initializing *Indices with VirtioPrepare()
+ first.
+
@param[in out] Ring The virtio ring to append the buffer to, as a
descriptor.
@@ -164,6 +197,8 @@ VirtioRingUninit (
host only interprets it dependent on
VRING_DESC_F_NEXT.
+ In *Indices:
+
@param [in] HeadIdx The index identifying the head buffer (first
buffer appended) belonging to this same
request.
@@ -176,12 +211,41 @@ VirtioRingUninit (
VOID
EFIAPI
VirtioAppendDesc (
- IN OUT VRING *Ring,
- IN UINTN BufferPhysAddr,
- IN UINT32 BufferSize,
- IN UINT16 Flags,
- IN UINT16 HeadIdx,
- IN OUT UINT16 *NextAvailIdx
+ IN OUT VRING *Ring,
+ IN UINTN BufferPhysAddr,
+ IN UINT32 BufferSize,
+ IN UINT16 Flags,
+ IN OUT DESC_INDICES *Indices
+ );
+
+
+/**
+
+ Notify the host about appended descriptors and wait until it processes the
+ last one (ie. all of them).
+
+ @param[in] PciIo The target virtio PCI device to notify.
+
+ @param[in] VirtQueueId Identifies the queue for the target device.
+
+ @param[in out] Ring The virtio ring with descriptors to submit.
+
+ @param[in] Indices The function waits until the host processes
+ descriptors up to Indices->NextAvailIdx.
+
+
+ @return Error code from VirtioWrite() if it fails.
+
+ @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtioFlush (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 VirtQueueId,
+ IN OUT VRING *Ring,
+ IN DESC_INDICES *Indices
);
#endif // _VIRTIO_LIB_H_
diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c b/OvmfPkg/Library/VirtioLib/VirtioLib.c
index f0328ef4cd..6ed977cd10 100644
--- a/OvmfPkg/Library/VirtioLib/VirtioLib.c
+++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c
@@ -15,9 +15,11 @@
**/
#include <IndustryStandard/Pci22.h>
+#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
#include <Library/VirtioLib.h>
@@ -276,6 +278,39 @@ VirtioRingUninit (
/**
+ Turn off interrupt notifications from the host, and prepare for appending
+ multiple descriptors to the virtio ring.
+
+ The calling driver must be in VSTAT_DRIVER_OK state.
+
+ @param[in out] Ring The virtio ring we intend to append descriptors to.
+
+ @param[out] Indices The DESC_INDICES structure to initialize.
+
+**/
+VOID
+EFIAPI
+VirtioPrepare (
+ IN OUT VRING *Ring,
+ OUT DESC_INDICES *Indices
+ )
+{
+ //
+ // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
+ // We're going to poll the answer, the host should not send an interrupt.
+ //
+ *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
+
+ //
+ // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
+ //
+ Indices->HeadIdx = *Ring->Avail.Idx;
+ Indices->NextAvailIdx = Indices->HeadIdx;
+}
+
+
+/**
+
Append a contiguous buffer for transmission / reception via the virtio ring.
This function implements the following sections from virtio-0.9.5:
@@ -287,6 +322,9 @@ VirtioRingUninit (
request submission. It is the calling driver's responsibility to verify the
ring size in advance.
+ The caller is responsible for initializing *Indices with VirtioPrepare()
+ first.
+
@param[in out] Ring The virtio ring to append the buffer to, as a
descriptor.
@@ -303,6 +341,8 @@ VirtioRingUninit (
host only interprets it dependent on
VRING_DESC_F_NEXT.
+ In *Indices:
+
@param [in] HeadIdx The index identifying the head buffer (first
buffer appended) belonging to this same
request.
@@ -315,21 +355,96 @@ VirtioRingUninit (
VOID
EFIAPI
VirtioAppendDesc (
- IN OUT VRING *Ring,
- IN UINTN BufferPhysAddr,
- IN UINT32 BufferSize,
- IN UINT16 Flags,
- IN UINT16 HeadIdx,
- IN OUT UINT16 *NextAvailIdx
+ IN OUT VRING *Ring,
+ IN UINTN BufferPhysAddr,
+ IN UINT32 BufferSize,
+ IN UINT16 Flags,
+ IN OUT DESC_INDICES *Indices
)
{
volatile VRING_DESC *Desc;
- Desc = &Ring->Desc[*NextAvailIdx % Ring->QueueSize];
+ Desc = &Ring->Desc[Indices->NextAvailIdx % Ring->QueueSize];
Desc->Addr = BufferPhysAddr;
Desc->Len = BufferSize;
Desc->Flags = Flags;
- Ring->Avail.Ring[(*NextAvailIdx)++ % Ring->QueueSize] =
- HeadIdx % Ring->QueueSize;
- Desc->Next = *NextAvailIdx % Ring->QueueSize;
+ Ring->Avail.Ring[Indices->NextAvailIdx++ % Ring->QueueSize] =
+ Indices->HeadIdx % Ring->QueueSize;
+ Desc->Next = Indices->NextAvailIdx % Ring->QueueSize;
+}
+
+
+/**
+
+ Notify the host about appended descriptors and wait until it processes the
+ last one (ie. all of them).
+
+ @param[in] PciIo The target virtio PCI device to notify.
+
+ @param[in] VirtQueueId Identifies the queue for the target device.
+
+ @param[in out] Ring The virtio ring with descriptors to submit.
+
+ @param[in] Indices The function waits until the host processes
+ descriptors up to Indices->NextAvailIdx.
+
+
+ @return Error code from VirtioWrite() if it fails.
+
+ @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtioFlush (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 VirtQueueId,
+ IN OUT VRING *Ring,
+ IN DESC_INDICES *Indices
+ )
+{
+ EFI_STATUS Status;
+ UINTN PollPeriodUsecs;
+
+ //
+ // virtio-0.9.5, 2.4.1.3 Updating the Index Field
+ //
+ MemoryFence();
+ *Ring->Avail.Idx = Indices->NextAvailIdx;
+
+ //
+ // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
+ // OK.
+ //
+ MemoryFence();
+ Status = VirtioWrite (
+ PciIo,
+ OFFSET_OF (VIRTIO_HDR, VhdrQueueNotify),
+ sizeof (UINT16),
+ VirtQueueId
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
+ // Wait until the host processes and acknowledges our descriptor chain. The
+ // condition we use for polling is greatly simplified and relies on the
+ // synchronous, lock-step progress.
+ //
+ // Keep slowing down until we reach a poll period of slightly above 1 ms.
+ //
+ PollPeriodUsecs = 1;
+ MemoryFence();
+ while (*Ring->Used.Idx != Indices->NextAvailIdx) {
+ gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay
+
+ if (PollPeriodUsecs < 1024) {
+ PollPeriodUsecs *= 2;
+ }
+ MemoryFence();
+ }
+
+ return EFI_SUCCESS;
}
diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.inf b/OvmfPkg/Library/VirtioLib/VirtioLib.inf
index cfd93a2c2c..fb5897a88e 100644
--- a/OvmfPkg/Library/VirtioLib/VirtioLib.inf
+++ b/OvmfPkg/Library/VirtioLib/VirtioLib.inf
@@ -29,6 +29,8 @@
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
+ BaseLib
BaseMemoryLib
DebugLib
MemoryAllocationLib
+ UefiBootServicesTableLib
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
index ce38ff7093..44a05cfb5f 100644
--- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
+++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
@@ -248,9 +248,7 @@ SynchronousRequest (
UINT32 BlockSize;
volatile VIRTIO_BLK_REQ Request;
volatile UINT8 HostStatus;
- UINT16 FirstAvailIdx;
- UINT16 NextAvailIdx;
- UINTN PollPeriodUsecs;
+ DESC_INDICES Indices;
BlockSize = Dev->BlockIoMedia.BlockSize;
@@ -275,11 +273,7 @@ SynchronousRequest (
Request.IoPrio = 0;
Request.Sector = Lba * (BlockSize / 512);
- //
- // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
- // We're going to poll the answer, the host should not send an interrupt.
- //
- *Dev->Ring.Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
+ VirtioPrepare (&Dev->Ring, &Indices);
//
// preset a host status for ourselves that we do not accept as success
@@ -293,16 +287,10 @@ SynchronousRequest (
ASSERT (Dev->Ring.QueueSize >= 3);
//
- // Implement virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
- //
- FirstAvailIdx = *Dev->Ring.Avail.Idx;
- NextAvailIdx = FirstAvailIdx;
-
- //
// virtio-blk header in first desc
//
VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request,
- VRING_DESC_F_NEXT, FirstAvailIdx, &NextAvailIdx);
+ VRING_DESC_F_NEXT, &Indices);
//
// data buffer for read/write in second desc
@@ -323,50 +311,20 @@ SynchronousRequest (
//
VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize,
VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),
- FirstAvailIdx, &NextAvailIdx);
+ &Indices);
}
//
// host status in last (second or third) desc
//
VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus,
- VRING_DESC_F_WRITE, FirstAvailIdx, &NextAvailIdx);
+ VRING_DESC_F_WRITE, &Indices);
//
- // virtio-0.9.5, 2.4.1.3 Updating the Index Field
+ // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
//
- MemoryFence();
- *Dev->Ring.Avail.Idx = NextAvailIdx;
-
- //
- // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
- // OK. virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
- //
- MemoryFence();
- if (EFI_ERROR (VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, 0))) {
- return EFI_DEVICE_ERROR;
- }
-
- //
- // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
- // Wait until the host processes and acknowledges our 3-part descriptor
- // chain. The condition we use for polling is greatly simplified and relies
- // on synchronous, the lock-step progress.
- //
- // Keep slowing down until we reach a poll period of slightly above 1 ms.
- //
- PollPeriodUsecs = 1;
- MemoryFence();
- while (*Dev->Ring.Used.Idx != NextAvailIdx) {
- gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay
-
- if (PollPeriodUsecs < 1024) {
- PollPeriodUsecs *= 2;
- }
- MemoryFence();
- }
-
- if (HostStatus == VIRTIO_BLK_S_OK) {
+ if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&
+ HostStatus == VIRTIO_BLK_S_OK) {
return EFI_SUCCESS;
}