]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioNetDxe/SnpInitialize.c
OvmfPkg/VirtioLib: take VirtIo instance in VirtioRingInit/VirtioRingUninit
[mirror_edk2.git] / OvmfPkg / VirtioNetDxe / SnpInitialize.c
index 39282d9a4ac3c09bc4236356d4da625c9450e008..6d9b81a9f9399e08c73b13f7d204c2d77d2ab472 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
@@ -57,14 +58,15 @@ VirtioNetInitRing (
   //\r
   // step 4b -- allocate selected queue\r
   //\r
   //\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
   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
   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
   //\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
   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
   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
   //\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);\r
   if (EFI_ERROR (Status)) {\r
   if (EFI_ERROR (Status)) {\r
-    VirtioRingUninit (Ring);\r
+    goto ReleaseQueue;\r
   }\r
   }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ReleaseQueue:\r
+  VirtioRingUninit (Dev->VirtIo, Ring);\r
+\r
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
 \r
@@ -118,9 +139,11 @@ VirtioNetInitTx (
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
   IN OUT VNET_DEV *Dev\r
   )\r
 {\r
+  UINTN TxSharedReqSize;\r
   UINTN PktIdx;\r
 \r
   UINTN PktIdx;\r
 \r
-  Dev->TxMaxPending = MIN (Dev->TxRing.QueueSize / 2, VNET_MAX_PENDING);\r
+  Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,\r
+                                 VNET_MAX_PENDING);\r
   Dev->TxCurPending = 0;\r
   Dev->TxFreeStack  = AllocatePool (Dev->TxMaxPending *\r
                         sizeof *Dev->TxFreeStack);\r
   Dev->TxCurPending = 0;\r
   Dev->TxFreeStack  = AllocatePool (Dev->TxMaxPending *\r
                         sizeof *Dev->TxFreeStack);\r
@@ -128,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
@@ -139,9 +170,9 @@ 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].Flags = VRING_DESC_F_NEXT;\r
-    Dev->TxRing.Desc[DescIdx].Next  = DescIdx + 1;\r
+    Dev->TxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);\r
 \r
     //\r
     // The second descriptor of each pending TX packet is updated on the fly,\r
 \r
     //\r
     // The second descriptor of each pending TX packet is updated on the fly,\r
@@ -153,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
@@ -202,26 +238,35 @@ 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
   // Limit the number of pending RX packets if the queue is big. The division\r
   // by two is due to the above "two descriptors per packet" trait.\r
   //\r
               (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);\r
 \r
   //\r
   // Limit the number of pending RX packets if the queue is big. The division\r
   // by two is due to the above "two descriptors per packet" trait.\r
   //\r
-  RxAlwaysPending = MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);\r
+  RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);\r
 \r
   Dev->RxBuf = AllocatePool (RxAlwaysPending * RxBufSize);\r
   if (Dev->RxBuf == NULL) {\r
 \r
   Dev->RxBuf = AllocatePool (RxAlwaysPending * RxBufSize);\r
   if (Dev->RxBuf == NULL) {\r
@@ -259,13 +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].Flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;\r
-    Dev->RxRing.Desc[DescIdx].Next  = DescIdx + 1;\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
     RxPtr += Dev->RxRing.Desc[DescIdx++].Len;\r
 \r
     Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;\r
-    Dev->RxRing.Desc[DescIdx].Len   = RxBufSize - 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
@@ -285,10 +330,9 @@ VirtioNetInitRx (
   // virtio-0.9.5, 2.4.1.4 Notifying the Device\r
   //\r
   MemoryFence ();\r
   // 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
   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
     FreePool (Dev->RxBuf);\r
   }\r
 \r
@@ -338,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
@@ -364,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
   // 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
   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
   if (EFI_ERROR (Status)) {\r
     goto DeviceFailed;\r
   }\r
@@ -379,14 +431,28 @@ VirtioNetInitialize (
   // step 4a -- retrieve features. Note that we're past validating required\r
   // features in VirtioNetGetFeatures().\r
   //\r
   // 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
   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
   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
   //\r
   // step 4b, 4c -- allocate and report virtqueues\r
   //\r
@@ -403,17 +469,19 @@ 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 = 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
   }\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
   if (EFI_ERROR (Status)) {\r
     goto ReleaseTxRing;\r
   }\r
@@ -439,19 +507,19 @@ ReleaseTxAux:
   VirtioNetShutdownTx (Dev);\r
 \r
 AbortDevice:\r
   VirtioNetShutdownTx (Dev);\r
 \r
 AbortDevice:\r
-  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
 ReleaseTxRing:\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
   // restore device status invariant for the EfiSimpleNetworkStarted state\r
   //\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
 \r
 InitFailed:\r
   gBS->RestoreTPL (OldTpl);\r