]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg: librarize reusable bits from VirtioBlkDxe's SynchronousRequest()
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 12 Oct 2012 18:54:35 +0000 (18:54 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 12 Oct 2012 18:54:35 +0000 (18:54 +0000)
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

OvmfPkg/Include/Library/VirtioLib.h
OvmfPkg/Library/VirtioLib/VirtioLib.c
OvmfPkg/Library/VirtioLib/VirtioLib.inf
OvmfPkg/VirtioBlkDxe/VirtioBlk.c

index eff66da6b3d16c8ca7a01db91f9919dd31475c2f..07e4add7844cd29a63bbc4346cb7df41cc97c379 100644 (file)
@@ -135,6 +135,36 @@ VirtioRingUninit (
   );\r
 \r
 \r
+//\r
+// Internal use structure for tracking the submission of a multi-descriptor\r
+// request.\r
+//\r
+typedef struct {\r
+  UINT16 HeadIdx;\r
+  UINT16 NextAvailIdx;\r
+} DESC_INDICES;\r
+\r
+\r
+/**\r
+\r
+  Turn off interrupt notifications from the host, and prepare for appending\r
+  multiple descriptors to the virtio ring.\r
+\r
+  The calling driver must be in VSTAT_DRIVER_OK state.\r
+\r
+  @param[in out] Ring  The virtio ring we intend to append descriptors to.\r
+\r
+  @param[out] Indices  The DESC_INDICES structure to initialize.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VirtioPrepare (\r
+  IN OUT VRING        *Ring,\r
+  OUT    DESC_INDICES *Indices\r
+  );\r
+\r
+\r
 /**\r
 \r
   Append a contiguous buffer for transmission / reception via the virtio ring.\r
@@ -148,6 +178,9 @@ VirtioRingUninit (
   request submission. It is the calling driver's responsibility to verify the\r
   ring size in advance.\r
 \r
+  The caller is responsible for initializing *Indices with VirtioPrepare()\r
+  first.\r
+\r
   @param[in out] Ring           The virtio ring to append the buffer to, as a\r
                                 descriptor.\r
 \r
@@ -164,6 +197,8 @@ VirtioRingUninit (
                                 host only interprets it dependent on\r
                                 VRING_DESC_F_NEXT.\r
 \r
+  In *Indices:\r
+\r
   @param [in] HeadIdx           The index identifying the head buffer (first\r
                                 buffer appended) belonging to this same\r
                                 request.\r
@@ -176,12 +211,41 @@ VirtioRingUninit (
 VOID\r
 EFIAPI\r
 VirtioAppendDesc (\r
-  IN OUT VRING  *Ring,\r
-  IN     UINTN  BufferPhysAddr,\r
-  IN     UINT32 BufferSize,\r
-  IN     UINT16 Flags,\r
-  IN     UINT16 HeadIdx,\r
-  IN OUT UINT16 *NextAvailIdx\r
+  IN OUT VRING        *Ring,\r
+  IN     UINTN        BufferPhysAddr,\r
+  IN     UINT32       BufferSize,\r
+  IN     UINT16       Flags,\r
+  IN OUT DESC_INDICES *Indices\r
+  );\r
+\r
+\r
+/**\r
+\r
+  Notify the host about appended descriptors and wait until it processes the\r
+  last one (ie. all of them).\r
+\r
+  @param[in] PciIo        The target virtio PCI device to notify.\r
+\r
+  @param[in] VirtQueueId  Identifies the queue for the target device.\r
+\r
+  @param[in out] Ring     The virtio ring with descriptors to submit.\r
+\r
+  @param[in] Indices      The function waits until the host processes\r
+                          descriptors up to Indices->NextAvailIdx.\r
+\r
+\r
+  @return              Error code from VirtioWrite() if it fails.\r
+\r
+  @retval EFI_SUCCESS  Otherwise, the host processed all descriptors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFlush (\r
+  IN     EFI_PCI_IO_PROTOCOL *PciIo,\r
+  IN     UINT16              VirtQueueId,\r
+  IN OUT VRING               *Ring,\r
+  IN     DESC_INDICES        *Indices\r
   );\r
 \r
 #endif // _VIRTIO_LIB_H_\r
index f0328ef4cd6e5aaac476bbc2cca123a852380bbd..6ed977cd1019b1c3d155c2e89399bd4caedef634 100644 (file)
 **/\r
 \r
 #include <IndustryStandard/Pci22.h>\r
+#include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
 \r
 #include <Library/VirtioLib.h>\r
 \r
@@ -274,6 +276,39 @@ VirtioRingUninit (
 }\r
 \r
 \r
+/**\r
+\r
+  Turn off interrupt notifications from the host, and prepare for appending\r
+  multiple descriptors to the virtio ring.\r
+\r
+  The calling driver must be in VSTAT_DRIVER_OK state.\r
+\r
+  @param[in out] Ring  The virtio ring we intend to append descriptors to.\r
+\r
+  @param[out] Indices  The DESC_INDICES structure to initialize.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VirtioPrepare (\r
+  IN OUT VRING        *Ring,\r
+  OUT    DESC_INDICES *Indices\r
+  )\r
+{\r
+  //\r
+  // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.\r
+  // We're going to poll the answer, the host should not send an interrupt.\r
+  //\r
+  *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;\r
+\r
+  //\r
+  // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.\r
+  //\r
+  Indices->HeadIdx = *Ring->Avail.Idx;\r
+  Indices->NextAvailIdx = Indices->HeadIdx;\r
+}\r
+\r
+\r
 /**\r
 \r
   Append a contiguous buffer for transmission / reception via the virtio ring.\r
@@ -287,6 +322,9 @@ VirtioRingUninit (
   request submission. It is the calling driver's responsibility to verify the\r
   ring size in advance.\r
 \r
+  The caller is responsible for initializing *Indices with VirtioPrepare()\r
+  first.\r
+\r
   @param[in out] Ring           The virtio ring to append the buffer to, as a\r
                                 descriptor.\r
 \r
@@ -303,6 +341,8 @@ VirtioRingUninit (
                                 host only interprets it dependent on\r
                                 VRING_DESC_F_NEXT.\r
 \r
+  In *Indices:\r
+\r
   @param [in] HeadIdx           The index identifying the head buffer (first\r
                                 buffer appended) belonging to this same\r
                                 request.\r
@@ -315,21 +355,96 @@ VirtioRingUninit (
 VOID\r
 EFIAPI\r
 VirtioAppendDesc (\r
-  IN OUT VRING  *Ring,\r
-  IN     UINTN  BufferPhysAddr,\r
-  IN     UINT32 BufferSize,\r
-  IN     UINT16 Flags,\r
-  IN     UINT16 HeadIdx,\r
-  IN OUT UINT16 *NextAvailIdx\r
+  IN OUT VRING        *Ring,\r
+  IN     UINTN        BufferPhysAddr,\r
+  IN     UINT32       BufferSize,\r
+  IN     UINT16       Flags,\r
+  IN OUT DESC_INDICES *Indices\r
   )\r
 {\r
   volatile VRING_DESC *Desc;\r
 \r
-  Desc        = &Ring->Desc[*NextAvailIdx % Ring->QueueSize];\r
+  Desc        = &Ring->Desc[Indices->NextAvailIdx % Ring->QueueSize];\r
   Desc->Addr  = BufferPhysAddr;\r
   Desc->Len   = BufferSize;\r
   Desc->Flags = Flags;\r
-  Ring->Avail.Ring[(*NextAvailIdx)++ % Ring->QueueSize] =\r
-    HeadIdx % Ring->QueueSize;\r
-  Desc->Next  = *NextAvailIdx % Ring->QueueSize;\r
+  Ring->Avail.Ring[Indices->NextAvailIdx++ % Ring->QueueSize] =\r
+    Indices->HeadIdx % Ring->QueueSize;\r
+  Desc->Next  = Indices->NextAvailIdx % Ring->QueueSize;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Notify the host about appended descriptors and wait until it processes the\r
+  last one (ie. all of them).\r
+\r
+  @param[in] PciIo        The target virtio PCI device to notify.\r
+\r
+  @param[in] VirtQueueId  Identifies the queue for the target device.\r
+\r
+  @param[in out] Ring     The virtio ring with descriptors to submit.\r
+\r
+  @param[in] Indices      The function waits until the host processes\r
+                          descriptors up to Indices->NextAvailIdx.\r
+\r
+\r
+  @return              Error code from VirtioWrite() if it fails.\r
+\r
+  @retval EFI_SUCCESS  Otherwise, the host processed all descriptors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFlush (\r
+  IN     EFI_PCI_IO_PROTOCOL *PciIo,\r
+  IN     UINT16              VirtQueueId,\r
+  IN OUT VRING               *Ring,\r
+  IN     DESC_INDICES        *Indices\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  UINTN      PollPeriodUsecs;\r
+\r
+  //\r
+  // virtio-0.9.5, 2.4.1.3 Updating the Index Field\r
+  //\r
+  MemoryFence();\r
+  *Ring->Avail.Idx = Indices->NextAvailIdx;\r
+\r
+  //\r
+  // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are\r
+  // OK.\r
+  //\r
+  MemoryFence();\r
+  Status = VirtioWrite (\r
+             PciIo,\r
+             OFFSET_OF (VIRTIO_HDR, VhdrQueueNotify),\r
+             sizeof (UINT16),\r
+             VirtQueueId\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
+  // Wait until the host processes and acknowledges our descriptor chain. The\r
+  // condition we use for polling is greatly simplified and relies on the\r
+  // synchronous, lock-step progress.\r
+  //\r
+  // Keep slowing down until we reach a poll period of slightly above 1 ms.\r
+  //\r
+  PollPeriodUsecs = 1;\r
+  MemoryFence();\r
+  while (*Ring->Used.Idx != Indices->NextAvailIdx) {\r
+    gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay\r
+\r
+    if (PollPeriodUsecs < 1024) {\r
+      PollPeriodUsecs *= 2;\r
+    }\r
+    MemoryFence();\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
index cfd93a2c2c563b703362569bc183fc73c212c517..fb5897a88ecf897b51cc9f89400f5ff257480443 100644 (file)
@@ -29,6 +29,8 @@
   OvmfPkg/OvmfPkg.dec\r
 \r
 [LibraryClasses]\r
+  BaseLib\r
   BaseMemoryLib\r
   DebugLib\r
   MemoryAllocationLib\r
+  UefiBootServicesTableLib\r
index ce38ff70936ed1744020d12dc06af225fd4766e6..44a05cfb5f8be21a546ed48deb95605fed21ea95 100644 (file)
@@ -248,9 +248,7 @@ SynchronousRequest (
   UINT32                  BlockSize;\r
   volatile VIRTIO_BLK_REQ Request;\r
   volatile UINT8          HostStatus;\r
-  UINT16                  FirstAvailIdx;\r
-  UINT16                  NextAvailIdx;\r
-  UINTN                   PollPeriodUsecs;\r
+  DESC_INDICES            Indices;\r
 \r
   BlockSize = Dev->BlockIoMedia.BlockSize;\r
 \r
@@ -275,11 +273,7 @@ SynchronousRequest (
   Request.IoPrio = 0;\r
   Request.Sector = Lba * (BlockSize / 512);\r
 \r
-  //\r
-  // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.\r
-  // We're going to poll the answer, the host should not send an interrupt.\r
-  //\r
-  *Dev->Ring.Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;\r
+  VirtioPrepare (&Dev->Ring, &Indices);\r
 \r
   //\r
   // preset a host status for ourselves that we do not accept as success\r
@@ -292,17 +286,11 @@ SynchronousRequest (
   //\r
   ASSERT (Dev->Ring.QueueSize >= 3);\r
 \r
-  //\r
-  // Implement virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.\r
-  //\r
-  FirstAvailIdx = *Dev->Ring.Avail.Idx;\r
-  NextAvailIdx  = FirstAvailIdx;\r
-\r
   //\r
   // virtio-blk header in first desc\r
   //\r
   VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request,\r
-    VRING_DESC_F_NEXT, FirstAvailIdx, &NextAvailIdx);\r
+    VRING_DESC_F_NEXT, &Indices);\r
 \r
   //\r
   // data buffer for read/write in second desc\r
@@ -323,50 +311,20 @@ SynchronousRequest (
     //\r
     VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize,\r
       VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
-      FirstAvailIdx, &NextAvailIdx);\r
+      &Indices);\r
   }\r
 \r
   //\r
   // host status in last (second or third) desc\r
   //\r
   VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus,\r
-    VRING_DESC_F_WRITE, FirstAvailIdx, &NextAvailIdx);\r
+    VRING_DESC_F_WRITE, &Indices);\r
 \r
   //\r
-  // virtio-0.9.5, 2.4.1.3 Updating the Index Field\r
+  // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
   //\r
-  MemoryFence();\r
-  *Dev->Ring.Avail.Idx = NextAvailIdx;\r
-\r
-  //\r
-  // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are\r
-  // OK. virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
-  //\r
-  MemoryFence();\r
-  if (EFI_ERROR (VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, 0))) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  //\r
-  // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
-  // Wait until the host processes and acknowledges our 3-part descriptor\r
-  // chain. The condition we use for polling is greatly simplified and relies\r
-  // on synchronous, the lock-step progress.\r
-  //\r
-  // Keep slowing down until we reach a poll period of slightly above 1 ms.\r
-  //\r
-  PollPeriodUsecs = 1;\r
-  MemoryFence();\r
-  while (*Dev->Ring.Used.Idx != NextAvailIdx) {\r
-    gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay\r
-\r
-    if (PollPeriodUsecs < 1024) {\r
-      PollPeriodUsecs *= 2;\r
-    }\r
-    MemoryFence();\r
-  }\r
-\r
-  if (HostStatus == VIRTIO_BLK_S_OK) {\r
+  if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&\r
+      HostStatus == VIRTIO_BLK_S_OK) {\r
     return EFI_SUCCESS;\r
   }\r
 \r