--- /dev/null
+/** @file\r
+\r
+ Implementation of the SNP.GetStatus() function and its private helpers if\r
+ any.\r
+\r
+ Copyright (C) 2013, Red Hat, Inc.\r
+ Copyright (c) 2006 - 2010, Intel Corporation. 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
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include "VirtioNet.h"\r
+\r
+/**\r
+ Reads the current interrupt status and recycled transmit buffer status from\r
+ a network interface.\r
+\r
+ @param This The protocol instance pointer.\r
+ @param InterruptStatus A pointer to the bit mask of the currently active\r
+ interrupts If this is NULL, the interrupt status will\r
+ not be read from the device. If this is not NULL, the\r
+ interrupt status will be read from the device. When\r
+ the interrupt status is read, it will also be\r
+ cleared. Clearing the transmit interrupt does not\r
+ empty the recycled transmit buffer array.\r
+ @param TxBuf Recycled transmit buffer address. The network\r
+ interface will not transmit if its internal recycled\r
+ transmit buffer array is full. Reading the transmit\r
+ buffer does not clear the transmit interrupt. If this\r
+ is NULL, then the transmit buffer status will not be\r
+ read. If there are no transmit buffers to recycle and\r
+ TxBuf is not NULL, * TxBuf will be set to NULL.\r
+\r
+ @retval EFI_SUCCESS The status of the network interface was\r
+ retrieved.\r
+ @retval EFI_NOT_STARTED The network interface has not been started.\r
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an\r
+ unsupported value.\r
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network\r
+ interface.\r
+ @retval EFI_UNSUPPORTED This function is not supported by the network\r
+ interface.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioNetGetStatus (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r
+ OUT UINT32 *InterruptStatus OPTIONAL,\r
+ OUT VOID **TxBuf OPTIONAL\r
+ )\r
+{\r
+ VNET_DEV *Dev;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ UINT16 RxCurUsed;\r
+ UINT16 TxCurUsed;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = VIRTIO_NET_FROM_SNP (This);\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ switch (Dev->Snm.State) {\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ case EfiSimpleNetworkStarted:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ //\r
+ // update link status\r
+ //\r
+ if (Dev->Snm.MediaPresentSupported) {\r
+ UINT16 LinkStatus;\r
+\r
+ Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ Dev->Snm.MediaPresent = !!(LinkStatus & VIRTIO_NET_S_LINK_UP);\r
+ }\r
+\r
+ //\r
+ // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
+ //\r
+ MemoryFence ();\r
+ RxCurUsed = *Dev->RxRing.Used.Idx;\r
+ TxCurUsed = *Dev->TxRing.Used.Idx;\r
+\r
+ if (InterruptStatus != NULL) {\r
+ //\r
+ // report the receive interrupt if there is data available for reception,\r
+ // report the transmit interrupt if we have transmitted at least one buffer\r
+ //\r
+ *InterruptStatus = 0;\r
+ if (Dev->RxLastUsed != RxCurUsed) {\r
+ *InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
+ }\r
+ if (Dev->TxLastUsed != TxCurUsed) {\r
+ ASSERT (Dev->TxCurPending > 0);\r
+ *InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
+ }\r
+ }\r
+\r
+ if (TxBuf != NULL) {\r
+ if (Dev->TxLastUsed == TxCurUsed) {\r
+ *TxBuf = NULL;\r
+ }\r
+ else {\r
+ UINT16 UsedElemIdx;\r
+ UINT32 DescIdx;\r
+\r
+ //\r
+ // fetch the first descriptor among those that the hypervisor reports\r
+ // completed\r
+ //\r
+ ASSERT (Dev->TxCurPending > 0);\r
+ ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);\r
+\r
+ UsedElemIdx = Dev->TxLastUsed++ % Dev->TxRing.QueueSize;\r
+ DescIdx = Dev->TxRing.Used.UsedElem[UsedElemIdx].Id;\r
+ ASSERT (DescIdx < 2 * Dev->TxMaxPending - 1);\r
+\r
+ //\r
+ // report buffer address to caller that has been enqueued by caller\r
+ //\r
+ *TxBuf = (VOID *) Dev->TxRing.Desc[DescIdx + 1].Addr;\r
+\r
+ //\r
+ // now this descriptor can be used again to enqueue a transmit buffer\r
+ //\r
+ Dev->TxFreeStack[--Dev->TxCurPending] = (UINT16) DescIdx;\r
+ }\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+Exit:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Implementation of the SNP.Transmit() function and its private helpers if any.\r
+\r
+ Copyright (C) 2013, Red Hat, Inc.\r
+ Copyright (c) 2006 - 2010, Intel Corporation. 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
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include "VirtioNet.h"\r
+\r
+/**\r
+ Places a packet in the transmit queue of a network interface.\r
+\r
+ @param This The protocol instance pointer.\r
+ @param HeaderSize The size, in bytes, of the media header to be filled in by\r
+ the Transmit() function. If HeaderSize is non-zero, then\r
+ it must be equal to This->Mode->MediaHeaderSize and the\r
+ DestAddr and Protocol parameters must not be NULL.\r
+ @param BufferSize The size, in bytes, of the entire packet (media header and\r
+ data) to be transmitted through the network interface.\r
+ @param Buffer A pointer to the packet (media header followed by data) to\r
+ be transmitted. This parameter cannot be NULL. If\r
+ HeaderSize is zero, then the media header in Buffer must\r
+ already be filled in by the caller. If HeaderSize is\r
+ non-zero, then the media header will be filled in by the\r
+ Transmit() function.\r
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then\r
+ this parameter is ignored. If HeaderSize is non-zero and\r
+ SrcAddr is NULL, then This->Mode->CurrentAddress is used\r
+ for the source HW MAC address.\r
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero,\r
+ then this parameter is ignored.\r
+ @param Protocol The type of header to build. If HeaderSize is zero, then\r
+ this parameter is ignored. See RFC 1700, section "Ether\r
+ Types", for examples.\r
+\r
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.\r
+ @retval EFI_NOT_STARTED The network interface has not been started.\r
+ @retval EFI_NOT_READY The network interface is too busy to accept\r
+ this transmit request.\r
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.\r
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an\r
+ unsupported value.\r
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network\r
+ interface.\r
+ @retval EFI_UNSUPPORTED This function is not supported by the network\r
+ interface.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioNetTransmit (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r
+ IN UINTN HeaderSize,\r
+ IN UINTN BufferSize,\r
+ IN /* +OUT! */ VOID *Buffer,\r
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,\r
+ IN UINT16 *Protocol OPTIONAL\r
+ )\r
+{\r
+ VNET_DEV *Dev;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ UINT16 DescIdx;\r
+ UINT16 AvailIdx;\r
+\r
+ if (This == NULL || BufferSize == 0 || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = VIRTIO_NET_FROM_SNP (This);\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ switch (Dev->Snm.State) {\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ case EfiSimpleNetworkStarted:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ if (BufferSize < Dev->Snm.MediaHeaderSize) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto Exit;\r
+ }\r
+ if (BufferSize > Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // check if we have room for transmission\r
+ //\r
+ ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);\r
+ if (Dev->TxCurPending == Dev->TxMaxPending) {\r
+ Status = EFI_NOT_READY;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // the caller may want us to fill in the media header:\r
+ // dst MAC, src MAC, Ethertype\r
+ //\r
+ if (HeaderSize != 0) {\r
+ UINT8 *Ptr;\r
+\r
+ if (HeaderSize != Dev->Snm.MediaHeaderSize ||\r
+ DestAddr == NULL || Protocol == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+ Ptr = Buffer;\r
+ ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));\r
+\r
+ CopyMem (Ptr, DestAddr, SIZE_OF_VNET (VhdrMac));\r
+ Ptr += SIZE_OF_VNET (VhdrMac);\r
+\r
+ CopyMem (Ptr,\r
+ (SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,\r
+ SIZE_OF_VNET (VhdrMac));\r
+ Ptr += SIZE_OF_VNET (VhdrMac);\r
+\r
+ *Ptr++ = (UINT8) (*Protocol >> 8);\r
+ *Ptr++ = (UINT8) *Protocol;\r
+\r
+ ASSERT (Ptr - (UINT8 *) Buffer == Dev->Snm.MediaHeaderSize);\r
+ }\r
+\r
+ //\r
+ // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device\r
+ //\r
+ DescIdx = Dev->TxFreeStack[Dev->TxCurPending++];\r
+ Dev->TxRing.Desc[DescIdx + 1].Addr = (UINTN) Buffer;\r
+ Dev->TxRing.Desc[DescIdx + 1].Len = (UINT32) BufferSize;\r
+\r
+ //\r
+ // the available index is never written by the host, we can read it back\r
+ // without a barrier\r
+ //\r
+ AvailIdx = *Dev->TxRing.Avail.Idx;\r
+ Dev->TxRing.Avail.Ring[AvailIdx++ % Dev->TxRing.QueueSize] = DescIdx;\r
+\r
+ MemoryFence ();\r
+ *Dev->TxRing.Avail.Idx = AvailIdx;\r
+\r
+ MemoryFence ();\r
+ Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_TX);\r
+\r
+Exit:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r