]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/VirtioNetDxe: alloc RxBuf using AllocateSharedPages()
authorBrijesh Singh <brijesh.singh@amd.com>
Thu, 14 Sep 2017 21:22:42 +0000 (16:22 -0500)
committerLaszlo Ersek <lersek@redhat.com>
Thu, 14 Sep 2017 21:54:07 +0000 (23:54 +0200)
When device is behind the IOMMU, VirtioNetDxe is required to use the
device address in bus master operations. RxBuf is allocated using
AllocatePool() which returns the system physical address.

The patch uses VIRTIO_DEVICE_PROTOCOL.AllocateSharedPages() to allocate
the RxBuf and map with VirtioMapAllBytesInSharedBuffer() so that we can
obtain the device address for RxBuf.

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/SnpReceive.c
OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
OvmfPkg/VirtioNetDxe/TechNotes.txt
OvmfPkg/VirtioNetDxe/VirtioNet.h

index 8eabdbff6f5e268102f7edcb9765334a55c5654c..b739875d4c0162ee2cbc79e1829c14204638ac01 100644 (file)
@@ -242,8 +242,9 @@ VirtioNetInitTx (
   @param[in,out] Dev       The VNET_DEV driver instance about to enter the\r
                            EfiSimpleNetworkInitialized state.\r
 \r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate RX destination area.\r
-  @return                       Status codes from VIRTIO_CFG_WRITE().\r
+  @return                       Status codes from VIRTIO_CFG_WRITE() or\r
+                                VIRTIO_DEVICE_PROTOCOL.AllocateSharedPages or\r
+                                VirtioMapAllBytesInSharedBuffer().\r
   @retval EFI_SUCCESS           RX setup successful. The device is live and may\r
                                 already be writing to the receive area.\r
 */\r
@@ -255,13 +256,15 @@ VirtioNetInitRx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
-  EFI_STATUS Status;\r
-  UINTN      VirtioNetReqSize;\r
-  UINTN      RxBufSize;\r
-  UINT16     RxAlwaysPending;\r
-  UINTN      PktIdx;\r
-  UINT16     DescIdx;\r
-  UINT8      *RxPtr;\r
+  EFI_STATUS            Status;\r
+  UINTN                 VirtioNetReqSize;\r
+  UINTN                 RxBufSize;\r
+  UINT16                RxAlwaysPending;\r
+  UINTN                 PktIdx;\r
+  UINT16                DescIdx;\r
+  UINTN                 NumBytes;\r
+  EFI_PHYSICAL_ADDRESS  RxBufDeviceAddress;\r
+  VOID                  *RxBuffer;\r
 \r
   //\r
   // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on\r
@@ -286,11 +289,39 @@ VirtioNetInitRx (
   //\r
   RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);\r
 \r
-  Dev->RxBuf = AllocatePool (RxAlwaysPending * RxBufSize);\r
-  if (Dev->RxBuf == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+  //\r
+  // The RxBuf is shared between guest and hypervisor, use\r
+  // AllocateSharedPages() to allocate this memory region and map it with\r
+  // BusMasterCommonBuffer so that it can be accessed by both guest and\r
+  // hypervisor.\r
+  //\r
+  NumBytes = RxAlwaysPending * RxBufSize;\r
+  Dev->RxBufNrPages = EFI_SIZE_TO_PAGES (NumBytes);\r
+  Status = Dev->VirtIo->AllocateSharedPages (\r
+                          Dev->VirtIo,\r
+                          Dev->RxBufNrPages,\r
+                          &RxBuffer\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
+  ZeroMem (RxBuffer, NumBytes);\r
+\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             Dev->VirtIo,\r
+             VirtioOperationBusMasterCommonBuffer,\r
+             RxBuffer,\r
+             NumBytes,\r
+             &Dev->RxBufDeviceBase,\r
+             &Dev->RxBufMap\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeSharedBuffer;\r
+  }\r
+\r
+  Dev->RxBuf = RxBuffer;\r
+\r
   //\r
   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
   //\r
@@ -310,7 +341,7 @@ VirtioNetInitRx (
   // link each chain into (from) the available ring as well\r
   //\r
   DescIdx = 0;\r
-  RxPtr = Dev->RxBuf;\r
+  RxBufDeviceAddress = Dev->RxBufDeviceBase;\r
   for (PktIdx = 0; PktIdx < RxAlwaysPending; ++PktIdx) {\r
     //\r
     // virtio-0.9.5, 2.4.1.2 Updating the Available Ring\r
@@ -321,16 +352,16 @@ VirtioNetInitRx (
     //\r
     // virtio-0.9.5, 2.4.1.1 Placing Buffers into the Descriptor Table\r
     //\r
-    Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;\r
+    Dev->RxRing.Desc[DescIdx].Addr  = RxBufDeviceAddress;\r
     Dev->RxRing.Desc[DescIdx].Len   = (UINT32) VirtioNetReqSize;\r
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;\r
     Dev->RxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);\r
-    RxPtr += Dev->RxRing.Desc[DescIdx++].Len;\r
+    RxBufDeviceAddress += Dev->RxRing.Desc[DescIdx++].Len;\r
 \r
-    Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;\r
+    Dev->RxRing.Desc[DescIdx].Addr  = RxBufDeviceAddress;\r
     Dev->RxRing.Desc[DescIdx].Len   = (UINT32) (RxBufSize - VirtioNetReqSize);\r
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE;\r
-    RxPtr += Dev->RxRing.Desc[DescIdx++].Len;\r
+    RxBufDeviceAddress += Dev->RxRing.Desc[DescIdx++].Len;\r
   }\r
 \r
   //\r
@@ -351,10 +382,21 @@ VirtioNetInitRx (
   Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);\r
   if (EFI_ERROR (Status)) {\r
     Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
-    FreePool (Dev->RxBuf);\r
+    goto UnmapSharedBuffer;\r
   }\r
 \r
   return Status;\r
+\r
+UnmapSharedBuffer:\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);\r
+\r
+FreeSharedBuffer:\r
+  Dev->VirtIo->FreeSharedPages (\r
+                 Dev->VirtIo,\r
+                 Dev->RxBufNrPages,\r
+                 RxBuffer\r
+                 );\r
+  return Status;\r
 }\r
 \r
 \r
index 99abd7ebe454dde610296f665b12cf3c7b1cd6a7..c42489636ea0b0d1c107c9e1c48fdaf127e2c511 100644 (file)
@@ -82,6 +82,7 @@ VirtioNetReceive (
   UINT8      *RxPtr;\r
   UINT16     AvailIdx;\r
   EFI_STATUS NotifyStatus;\r
+  UINTN      RxBufOffset;\r
 \r
   if (This == NULL || BufferSize == NULL || Buffer == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -143,7 +144,9 @@ VirtioNetReceive (
     *HeaderSize = Dev->Snm.MediaHeaderSize;\r
   }\r
 \r
-  RxPtr = (UINT8 *)(UINTN) Dev->RxRing.Desc[DescIdx + 1].Addr;\r
+  RxBufOffset = (UINTN)(Dev->RxRing.Desc[DescIdx + 1].Addr -\r
+                        Dev->RxBufDeviceBase);\r
+  RxPtr = Dev->RxBuf + RxBufOffset;\r
   CopyMem (Buffer, RxPtr, RxLen);\r
 \r
   if (DestAddr != NULL) {\r
index 57c7395848bd2d21c61abb0c0475783725cb05c5..ee4f9ed36ecdaee26fc7f29ab3e47862b837b893 100644 (file)
@@ -39,7 +39,12 @@ VirtioNetShutdownRx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
-  FreePool (Dev->RxBuf);\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);\r
+  Dev->VirtIo->FreeSharedPages (\r
+                 Dev->VirtIo,\r
+                 Dev->RxBufNrPages,\r
+                 Dev->RxBuf\r
+                 );\r
 }\r
 \r
 \r
index 37250b14a98cd09aa8a1fb52aa8c65beb2ad1b18..fedbaee07ec7b3b28d71b3d44f1c5e0b95116a99 100644 (file)
@@ -247,7 +247,7 @@ In VirtioNetInitRx, the guest allocates the fixed size Receive Destination
 Area, which accommodates all packets delivered asynchronously by the host. To\r
 each packet, a slice of this area is dedicated; each slice is further\r
 subdivided into virtio-net request header and network packet data. The\r
-(guest-physical) addresses of these sub-slices are denoted with A2, A3, A4 and\r
+(device-physical) addresses of these sub-slices are denoted with A2, A3, A4 and\r
 so on. Importantly, an even-subscript "A" always belongs to a virtio-net\r
 request header, while an odd-subscript "A" always belongs to a packet\r
 sub-slice.\r
index 6762fc9d1d6e831ef770374a7a6c27537b2efc42..995593f4b236bbdf69bed6455f173d506fcfa29f 100644 (file)
@@ -4,6 +4,7 @@
   Protocol instances for virtio-net devices.\r
 \r
   Copyright (C) 2013, 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
@@ -86,6 +87,9 @@ typedef struct {
                                                  // VirtioNetInitRing\r
   UINT8                       *RxBuf;            // VirtioNetInitRx\r
   UINT16                      RxLastUsed;        // VirtioNetInitRx\r
+  UINTN                       RxBufNrPages;      // VirtioNetInitRx\r
+  EFI_PHYSICAL_ADDRESS        RxBufDeviceBase;   // VirtioNetInitRx\r
+  VOID                        *RxBufMap;         // VirtioNetInitRx\r
 \r
   VRING                       TxRing;            // VirtioNetInitRing\r
   VOID                        *TxRingMap;        // VirtioRingMap and\r