\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
the network device.\r
@param[out] Ring The virtio-ring inside the VNET_DEV structure,\r
corresponding to Selector.\r
+ @param[out] Mapping A resulting token to pass to VirtioNetUninitRing()\r
\r
@retval EFI_UNSUPPORTED The queue size reported by the virtio-net device is\r
too small.\r
@return Status codes from VIRTIO_CFG_WRITE(),\r
- VIRTIO_CFG_READ() and VirtioRingInit().\r
+ VIRTIO_CFG_READ(), VirtioRingInit() and\r
+ VirtioRingMap().\r
@retval EFI_SUCCESS Ring initialized.\r
*/\r
\r
VirtioNetInitRing (\r
IN OUT VNET_DEV *Dev,\r
IN UINT16 Selector,\r
- OUT VRING *Ring\r
+ OUT VRING *Ring,\r
+ OUT VOID **Mapping\r
)\r
{\r
EFI_STATUS Status;\r
UINT16 QueueSize;\r
+ UINT64 RingBaseShift;\r
+ VOID *MapInfo;\r
\r
//\r
// step 4b -- allocate selected queue\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
+ //\r
+ // If anything fails from here on, we must release the ring resources.\r
+ //\r
+ Status = VirtioRingMap (Dev->VirtIo, Ring, &RingBaseShift, &MapInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ReleaseQueue;\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
+ // size. If anything fails from here on, we must unmap the ring resources.\r
//\r
Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);\r
if (EFI_ERROR (Status)) {\r
- goto ReleaseQueue;\r
+ goto UnmapQueue;\r
}\r
\r
Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);\r
if (EFI_ERROR (Status)) {\r
- goto ReleaseQueue;\r
+ goto UnmapQueue;\r
}\r
\r
//\r
// step 4c -- report GPFN (guest-physical frame number) of queue\r
//\r
- Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, Ring);\r
+ Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, Ring, RingBaseShift);\r
if (EFI_ERROR (Status)) {\r
- goto ReleaseQueue;\r
+ goto UnmapQueue;\r
}\r
\r
+ *Mapping = MapInfo;\r
+\r
return EFI_SUCCESS;\r
\r
+UnmapQueue:\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, MapInfo);\r
+\r
ReleaseQueue:\r
- VirtioRingUninit (Ring);\r
+ VirtioRingUninit (Dev->VirtIo, Ring);\r
\r
return Status;\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
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
// (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
//\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
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
// 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
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
- Status = VirtioNetInitRing (Dev, VIRTIO_NET_Q_RX, &Dev->RxRing);\r
+ Status = VirtioNetInitRing (\r
+ Dev,\r
+ VIRTIO_NET_Q_RX,\r
+ &Dev->RxRing,\r
+ &Dev->RxRingMap\r
+ );\r
if (EFI_ERROR (Status)) {\r
goto DeviceFailed;\r
}\r
\r
- Status = VirtioNetInitRing (Dev, VIRTIO_NET_Q_TX, &Dev->TxRing);\r
+ Status = VirtioNetInitRing (\r
+ Dev,\r
+ VIRTIO_NET_Q_TX,\r
+ &Dev->TxRing,\r
+ &Dev->TxRingMap\r
+ );\r
if (EFI_ERROR (Status)) {\r
goto ReleaseRxRing;\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
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
\r
ReleaseTxRing:\r
- VirtioRingUninit (&Dev->TxRing);\r
+ VirtioNetUninitRing (Dev, &Dev->TxRing, Dev->TxRingMap);\r
\r
ReleaseRxRing:\r
- VirtioRingUninit (&Dev->RxRing);\r
+ VirtioNetUninitRing (Dev, &Dev->RxRing, Dev->RxRingMap);\r
\r
DeviceFailed:\r
//\r