diff mbox

[edk2,wave,3,v2,14/17] OvmfPkg: VirtioNetDxe: adapt virtio-net packet header size to virtio-1.0

Message ID 1459946427-15771-15-git-send-email-lersek@redhat.com
State New
Headers show

Commit Message

Laszlo Ersek April 6, 2016, 12:40 p.m. UTC
In virtio-0.9.5, the size of the virtio-net packet header depends on
whether the VIRTIO_NET_F_MRG_RXBUF feature is negotiated -- the
"num_buffers" field is only appended to the header if the feature is
negotiated.

Since we never negotiate this feature, VirtioNetDxe never allocates room
for the "num_buffers" field.

With virtio-1.0, the "num_buffers" field is always there (although it
doesn't carry useful information without VIRTIO_NET_F_MRG_RXBUF). Adapt
the buffers that depend on the virtio-net header size (otherwise we have
skewed / truncated packets).

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>

Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>

---

Notes:
    v2:
    - rename the "Legacy" field in VIRTIO_1_0_NET_REQ to "V0_9_5" [Jordan]
    - no need to include <IndustryStandard/Virtio10Net.h> explicitly,
      <IndustryStandard/VirtioNet.h> exposes all versions [Jordan]

 OvmfPkg/VirtioNetDxe/VirtioNet.h     |  2 +-
 OvmfPkg/VirtioNetDxe/SnpInitialize.c | 36 ++++++++++++++++----
 2 files changed, 30 insertions(+), 8 deletions(-)

-- 
1.8.3.1


_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox

Patch

diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h
index 2d3f3d87eb11..710859bc6115 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.h
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h
@@ -85,15 +85,15 @@  typedef struct {
   UINT8                       *RxBuf;            // VirtioNetInitRx
   UINT16                      RxLastUsed;        // VirtioNetInitRx
 
   VRING                       TxRing;            // VirtioNetInitRing
   UINT16                      TxMaxPending;      // VirtioNetInitTx
   UINT16                      TxCurPending;      // VirtioNetInitTx
   UINT16                      *TxFreeStack;      // VirtioNetInitTx
-  VIRTIO_NET_REQ              TxSharedReq;       // VirtioNetInitTx
+  VIRTIO_1_0_NET_REQ          TxSharedReq;       // VirtioNetInitTx
   UINT16                      TxLastUsed;        // VirtioNetInitTx
 } VNET_DEV;
 
 
 //
 // In order to avoid duplication of interface documentation, please find all
 // leading comments near the respective function / variable definitions (not
diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
index 38012a0df8d6..430670a980f2 100644
--- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c
+++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
@@ -134,52 +134,66 @@  ReleaseQueue:
 STATIC
 EFI_STATUS
 EFIAPI
 VirtioNetInitTx (
   IN OUT VNET_DEV *Dev
   )
 {
+  UINTN TxSharedReqSize;
   UINTN PktIdx;
 
   Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,
                                  VNET_MAX_PENDING);
   Dev->TxCurPending = 0;
   Dev->TxFreeStack  = AllocatePool (Dev->TxMaxPending *
                         sizeof *Dev->TxFreeStack);
   if (Dev->TxFreeStack == NULL) {
     return EFI_OUT_OF_RESOURCES;
   }
 
+  //
+  // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on
+  // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate.
+  //
+  TxSharedReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ?
+                    sizeof Dev->TxSharedReq.V0_9_5 :
+                    sizeof Dev->TxSharedReq;
+
   for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) {
     UINT16 DescIdx;
 
     DescIdx = (UINT16) (2 * PktIdx);
     Dev->TxFreeStack[PktIdx] = DescIdx;
 
     //
     // For each possibly pending packet, lay out the descriptor for the common
     // (unmodified by the host) virtio-net request header.
     //
     Dev->TxRing.Desc[DescIdx].Addr  = (UINTN) &Dev->TxSharedReq;
-    Dev->TxRing.Desc[DescIdx].Len   = sizeof Dev->TxSharedReq;
+    Dev->TxRing.Desc[DescIdx].Len   = (UINT32) TxSharedReqSize;
     Dev->TxRing.Desc[DescIdx].Flags = VRING_DESC_F_NEXT;
     Dev->TxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);
 
     //
     // The second descriptor of each pending TX packet is updated on the fly,
     // but it always terminates the descriptor chain of the packet.
     //
     Dev->TxRing.Desc[DescIdx + 1].Flags = 0;
   }
 
   //
   // virtio-0.9.5, Appendix C, Packet Transmission
   //
-  Dev->TxSharedReq.Flags   = 0;
-  Dev->TxSharedReq.GsoType = VIRTIO_NET_HDR_GSO_NONE;
+  Dev->TxSharedReq.V0_9_5.Flags   = 0;
+  Dev->TxSharedReq.V0_9_5.GsoType = VIRTIO_NET_HDR_GSO_NONE;
+
+  //
+  // For VirtIo 1.0 only -- the field exists, but it is unused
+  //
+  Dev->TxSharedReq.NumBuffers = 0;
 
   //
   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
   //
   MemoryFence ();
   Dev->TxLastUsed = *Dev->TxRing.Used.Idx;
   ASSERT (Dev->TxLastUsed == 0);
@@ -219,27 +233,36 @@  STATIC
 EFI_STATUS
 EFIAPI
 VirtioNetInitRx (
   IN OUT VNET_DEV *Dev
   )
 {
   EFI_STATUS Status;
+  UINTN      VirtioNetReqSize;
   UINTN      RxBufSize;
   UINT16     RxAlwaysPending;
   UINTN      PktIdx;
   UINT16     DescIdx;
   UINT8      *RxPtr;
 
   //
+  // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on
+  // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate.
+  //
+  VirtioNetReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ?
+                     sizeof (VIRTIO_NET_REQ) :
+                     sizeof (VIRTIO_1_0_NET_REQ);
+
+  //
   // For each incoming packet we must supply two descriptors:
   // - the recipient for the virtio-net request header, plus
   // - the recipient for the network data (which consists of Ethernet header
   //   and Ethernet payload).
   //
-  RxBufSize = sizeof (VIRTIO_NET_REQ) +
+  RxBufSize = VirtioNetReqSize +
               (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);
 
   //
   // Limit the number of pending RX packets if the queue is big. The division
   // by two is due to the above "two descriptors per packet" trait.
   //
   RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);
@@ -276,22 +299,21 @@  VirtioNetInitRx (
     //
     Dev->RxRing.Avail.Ring[PktIdx] = DescIdx;
 
     //
     // virtio-0.9.5, 2.4.1.1 Placing Buffers into the Descriptor Table
     //
     Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;
-    Dev->RxRing.Desc[DescIdx].Len   = sizeof (VIRTIO_NET_REQ);
+    Dev->RxRing.Desc[DescIdx].Len   = (UINT32) VirtioNetReqSize;
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;
     Dev->RxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);
     RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
 
     Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;
-    Dev->RxRing.Desc[DescIdx].Len   = (UINT32) (RxBufSize -
-                                                sizeof (VIRTIO_NET_REQ));
+    Dev->RxRing.Desc[DescIdx].Len   = (UINT32) (RxBufSize - VirtioNetReqSize);
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE;
     RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
   }
 
   //
   // virtio-0.9.5, 2.4.1.3 Updating the Index Field
   //