]> 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 6cee014072e7ccd1121e9f5ad587151568b88afc..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
+  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
@@ -57,14 +58,15 @@ VirtioNetInitRing (
   //\r
   // step 4b -- allocate selected queue\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, Selector);\r
+  Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Selector);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);\r
+  Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
   // For each packet (RX and TX alike), we need two descriptors:\r
   // one for the virtio-net request header, and another one for the data\r
@@ -72,19 +74,38 @@ VirtioNetInitRing (
   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
 \r
+  //\r
+  // Additional steps for MMIO: align the queue appropriately, and set the\r
+  // size. If anything fails from here on, we must release the ring resources.\r
+  //\r
+  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ReleaseQueue;\r
+  }\r
+\r
+  Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ReleaseQueue;\r
+  }\r
+\r
   //\r
   // step 4c -- report GPFN (guest-physical frame number) of queue\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,\r
-             (UINTN) Ring->Base >> EFI_PAGE_SHIFT);\r
+  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, Ring, 0);\r
   if (EFI_ERROR (Status)) {\r
-    VirtioRingUninit (Ring);\r
+    goto ReleaseQueue;\r
   }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ReleaseQueue:\r
+  VirtioRingUninit (Dev->VirtIo, Ring);\r
+\r
   return Status;\r
 }\r
 \r
@@ -118,6 +139,7 @@ VirtioNetInitTx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
+  UINTN TxSharedReqSize;\r
   UINTN PktIdx;\r
 \r
   Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,\r
@@ -129,6 +151,14 @@ VirtioNetInitTx (
     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
@@ -140,7 +170,7 @@ VirtioNetInitTx (
     // (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
@@ -154,8 +184,13 @@ VirtioNetInitTx (
   //\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
@@ -203,19 +238,28 @@ VirtioNetInitRx (
   )\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
+  //\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
-  RxBufSize = sizeof (VIRTIO_NET_REQ) +\r
+  RxBufSize = VirtioNetReqSize +\r
               (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);\r
 \r
   //\r
@@ -260,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
-    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].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
@@ -287,10 +330,9 @@ VirtioNetInitRx (
   // virtio-0.9.5, 2.4.1.4 Notifying the Device\r
   //\r
   MemoryFence ();\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_RX);\r
-\r
+  Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);\r
   if (EFI_ERROR (Status)) {\r
-    VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
+    Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
     FreePool (Dev->RxBuf);\r
   }\r
 \r
@@ -340,7 +382,7 @@ VirtioNetInitialize (
   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
@@ -366,13 +408,21 @@ VirtioNetInitialize (
   // virtio-0.9.5 spec, 2.2.1 Device Initialization Sequence.\r
   //\r
   NextDevStat = VSTAT_ACK;    // step 2 -- acknowledge device presence\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
   if (EFI_ERROR (Status)) {\r
     goto InitFailed;\r
   }\r
 \r
   NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
+  if (EFI_ERROR (Status)) {\r
+    goto DeviceFailed;\r
+  }\r
+\r
+  //\r
+  // Set Page Size - MMIO VirtIo Specific\r
+  //\r
+  Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);\r
   if (EFI_ERROR (Status)) {\r
     goto DeviceFailed;\r
   }\r
@@ -381,14 +431,28 @@ VirtioNetInitialize (
   // step 4a -- retrieve features. Note that we're past validating required\r
   // features in VirtioNetGetFeatures().\r
   //\r
-  Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);\r
+  Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);\r
   if (EFI_ERROR (Status)) {\r
     goto DeviceFailed;\r
   }\r
+\r
   ASSERT (Features & VIRTIO_NET_F_MAC);\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
@@ -405,17 +469,19 @@ VirtioNetInitialize (
   //\r
   // step 5 -- keep only the features we want\r
   //\r
-  Features &= VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS;\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 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
   // step 6 -- virtio-net initialization complete\r
   //\r
   NextDevStat |= VSTAT_DRIVER_OK;\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseTxRing;\r
   }\r
@@ -441,19 +507,19 @@ ReleaseTxAux:
   VirtioNetShutdownTx (Dev);\r
 \r
 AbortDevice:\r
-  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
 ReleaseTxRing:\r
-  VirtioRingUninit (&Dev->TxRing);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->TxRing);\r
 \r
 ReleaseRxRing:\r
-  VirtioRingUninit (&Dev->RxRing);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->RxRing);\r
 \r
 DeviceFailed:\r
   //\r
   // restore device status invariant for the EfiSimpleNetworkStarted state\r
   //\r
-  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
 InitFailed:\r
   gBS->RestoreTPL (OldTpl);\r