]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/VirtioLib/VirtioLib.c
OvmfPkg: Make the VirtIo devices use the new VIRTIO_DEVICE_PROTOCOL
[mirror_edk2.git] / OvmfPkg / Library / VirtioLib / VirtioLib.c
index 8398c9db4c51c4f77b407ed5aa4a1e24a50e2123..503d4adffc8c24722d0b123baded1f43f9960568 100644 (file)
@@ -3,6 +3,7 @@
   Utility functions used by virtio device drivers.\r
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
+  Portion of Copyright (C) 2013, ARM Ltd.\r
 \r
   This program and the accompanying materials are licensed and made available\r
   under the terms and conditions of the BSD License which accompanies this\r
@@ -14,7 +15,6 @@
 \r
 **/\r
 \r
-#include <IndustryStandard/Pci22.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 \r
 /**\r
 \r
-  Write a word into Region 0 of the device specified by PciIo.\r
+  Write a word into Region 0 of the device specified by VirtIo.\r
 \r
   Region 0 must be an iomem region. This is an internal function for the\r
   driver-specific VIRTIO_CFG_WRITE() macros.\r
 \r
-  @param[in] PciIo        Target PCI device.\r
+  @param[in] VirtIo       Target VirtIo device.\r
 \r
   @param[in] FieldOffset  Destination offset.\r
 \r
                           The least significant FieldSize bytes will be used.\r
 \r
 \r
-  @return  Status code returned by PciIo->Io.Write().\r
+  @return  Status code returned by VirtIo->Io.Write().\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-VirtioWrite (\r
-  IN EFI_PCI_IO_PROTOCOL *PciIo,\r
-  IN UINTN               FieldOffset,\r
-  IN UINTN               FieldSize,\r
-  IN UINT64              Value\r
+VirtioWriteDevice (\r
+  IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
+  IN UINTN                  FieldOffset,\r
+  IN UINTN                  FieldSize,\r
+  IN UINT64                 Value\r
   )\r
 {\r
-  UINTN                     Count;\r
-  EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
-\r
-  Count = 1;\r
-  switch (FieldSize) {\r
-    case 1:\r
-      Width = EfiPciIoWidthUint8;\r
-      break;\r
-\r
-    case 2:\r
-      Width = EfiPciIoWidthUint16;\r
-      break;\r
-\r
-    case 8:\r
-      Count = 2;\r
-      // fall through\r
-\r
-    case 4:\r
-      Width = EfiPciIoWidthUint32;\r
-      break;\r
-\r
-    default:\r
-      ASSERT (FALSE);\r
-      return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  return PciIo->Io.Write (\r
-                     PciIo,\r
-                     Width,\r
-                     PCI_BAR_IDX0,\r
-                     FieldOffset,\r
-                     Count,\r
-                     &Value\r
-                     );\r
+  return VirtIo->WriteDevice (VirtIo, FieldOffset, FieldSize, Value);\r
 }\r
 \r
 \r
 /**\r
 \r
-  Read a word from Region 0 of the device specified by PciIo.\r
+  Read a word from Region 0 of the device specified by VirtIo.\r
 \r
   Region 0 must be an iomem region. This is an internal function for the\r
   driver-specific VIRTIO_CFG_READ() macros.\r
 \r
-  @param[in] PciIo        Source PCI device.\r
+  @param[in] VirtIo       Source VirtIo device.\r
 \r
   @param[in] FieldOffset  Source offset.\r
 \r
@@ -109,55 +76,20 @@ VirtioWrite (
   @param[out] Buffer      Target buffer.\r
 \r
 \r
-  @return  Status code returned by PciIo->Io.Read().\r
+  @return  Status code returned by VirtIo->Io.Read().\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-VirtioRead (\r
-  IN  EFI_PCI_IO_PROTOCOL *PciIo,\r
-  IN  UINTN               FieldOffset,\r
-  IN  UINTN               FieldSize,\r
-  IN  UINTN               BufferSize,\r
-  OUT VOID                *Buffer\r
+VirtioReadDevice (\r
+  IN  VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
+  IN  UINTN                  FieldOffset,\r
+  IN  UINTN                  FieldSize,\r
+  IN  UINTN                  BufferSize,\r
+  OUT VOID                   *Buffer\r
   )\r
 {\r
-  UINTN                     Count;\r
-  EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
-\r
-  ASSERT (FieldSize == BufferSize);\r
-\r
-  Count = 1;\r
-  switch (FieldSize) {\r
-    case 1:\r
-      Width = EfiPciIoWidthUint8;\r
-      break;\r
-\r
-    case 2:\r
-      Width = EfiPciIoWidthUint16;\r
-      break;\r
-\r
-    case 8:\r
-      Count = 2;\r
-      // fall through\r
-\r
-    case 4:\r
-      Width = EfiPciIoWidthUint32;\r
-      break;\r
-\r
-    default:\r
-      ASSERT (FALSE);\r
-      return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  return PciIo->Io.Read (\r
-                     PciIo,\r
-                     Width,\r
-                     PCI_BAR_IDX0,\r
-                     FieldOffset,\r
-                     Count,\r
-                     Buffer\r
-                     );\r
+  return VirtIo->ReadDevice (VirtIo, FieldOffset, FieldSize, BufferSize, Buffer);\r
 }\r
 \r
 \r
@@ -285,7 +217,7 @@ VirtioRingUninit (
 \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
+  @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
@@ -306,8 +238,11 @@ VirtioPrepare (
   //\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
+  // Since we support only one in-flight descriptor chain, we can always build\r
+  // that chain starting at entry #0 of the descriptor table.\r
+  //\r
+  Indices->HeadDescIdx = 0;\r
+  Indices->NextDescIdx = Indices->HeadDescIdx;\r
 }\r
 \r
 \r
@@ -315,9 +250,8 @@ VirtioPrepare (
 \r
   Append a contiguous buffer for transmission / reception via the virtio ring.\r
 \r
-  This function implements the following sections from virtio-0.9.5:\r
+  This function implements the following section from virtio-0.9.5:\r
   - 2.4.1.1 Placing Buffers into the Descriptor Table\r
-  - 2.4.1.2 Updating the Available Ring\r
 \r
   Free space is taken as granted, since the individual drivers support only\r
   synchronous requests and host side status is processed in lock-step with\r
@@ -327,31 +261,26 @@ VirtioPrepare (
   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
-  @param [in] BufferPhysAddr    (Guest pseudo-physical) start address of the\r
-                                transmit / receive buffer.\r
+  @param[in,out] Ring        The virtio ring to append the buffer to, as a\r
+                             descriptor.\r
 \r
-  @param [in] BufferSize        Number of bytes to transmit or receive.\r
+  @param[in] BufferPhysAddr  (Guest pseudo-physical) start address of the\r
+                             transmit / receive buffer.\r
 \r
-  @param [in] Flags             A bitmask of VRING_DESC_F_* flags. The caller\r
-                                computes this mask dependent on further buffers\r
-                                to append and transfer direction.\r
-                                VRING_DESC_F_INDIRECT is unsupported. The\r
-                                VRING_DESC.Next field is always set, but the\r
-                                host only interprets it dependent on\r
-                                VRING_DESC_F_NEXT.\r
+  @param[in] BufferSize      Number of bytes to transmit or receive.\r
 \r
-  In *Indices:\r
+  @param[in] Flags           A bitmask of VRING_DESC_F_* flags. The caller\r
+                             computes this mask dependent on further buffers to\r
+                             append and transfer direction.\r
+                             VRING_DESC_F_INDIRECT is unsupported. The\r
+                             VRING_DESC.Next field is always set, but the host\r
+                             only interprets it dependent on VRING_DESC_F_NEXT.\r
 \r
-  @param [in] HeadIdx           The index identifying the head buffer (first\r
-                                buffer appended) belonging to this same\r
-                                request.\r
-\r
-  @param [in out] NextAvailIdx  On input, the index identifying the next\r
-                                descriptor available to carry the buffer. On\r
-                                output, incremented by one, modulo 2^16.\r
+  @param[in,out] Indices     Indices->HeadDescIdx is not accessed.\r
+                             On input, Indices->NextDescIdx identifies the next\r
+                             descriptor to carry the buffer. On output,\r
+                             Indices->NextDescIdx is incremented by one, modulo\r
+                             2^16.\r
 \r
 **/\r
 VOID\r
@@ -366,32 +295,31 @@ VirtioAppendDesc (
 {\r
   volatile VRING_DESC *Desc;\r
 \r
-  Desc        = &Ring->Desc[Indices->NextAvailIdx % Ring->QueueSize];\r
+  Desc        = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize];\r
   Desc->Addr  = BufferPhysAddr;\r
   Desc->Len   = BufferSize;\r
   Desc->Flags = Flags;\r
-  Ring->Avail.Ring[Indices->NextAvailIdx++ % Ring->QueueSize] =\r
-    Indices->HeadIdx % Ring->QueueSize;\r
-  Desc->Next  = Indices->NextAvailIdx % Ring->QueueSize;\r
+  Desc->Next  = Indices->NextDescIdx % 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
+  Notify the host about the descriptor chain just built, and wait until the\r
+  host processes it.\r
 \r
-  @param[in] PciIo        The target virtio PCI device to notify.\r
+  @param[in] VirtIo       The target virtio 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
+  @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
+  @param[in] Indices      Indices->NextDescIdx is not accessed.\r
+                          Indices->HeadDescIdx identifies the head descriptor\r
+                          of the descriptor chain.\r
 \r
 \r
-  @return              Error code from VirtioWrite() if it fails.\r
+  @return              Error code from VirtIo->SetQueueNotify() if it fails.\r
 \r
   @retval EFI_SUCCESS  Otherwise, the host processed all descriptors.\r
 \r
@@ -399,32 +327,39 @@ VirtioAppendDesc (
 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
+  IN     VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
+  IN     UINT16                 VirtQueueId,\r
+  IN OUT VRING                  *Ring,\r
+  IN     DESC_INDICES           *Indices\r
   )\r
 {\r
+  UINT16     NextAvailIdx;\r
   EFI_STATUS Status;\r
   UINTN      PollPeriodUsecs;\r
 \r
+  //\r
+  // virtio-0.9.5, 2.4.1.2 Updating the Available Ring\r
+  //\r
+  // It is not exactly clear from the wording of the virtio-0.9.5\r
+  // specification, but each entry in the Available Ring references only the\r
+  // head descriptor of any given descriptor chain.\r
+  //\r
+  NextAvailIdx = *Ring->Avail.Idx;\r
+  Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] =\r
+    Indices->HeadDescIdx % Ring->QueueSize;\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
+  *Ring->Avail.Idx = 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
+  Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -439,7 +374,7 @@ VirtioFlush (
   //\r
   PollPeriodUsecs = 1;\r
   MemoryFence();\r
-  while (*Ring->Used.Idx != Indices->NextAvailIdx) {\r
+  while (*Ring->Used.Idx != NextAvailIdx) {\r
     gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay\r
 \r
     if (PollPeriodUsecs < 1024) {\r
@@ -448,5 +383,6 @@ VirtioFlush (
     MemoryFence();\r
   }\r
 \r
+  MemoryFence();\r
   return EFI_SUCCESS;\r
 }\r