]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Virtio10Dxe/Virtio10.c
BaseTools/Capsule: Do not support -o with --dump-info
[mirror_edk2.git] / OvmfPkg / Virtio10Dxe / Virtio10.c
index d7ea4432bcb696e1ffc3383ce2cc5a20f007427b..9ebb72c76bfdac65f2532b3caa4183d2c68d9881 100644 (file)
@@ -2,6 +2,7 @@
   A non-transitional driver for VirtIo 1.0 PCI devices.\r
 \r
   Copyright (C) 2016, Red Hat, Inc.\r
+  Copyright (C) 2017, AMD Inc, All rights reserved.<BR>\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
 #include <IndustryStandard/Pci.h>\r
 #include <IndustryStandard/Virtio.h>\r
 #include <Protocol/PciIo.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
 #include <Protocol/VirtioDevice.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/PciCapLib.h>\r
+#include <Library/PciCapPciIoLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/UefiLib.h>\r
 \r
@@ -182,48 +186,6 @@ GetBarType (
 }\r
 \r
 \r
-/**\r
-  Read a slice from PCI config space at the given offset, then advance the\r
-  offset.\r
-\r
-  @param [in]     PciIo   The EFI_PCI_IO_PROTOCOL instance that represents the\r
-                          device.\r
-\r
-  @param [in,out] Offset  On input, the offset in PCI config space to start\r
-                          reading from. On output, the offset of the first byte\r
-                          that was not read. On error, Offset is not modified.\r
-\r
-  @param [in]     Size    The number of bytes to read.\r
-\r
-  @param [out]    Buffer  On output, the bytes read from PCI config space are\r
-                          stored in this object.\r
-\r
-  @retval EFI_SUCCESS  Size bytes have been transferred from PCI config space\r
-                       (from Offset) to Buffer, and Offset has been incremented\r
-                       by Size.\r
-\r
-  @return              Error codes from PciIo->Pci.Read().\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-ReadConfigSpace (\r
-  IN     EFI_PCI_IO_PROTOCOL *PciIo,\r
-  IN OUT UINT32              *Offset,\r
-  IN     UINTN               Size,\r
-     OUT VOID                *Buffer\r
-  )\r
-{\r
-  EFI_STATUS Status;\r
-\r
-  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, *Offset, Size, Buffer);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-  *Offset += (UINT32)Size;\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
 /*\r
   Traverse the PCI capabilities list of a virtio-1.0 device, and capture the\r
   locations of the interesting virtio-1.0 register blocks.\r
@@ -237,57 +199,51 @@ ReadConfigSpace (
                                 will have been updated from the PCI\r
                                 capabilities found.\r
 \r
-  @param[in]     CapabilityPtr  The offset of the first capability in PCI\r
-                                config space, taken from the standard PCI\r
-                                device header.\r
-\r
   @retval EFI_SUCCESS  Traversal successful.\r
 \r
-  @return              Error codes from the ReadConfigSpace() and GetBarType()\r
-                       helper functions.\r
+  @return              Error codes from PciCapPciIoLib, PciCapLib, and the\r
+                       GetBarType() helper function.\r
 */\r
 STATIC\r
 EFI_STATUS\r
 ParseCapabilities (\r
-  IN OUT VIRTIO_1_0_DEV *Device,\r
-  IN     UINT8          CapabilityPtr\r
+  IN OUT VIRTIO_1_0_DEV *Device\r
   )\r
 {\r
-  UINT32              Offset;\r
-  VIRTIO_PCI_CAP_LINK CapLink;\r
-\r
-  for (Offset = CapabilityPtr & 0xFC;\r
-       Offset > 0;\r
-       Offset = CapLink.CapNext & 0xFC\r
-       ) {\r
-    EFI_STATUS        Status;\r
+  EFI_STATUS   Status;\r
+  PCI_CAP_DEV  *PciDevice;\r
+  PCI_CAP_LIST *CapList;\r
+  UINT16       VendorInstance;\r
+  PCI_CAP      *VendorCap;\r
+\r
+  Status = PciCapPciIoDeviceInit (Device->PciIo, &PciDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  Status = PciCapListInit (PciDevice, &CapList);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitPciDevice;\r
+  }\r
+\r
+  for (VendorInstance = 0;\r
+       !EFI_ERROR (PciCapListFindCap (CapList, PciCapNormal,\r
+                     EFI_PCI_CAPABILITY_ID_VENDOR, VendorInstance,\r
+                     &VendorCap));\r
+       VendorInstance++) {\r
     UINT8             CapLen;\r
     VIRTIO_PCI_CAP    VirtIoCap;\r
     VIRTIO_1_0_CONFIG *ParsedConfig;\r
 \r
-    //\r
-    // Read capability identifier and link to next capability.\r
-    //\r
-    Status = ReadConfigSpace (Device->PciIo, &Offset, sizeof CapLink,\r
-               &CapLink);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-    if (CapLink.CapId != 0x09) {\r
-      //\r
-      // Not a vendor-specific capability, move to the next one.\r
-      //\r
-      continue;\r
-    }\r
-\r
     //\r
     // Big enough to accommodate a VIRTIO_PCI_CAP structure?\r
     //\r
-    Status = ReadConfigSpace (Device->PciIo, &Offset, sizeof CapLen, &CapLen);\r
+    Status = PciCapRead (PciDevice, VendorCap,\r
+               OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length), &CapLen,\r
+               sizeof CapLen);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto UninitCapList;\r
     }\r
-    if (CapLen < sizeof CapLink + sizeof CapLen + sizeof VirtIoCap) {\r
+    if (CapLen < sizeof VirtIoCap) {\r
       //\r
       // Too small, move to next.\r
       //\r
@@ -297,11 +253,11 @@ ParseCapabilities (
     //\r
     // Read interesting part of capability.\r
     //\r
-    Status = ReadConfigSpace (Device->PciIo, &Offset, sizeof VirtIoCap,\r
-               &VirtIoCap);\r
+    Status = PciCapRead (PciDevice, VendorCap, 0, &VirtIoCap, sizeof VirtIoCap);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto UninitCapList;\r
     }\r
+\r
     switch (VirtIoCap.ConfigType) {\r
     case VIRTIO_PCI_CAP_COMMON_CFG:\r
       ParsedConfig = &Device->CommonConfig;\r
@@ -324,7 +280,7 @@ ParseCapabilities (
     //\r
     Status = GetBarType (Device->PciIo, VirtIoCap.Bar, &ParsedConfig->BarType);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto UninitCapList;\r
     }\r
     ParsedConfig->Bar    = VirtIoCap.Bar;\r
     ParsedConfig->Offset = VirtIoCap.Offset;\r
@@ -335,19 +291,18 @@ ParseCapabilities (
       // This capability has an additional field called NotifyOffsetMultiplier;\r
       // parse it too.\r
       //\r
-      if (CapLen < sizeof CapLink + sizeof CapLen + sizeof VirtIoCap +\r
-                   sizeof Device->NotifyOffsetMultiplier) {\r
+      if (CapLen < sizeof VirtIoCap + sizeof Device->NotifyOffsetMultiplier) {\r
         //\r
         // Too small, move to next.\r
         //\r
         continue;\r
       }\r
 \r
-      Status = ReadConfigSpace (Device->PciIo, &Offset,\r
-                 sizeof Device->NotifyOffsetMultiplier,\r
-                 &Device->NotifyOffsetMultiplier);\r
+      Status = PciCapRead (PciDevice, VendorCap, sizeof VirtIoCap,\r
+                 &Device->NotifyOffsetMultiplier,\r
+                 sizeof Device->NotifyOffsetMultiplier);\r
       if (EFI_ERROR (Status)) {\r
-        return Status;\r
+        goto UninitCapList;\r
       }\r
     }\r
 \r
@@ -357,7 +312,15 @@ ParseCapabilities (
     ParsedConfig->Exists = TRUE;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+UninitCapList:\r
+  PciCapListUninit (CapList);\r
+\r
+UninitPciDevice:\r
+  PciCapPciIoDeviceUninit (PciDevice);\r
+\r
+  return Status;\r
 }\r
 \r
 \r
@@ -487,7 +450,8 @@ EFI_STATUS
 EFIAPI\r
 Virtio10SetQueueAddress (\r
   IN VIRTIO_DEVICE_PROTOCOL  *This,\r
-  IN VRING                   *Ring\r
+  IN VRING                   *Ring,\r
+  IN UINT64                  RingBaseShift\r
   )\r
 {\r
   VIRTIO_1_0_DEV *Dev;\r
@@ -498,6 +462,7 @@ Virtio10SetQueueAddress (
   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
 \r
   Address = (UINTN)Ring->Desc;\r
+  Address += RingBaseShift;\r
   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,\r
              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),\r
              sizeof Address, &Address);\r
@@ -506,6 +471,7 @@ Virtio10SetQueueAddress (
   }\r
 \r
   Address = (UINTN)Ring->Avail.Flags;\r
+  Address += RingBaseShift;\r
   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,\r
              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),\r
              sizeof Address, &Address);\r
@@ -514,6 +480,7 @@ Virtio10SetQueueAddress (
   }\r
 \r
   Address = (UINTN)Ring->Used.Flags;\r
+  Address += RingBaseShift;\r
   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,\r
              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),\r
              sizeof Address, &Address);\r
@@ -772,6 +739,117 @@ Virtio10ReadDevice (
   return Status;\r
 }\r
 \r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Virtio10AllocateSharedPages (\r
+  IN     VIRTIO_DEVICE_PROTOCOL  *This,\r
+  IN     UINTN                   Pages,\r
+  IN OUT VOID                    **HostAddress\r
+  )\r
+{\r
+  VIRTIO_1_0_DEV *Dev;\r
+  EFI_STATUS     Status;\r
+\r
+  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
+\r
+  Status = Dev->PciIo->AllocateBuffer (\r
+                         Dev->PciIo,\r
+                         AllocateAnyPages,\r
+                         EfiBootServicesData,\r
+                         Pages,\r
+                         HostAddress,\r
+                         EFI_PCI_ATTRIBUTE_MEMORY_CACHED\r
+                         );\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Virtio10FreeSharedPages (\r
+  IN  VIRTIO_DEVICE_PROTOCOL  *This,\r
+  IN  UINTN                   Pages,\r
+  IN  VOID                    *HostAddress\r
+  )\r
+{\r
+  VIRTIO_1_0_DEV *Dev;\r
+\r
+  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
+\r
+  Dev->PciIo->FreeBuffer (\r
+                Dev->PciIo,\r
+                Pages,\r
+                HostAddress\r
+                );\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Virtio10MapSharedBuffer (\r
+  IN     VIRTIO_DEVICE_PROTOCOL  *This,\r
+  IN     VIRTIO_MAP_OPERATION    Operation,\r
+  IN     VOID                    *HostAddress,\r
+  IN OUT UINTN                   *NumberOfBytes,\r
+  OUT    EFI_PHYSICAL_ADDRESS    *DeviceAddress,\r
+  OUT    VOID                    **Mapping\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  VIRTIO_1_0_DEV                *Dev;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;\r
+\r
+  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
+\r
+  //\r
+  // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION\r
+  //\r
+  switch (Operation) {\r
+  case VirtioOperationBusMasterRead:\r
+    PciIoOperation = EfiPciIoOperationBusMasterRead;\r
+    break;\r
+  case VirtioOperationBusMasterWrite:\r
+    PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
+    break;\r
+  case VirtioOperationBusMasterCommonBuffer:\r
+    PciIoOperation = EfiPciIoOperationBusMasterCommonBuffer;\r
+    break;\r
+  default:\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = Dev->PciIo->Map (\r
+                         Dev->PciIo,\r
+                         PciIoOperation,\r
+                         HostAddress,\r
+                         NumberOfBytes,\r
+                         DeviceAddress,\r
+                         Mapping\r
+                         );\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Virtio10UnmapSharedBuffer (\r
+  IN  VIRTIO_DEVICE_PROTOCOL  *This,\r
+  IN  VOID                    *Mapping\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  VIRTIO_1_0_DEV  *Dev;\r
+\r
+  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
+\r
+  Status = Dev->PciIo->Unmap (\r
+                         Dev->PciIo,\r
+                         Mapping\r
+                         );\r
+\r
+  return Status;\r
+}\r
 \r
 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {\r
   VIRTIO_SPEC_REVISION (1, 0, 0),\r
@@ -788,7 +866,11 @@ STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {
   Virtio10GetDeviceStatus,\r
   Virtio10SetDeviceStatus,\r
   Virtio10WriteDevice,\r
-  Virtio10ReadDevice\r
+  Virtio10ReadDevice,\r
+  Virtio10AllocateSharedPages,\r
+  Virtio10FreeSharedPages,\r
+  Virtio10MapSharedBuffer,\r
+  Virtio10UnmapSharedBuffer\r
 };\r
 \r
 \r
@@ -894,7 +976,7 @@ Virtio10BindingStart (
 \r
   Device->VirtIo.SubSystemDeviceId = Pci.Hdr.DeviceId - 0x1040;\r
 \r
-  Status = ParseCapabilities (Device, Pci.Device.CapabilityPtr);\r
+  Status = ParseCapabilities (Device);\r
   if (EFI_ERROR (Status)) {\r
     goto ClosePciIo;\r
   }\r
@@ -906,7 +988,8 @@ Virtio10BindingStart (
     goto ClosePciIo;\r
   }\r
 \r
-  SetAttributes = EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
+  SetAttributes = (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |\r
+                   EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
   UpdateAttributes (&Device->CommonConfig, &SetAttributes);\r
   UpdateAttributes (&Device->NotifyConfig, &SetAttributes);\r
   UpdateAttributes (&Device->SpecificConfig, &SetAttributes);\r