]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioNetDxe/SnpGetStatus.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / VirtioNetDxe / SnpGetStatus.c
CommitLineData
b6dfc654
LE
1/** @file\r
2\r
3 Implementation of the SNP.GetStatus() function and its private helpers if\r
4 any.\r
5\r
6 Copyright (C) 2013, Red Hat, Inc.\r
c4046161 7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
b6dfc654 8\r
b26f0cf9 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
b6dfc654
LE
10\r
11**/\r
12\r
13#include <Library/BaseLib.h>\r
14#include <Library/UefiBootServicesTableLib.h>\r
15\r
16#include "VirtioNet.h"\r
17\r
18/**\r
19 Reads the current interrupt status and recycled transmit buffer status from\r
20 a network interface.\r
21\r
22 @param This The protocol instance pointer.\r
23 @param InterruptStatus A pointer to the bit mask of the currently active\r
24 interrupts If this is NULL, the interrupt status will\r
25 not be read from the device. If this is not NULL, the\r
26 interrupt status will be read from the device. When\r
27 the interrupt status is read, it will also be\r
28 cleared. Clearing the transmit interrupt does not\r
29 empty the recycled transmit buffer array.\r
30 @param TxBuf Recycled transmit buffer address. The network\r
31 interface will not transmit if its internal recycled\r
32 transmit buffer array is full. Reading the transmit\r
33 buffer does not clear the transmit interrupt. If this\r
34 is NULL, then the transmit buffer status will not be\r
35 read. If there are no transmit buffers to recycle and\r
36 TxBuf is not NULL, * TxBuf will be set to NULL.\r
37\r
38 @retval EFI_SUCCESS The status of the network interface was\r
39 retrieved.\r
40 @retval EFI_NOT_STARTED The network interface has not been started.\r
41 @retval EFI_INVALID_PARAMETER One or more of the parameters has an\r
42 unsupported value.\r
43 @retval EFI_DEVICE_ERROR The command could not be sent to the network\r
44 interface.\r
45 @retval EFI_UNSUPPORTED This function is not supported by the network\r
46 interface.\r
47\r
48**/\r
b6dfc654
LE
49EFI_STATUS\r
50EFIAPI\r
51VirtioNetGetStatus (\r
ac0a286f
MK
52 IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r
53 OUT UINT32 *InterruptStatus OPTIONAL,\r
54 OUT VOID **TxBuf OPTIONAL\r
b6dfc654
LE
55 )\r
56{\r
ac0a286f
MK
57 VNET_DEV *Dev;\r
58 EFI_TPL OldTpl;\r
59 EFI_STATUS Status;\r
60 UINT16 RxCurUsed;\r
61 UINT16 TxCurUsed;\r
62 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
b6dfc654
LE
63\r
64 if (This == NULL) {\r
65 return EFI_INVALID_PARAMETER;\r
66 }\r
67\r
ac0a286f 68 Dev = VIRTIO_NET_FROM_SNP (This);\r
b6dfc654
LE
69 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
70 switch (Dev->Snm.State) {\r
ac0a286f
MK
71 case EfiSimpleNetworkStopped:\r
72 Status = EFI_NOT_STARTED;\r
73 goto Exit;\r
74 case EfiSimpleNetworkStarted:\r
75 Status = EFI_DEVICE_ERROR;\r
76 goto Exit;\r
77 default:\r
78 break;\r
b6dfc654
LE
79 }\r
80\r
81 //\r
82 // update link status\r
83 //\r
84 if (Dev->Snm.MediaPresentSupported) {\r
ac0a286f 85 UINT16 LinkStatus;\r
b6dfc654 86\r
56f65ed8 87 Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);\r
b6dfc654
LE
88 if (EFI_ERROR (Status)) {\r
89 goto Exit;\r
90 }\r
ac0a286f 91\r
c4046161 92 Dev->Snm.MediaPresent =\r
ac0a286f 93 (BOOLEAN)((LinkStatus & VIRTIO_NET_S_LINK_UP) != 0);\r
b6dfc654
LE
94 }\r
95\r
96 //\r
97 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
98 //\r
99 MemoryFence ();\r
100 RxCurUsed = *Dev->RxRing.Used.Idx;\r
101 TxCurUsed = *Dev->TxRing.Used.Idx;\r
dc9447bd 102 MemoryFence ();\r
b6dfc654
LE
103\r
104 if (InterruptStatus != NULL) {\r
105 //\r
106 // report the receive interrupt if there is data available for reception,\r
107 // report the transmit interrupt if we have transmitted at least one buffer\r
108 //\r
109 *InterruptStatus = 0;\r
110 if (Dev->RxLastUsed != RxCurUsed) {\r
111 *InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
112 }\r
ac0a286f 113\r
b6dfc654
LE
114 if (Dev->TxLastUsed != TxCurUsed) {\r
115 ASSERT (Dev->TxCurPending > 0);\r
116 *InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
117 }\r
118 }\r
119\r
120 if (TxBuf != NULL) {\r
121 if (Dev->TxLastUsed == TxCurUsed) {\r
122 *TxBuf = NULL;\r
ac0a286f
MK
123 } else {\r
124 UINT16 UsedElemIdx;\r
125 UINT32 DescIdx;\r
b6dfc654
LE
126\r
127 //\r
128 // fetch the first descriptor among those that the hypervisor reports\r
129 // completed\r
130 //\r
131 ASSERT (Dev->TxCurPending > 0);\r
132 ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);\r
133\r
134 UsedElemIdx = Dev->TxLastUsed++ % Dev->TxRing.QueueSize;\r
ac0a286f
MK
135 DescIdx = Dev->TxRing.Used.UsedElem[UsedElemIdx].Id;\r
136 ASSERT (DescIdx < (UINT32)(2 * Dev->TxMaxPending - 1));\r
b6dfc654
LE
137\r
138 //\r
8fa54a8a
BS
139 // get the device address that has been enqueued for the caller's\r
140 // transmit buffer\r
b6dfc654 141 //\r
8fa54a8a 142 DeviceAddress = Dev->TxRing.Desc[DescIdx + 1].Addr;\r
b6dfc654
LE
143\r
144 //\r
145 // now this descriptor can be used again to enqueue a transmit buffer\r
146 //\r
ac0a286f 147 Dev->TxFreeStack[--Dev->TxCurPending] = (UINT16)DescIdx;\r
8fa54a8a
BS
148\r
149 //\r
150 // Unmap the device address and perform the reverse mapping to find the\r
151 // caller buffer address.\r
152 //\r
153 Status = VirtioNetUnmapTxBuf (\r
154 Dev,\r
155 TxBuf,\r
156 DeviceAddress\r
157 );\r
158 if (EFI_ERROR (Status)) {\r
159 //\r
160 // VirtioNetUnmapTxBuf should never fail, if we have reached here\r
161 // that means our internal state has been corrupted\r
162 //\r
163 ASSERT (FALSE);\r
164 Status = EFI_DEVICE_ERROR;\r
165 goto Exit;\r
166 }\r
b6dfc654
LE
167 }\r
168 }\r
169\r
170 Status = EFI_SUCCESS;\r
171\r
172Exit:\r
173 gBS->RestoreTPL (OldTpl);\r
174 return Status;\r
175}\r