]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioNetDxe/SnpInitialize.c
OvmfPkg/Virtio: take RingBaseShift in SetQueueAddress()
[mirror_edk2.git] / OvmfPkg / VirtioNetDxe / SnpInitialize.c
index 4203fbd6c1a73a058312cc4fcb4318006518d3d3..0ecfe044a97735754eddd1e1a6025e6d24270f5f 100644 (file)
@@ -5,6 +5,7 @@
 \r
   Copyright (C) 2013, Red Hat, Inc.\r
   Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 \r
   Copyright (C) 2013, Red Hat, Inc.\r
   Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\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
 \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
@@ -73,7 +74,7 @@ VirtioNetInitRing (
   if (QueueSize < 2) {\r
     return EFI_UNSUPPORTED;\r
   }\r
   if (QueueSize < 2) {\r
     return EFI_UNSUPPORTED;\r
   }\r
-  Status = VirtioRingInit (QueueSize, Ring);\r
+  Status = VirtioRingInit (Dev->VirtIo, QueueSize, Ring);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -95,8 +96,7 @@ VirtioNetInitRing (
   //\r
   // step 4c -- report GPFN (guest-physical frame number) of queue\r
   //\r
   //\r
   // step 4c -- report GPFN (guest-physical frame number) of queue\r
   //\r
-  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,\r
-      (UINT32)(UINTN) Ring->Base >> EFI_PAGE_SHIFT);\r
+  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, Ring, 0);\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
@@ -104,7 +104,7 @@ VirtioNetInitRing (
   return EFI_SUCCESS;\r
 \r
 ReleaseQueue:\r
   return EFI_SUCCESS;\r
 \r
 ReleaseQueue:\r
-  VirtioRingUninit (Ring);\r
+  VirtioRingUninit (Dev->VirtIo, Ring);\r
 \r
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
@@ -139,6 +139,7 @@ VirtioNetInitTx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
+  UINTN TxSharedReqSize;\r
   UINTN PktIdx;\r
 \r
   Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,\r
   UINTN PktIdx;\r
 \r
   Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,\r
@@ -150,6 +151,14 @@ VirtioNetInitTx (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
     return EFI_OUT_OF_RESOURCES;\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
+\r
   for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) {\r
     UINT16 DescIdx;\r
 \r
   for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) {\r
     UINT16 DescIdx;\r
 \r
@@ -161,7 +170,7 @@ VirtioNetInitTx (
     // (unmodified by the host) virtio-net request header.\r
     //\r
     Dev->TxRing.Desc[DescIdx].Addr  = (UINTN) &Dev->TxSharedReq;\r
     // (unmodified by the host) virtio-net request header.\r
     //\r
     Dev->TxRing.Desc[DescIdx].Addr  = (UINTN) &Dev->TxSharedReq;\r
-    Dev->TxRing.Desc[DescIdx].Len   = sizeof Dev->TxSharedReq;\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
 \r
     Dev->TxRing.Desc[DescIdx].Flags = VRING_DESC_F_NEXT;\r
     Dev->TxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);\r
 \r
@@ -175,8 +184,13 @@ VirtioNetInitTx (
   //\r
   // virtio-0.9.5, Appendix C, Packet Transmission\r
   //\r
   //\r
   // virtio-0.9.5, Appendix C, Packet Transmission\r
   //\r
-  Dev->TxSharedReq.Flags   = 0;\r
-  Dev->TxSharedReq.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
 \r
   //\r
   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
 \r
   //\r
   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
@@ -224,19 +238,28 @@ VirtioNetInitRx (
   )\r
 {\r
   EFI_STATUS Status;\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
 \r
   UINTN      RxBufSize;\r
   UINT16     RxAlwaysPending;\r
   UINTN      PktIdx;\r
   UINT16     DescIdx;\r
   UINT8      *RxPtr;\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
+  VirtioNetReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ?\r
+                     sizeof (VIRTIO_NET_REQ) :\r
+                     sizeof (VIRTIO_1_0_NET_REQ);\r
+\r
   //\r
   // For each incoming packet we must supply two descriptors:\r
   // - the recipient for the virtio-net request header, plus\r
   // - the recipient for the network data (which consists of Ethernet header\r
   //   and Ethernet payload).\r
   //\r
   //\r
   // For each incoming packet we must supply two descriptors:\r
   // - the recipient for the virtio-net request header, plus\r
   // - the recipient for the network data (which consists of Ethernet header\r
   //   and Ethernet payload).\r
   //\r
-  RxBufSize = sizeof (VIRTIO_NET_REQ) +\r
+  RxBufSize = VirtioNetReqSize +\r
               (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);\r
 \r
   //\r
               (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);\r
 \r
   //\r
@@ -281,14 +304,13 @@ VirtioNetInitRx (
     // virtio-0.9.5, 2.4.1.1 Placing Buffers into the Descriptor Table\r
     //\r
     Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;\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].Len   = sizeof (VIRTIO_NET_REQ);\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
 \r
     Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;\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
 \r
     Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;\r
-    Dev->RxRing.Desc[DescIdx].Len   = (UINT32) (RxBufSize -\r
-                                                sizeof (VIRTIO_NET_REQ));\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
   }\r
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE;\r
     RxPtr += Dev->RxRing.Desc[DescIdx++].Len;\r
   }\r
@@ -360,7 +382,7 @@ VirtioNetInitialize (
   EFI_TPL    OldTpl;\r
   EFI_STATUS Status;\r
   UINT8      NextDevStat;\r
   EFI_TPL    OldTpl;\r
   EFI_STATUS Status;\r
   UINT8      NextDevStat;\r
-  UINT32     Features;\r
+  UINT64     Features;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -418,6 +440,19 @@ VirtioNetInitialize (
   ASSERT (Dev->Snm.MediaPresentSupported ==\r
     !!(Features & VIRTIO_NET_F_STATUS));\r
 \r
   ASSERT (Dev->Snm.MediaPresentSupported ==\r
     !!(Features & VIRTIO_NET_F_STATUS));\r
 \r
+  Features &= VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS | VIRTIO_F_VERSION_1;\r
+\r
+  //\r
+  // In virtio-1.0, feature negotiation is expected to complete before queue\r
+  // discovery, and the device can also reject the selected set of features.\r
+  //\r
+  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);\r
+    if (EFI_ERROR (Status)) {\r
+      goto DeviceFailed;\r
+    }\r
+  }\r
+\r
   //\r
   // step 4b, 4c -- allocate and report virtqueues\r
   //\r
   //\r
   // step 4b, 4c -- allocate and report virtqueues\r
   //\r
@@ -434,10 +469,12 @@ VirtioNetInitialize (
   //\r
   // step 5 -- keep only the features we want\r
   //\r
   //\r
   // step 5 -- keep only the features we want\r
   //\r
-  Features &= VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS;\r
-  Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
-  if (EFI_ERROR (Status)) {\r
-    goto ReleaseTxRing;\r
+  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Features &= ~(UINT64)VIRTIO_F_VERSION_1;\r
+    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReleaseTxRing;\r
+    }\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -473,10 +510,10 @@ AbortDevice:
   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
 ReleaseTxRing:\r
   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
 ReleaseTxRing:\r
-  VirtioRingUninit (&Dev->TxRing);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->TxRing);\r
 \r
 ReleaseRxRing:\r
 \r
 ReleaseRxRing:\r
-  VirtioRingUninit (&Dev->RxRing);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->RxRing);\r
 \r
 DeviceFailed:\r
   //\r
 \r
 DeviceFailed:\r
   //\r