]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/VirtioNetDxe: dynamically alloc transmit header
authorBrijesh Singh <brijesh.singh@amd.com>
Thu, 14 Sep 2017 21:22:43 +0000 (16:22 -0500)
committerLaszlo Ersek <lersek@redhat.com>
Thu, 14 Sep 2017 21:54:10 +0000 (23:54 +0200)
Each network packet is submitted for transmission by pushing the head
descriptor of a two-part descriptor chain to the Available Ring of the
TX queue. VirtioNetInitTx() sets up the the descriptor chains for all
queueable packets in advance, and points all the head descriptors to the
same shared, never modified, VIRTIO_1_0_NET_REQ header object (or its
initial VIRTIO_NET_REQ sub-object, dependent on virtio version).
VirtioNetInitTx() currently uses the header object's system physical
address for populating the head descriptors.

When device is behind the IOMMU, VirtioNet driver is required to provide
the device address of VIRTIO_1_0_NET_REQ header. In this patch we
dynamically allocate the header using AllocateSharedPages() and map with
BusMasterCommonBuffer so that header can be accessed by both processor
and the device.

We map the header object for CommonBuffer operation because, in order to
stick with the current code order, we populate the head descriptors with
the header's device address first, and fill in the header itself second.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
OvmfPkg/VirtioNetDxe/SnpInitialize.c
OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
OvmfPkg/VirtioNetDxe/VirtioNet.h

index b739875d4c0162ee2cbc79e1829c14204638ac01..9621f936d2cba243a9e4aad8ad18299ba999d937 100644 (file)
@@ -18,6 +18,7 @@
 **/\r
 \r
 #include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 \r
@@ -147,6 +148,9 @@ ReleaseQueue:
 \r
   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the stack to track the heads\r
                                 of free descriptor chains.\r
+  @return                       Status codes from VIRTIO_DEVICE_PROTOCOL.\r
+                                AllocateSharedPages() or\r
+                                VirtioMapAllBytesInSharedBuffer()\r
   @retval EFI_SUCCESS           TX setup successful.\r
 */\r
 \r
@@ -157,8 +161,11 @@ VirtioNetInitTx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
-  UINTN TxSharedReqSize;\r
-  UINTN PktIdx;\r
+  UINTN                 TxSharedReqSize;\r
+  UINTN                 PktIdx;\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;\r
+  VOID                  *TxSharedReqBuffer;\r
 \r
   Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,\r
                                  VNET_MAX_PENDING);\r
@@ -169,13 +176,43 @@ VirtioNetInitTx (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  //\r
+  // Allocate TxSharedReq header and map with BusMasterCommonBuffer so that it\r
+  // can be accessed equally by both processor and device.\r
+  //\r
+  Status = Dev->VirtIo->AllocateSharedPages (\r
+                          Dev->VirtIo,\r
+                          EFI_SIZE_TO_PAGES (sizeof *Dev->TxSharedReq),\r
+                          &TxSharedReqBuffer\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeTxFreeStack;\r
+  }\r
+\r
+  ZeroMem (TxSharedReqBuffer, sizeof *Dev->TxSharedReq);\r
+\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             Dev->VirtIo,\r
+             VirtioOperationBusMasterCommonBuffer,\r
+             TxSharedReqBuffer,\r
+             sizeof *(Dev->TxSharedReq),\r
+             &DeviceAddress,\r
+             &Dev->TxSharedReqMap\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeTxSharedReqBuffer;\r
+  }\r
+\r
+  Dev->TxSharedReq = TxSharedReqBuffer;\r
+\r
+\r
   //\r
   // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on\r
   // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate.\r
   //\r
   TxSharedReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ?\r
-                    sizeof Dev->TxSharedReq.V0_9_5 :\r
-                    sizeof Dev->TxSharedReq;\r
+                    sizeof (Dev->TxSharedReq->V0_9_5) :\r
+                    sizeof *Dev->TxSharedReq;\r
 \r
   for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) {\r
     UINT16 DescIdx;\r
@@ -187,7 +224,7 @@ VirtioNetInitTx (
     // For each possibly pending packet, lay out the descriptor for the common\r
     // (unmodified by the host) virtio-net request header.\r
     //\r
-    Dev->TxRing.Desc[DescIdx].Addr  = (UINTN) &Dev->TxSharedReq;\r
+    Dev->TxRing.Desc[DescIdx].Addr  = DeviceAddress;\r
     Dev->TxRing.Desc[DescIdx].Len   = (UINT32) TxSharedReqSize;\r
     Dev->TxRing.Desc[DescIdx].Flags = VRING_DESC_F_NEXT;\r
     Dev->TxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);\r
@@ -202,13 +239,13 @@ VirtioNetInitTx (
   //\r
   // virtio-0.9.5, Appendix C, Packet Transmission\r
   //\r
-  Dev->TxSharedReq.V0_9_5.Flags   = 0;\r
-  Dev->TxSharedReq.V0_9_5.GsoType = VIRTIO_NET_HDR_GSO_NONE;\r
+  Dev->TxSharedReq->V0_9_5.Flags   = 0;\r
+  Dev->TxSharedReq->V0_9_5.GsoType = VIRTIO_NET_HDR_GSO_NONE;\r
 \r
   //\r
   // For VirtIo 1.0 only -- the field exists, but it is unused\r
   //\r
-  Dev->TxSharedReq.NumBuffers = 0;\r
+  Dev->TxSharedReq->NumBuffers = 0;\r
 \r
   //\r
   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
@@ -223,6 +260,17 @@ VirtioNetInitTx (
   *Dev->TxRing.Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;\r
 \r
   return EFI_SUCCESS;\r
+\r
+FreeTxSharedReqBuffer:\r
+  Dev->VirtIo->FreeSharedPages (\r
+                 Dev->VirtIo,\r
+                 EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),\r
+                 TxSharedReqBuffer\r
+                 );\r
+FreeTxFreeStack:\r
+  FreePool (Dev->TxFreeStack);\r
+\r
+  return Status;\r
 }\r
 \r
 \r
index ee4f9ed36ecdaee26fc7f29ab3e47862b837b893..2fce8142d554d7849715df88528c298707ca423c 100644 (file)
@@ -54,6 +54,13 @@ VirtioNetShutdownTx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxSharedReqMap);\r
+  Dev->VirtIo->FreeSharedPages (\r
+                 Dev->VirtIo,\r
+                 EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),\r
+                 Dev->TxSharedReq\r
+                 );\r
+\r
   FreePool (Dev->TxFreeStack);\r
 }\r
 \r
index 995593f4b236bbdf69bed6455f173d506fcfa29f..027f75993e8e2f51120526b95d0bb622048fc474 100644 (file)
@@ -97,7 +97,8 @@ typedef struct {
   UINT16                      TxMaxPending;      // VirtioNetInitTx\r
   UINT16                      TxCurPending;      // VirtioNetInitTx\r
   UINT16                      *TxFreeStack;      // VirtioNetInitTx\r
-  VIRTIO_1_0_NET_REQ          TxSharedReq;       // VirtioNetInitTx\r
+  VIRTIO_1_0_NET_REQ          *TxSharedReq;      // VirtioNetInitTx\r
+  VOID                        *TxSharedReqMap;   // VirtioNetInitTx\r
   UINT16                      TxLastUsed;        // VirtioNetInitTx\r
 } VNET_DEV;\r
 \r