MdeModulePkg: SNP should check Cdb.StatCode with PXE_STATCODE_SUCCESS.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Get_status.c
CommitLineData
75d0f44d 1/** @file\r
4140a663 2 Implementation of reading the current interrupt status and recycled transmit\r
3 buffer status from a network interface.\r
4cda7726 4\r
7b4b93a2 5Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 6This program and the accompanying materials are licensed\r
c777c357 7and made available under the terms and conditions of the BSD License which\r
8accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
75d0f44d 10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
75d0f44d 14**/\r
15\r
16#include "Snp.h"\r
17\r
75d0f44d 18/**\r
7b4b93a2
FS
19 Call undi to get the status of the interrupts, get the list of recycled transmit\r
20 buffers that completed transmitting. The recycled transmit buffer address will\r
21 be saved into Snp->RecycledTxBuf.\r
f3816027 22\r
23 @param Snp Pointer to snp driver structure.\r
c777c357 24 @param InterruptStatusPtr A non null pointer to contain the interrupt\r
f3816027 25 status.\r
7b4b93a2
FS
26 @param GetTransmittedBuf Set to TRUE to retrieve the recycled transmit\r
27 buffer address.\r
c777c357 28\r
f3816027 29 @retval EFI_SUCCESS The status of the network interface was retrieved.\r
c777c357 30 @retval EFI_DEVICE_ERROR The command could not be sent to the network\r
f3816027 31 interface.\r
75d0f44d 32\r
33**/\r
34EFI_STATUS\r
4cda7726 35PxeGetStatus (\r
36 SNP_DRIVER *Snp,\r
75d0f44d 37 UINT32 *InterruptStatusPtr,\r
7b4b93a2 38 BOOLEAN GetTransmittedBuf\r
75d0f44d 39 )\r
40{\r
4cda7726 41 PXE_DB_GET_STATUS *Db;\r
75d0f44d 42 UINT16 InterruptFlags;\r
7b4b93a2
FS
43 UINT32 Index;\r
44 UINT64 *Tmp;\r
75d0f44d 45\r
7b4b93a2 46 Tmp = NULL;\r
4cda7726 47 Db = Snp->Db;\r
48 Snp->Cdb.OpCode = PXE_OPCODE_GET_STATUS;\r
75d0f44d 49\r
4cda7726 50 Snp->Cdb.OpFlags = 0;\r
75d0f44d 51\r
7b4b93a2 52 if (GetTransmittedBuf) {\r
4cda7726 53 Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;\r
7b4b93a2 54 ZeroMem (Db->TxBuffer, sizeof (Db->TxBuffer));\r
75d0f44d 55 }\r
56\r
57 if (InterruptStatusPtr != NULL) {\r
4cda7726 58 Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;\r
75d0f44d 59 }\r
60\r
c777c357 61 if (Snp->MediaStatusSupported) {\r
62 Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_MEDIA_STATUS;\r
63 }\r
64\r
4cda7726 65 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
66 Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
75d0f44d 67\r
f000a8c6 68 Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_GET_STATUS);\r
4cda7726 69 Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;\r
75d0f44d 70\r
4cda7726 71 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
72 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
73 Snp->Cdb.IFnum = Snp->IfNum;\r
74 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
75d0f44d 75\r
76 //\r
77 // Issue UNDI command and check result.\r
78 //\r
9cff2f8d 79 DEBUG ((EFI_D_NET, "\nSnp->undi.get_status() "));\r
75d0f44d 80\r
4cda7726 81 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);\r
75d0f44d 82\r
3af347b3 83 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
75d0f44d 84 DEBUG (\r
9cff2f8d 85 (EFI_D_NET,\r
4cda7726 86 "\nSnp->undi.get_status() %xh:%xh\n",\r
87 Snp->Cdb.StatFlags,\r
1e7b3ef6 88 Snp->Cdb.StatCode)\r
75d0f44d 89 );\r
90\r
91 return EFI_DEVICE_ERROR;\r
92 }\r
93 //\r
94 // report the values back..\r
95 //\r
96 if (InterruptStatusPtr != NULL) {\r
4cda7726 97 InterruptFlags = (UINT16) (Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);\r
75d0f44d 98\r
99 *InterruptStatusPtr = 0;\r
100\r
4cda7726 101 if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) == PXE_STATFLAGS_GET_STATUS_RECEIVE) {\r
75d0f44d 102 *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
103 }\r
104\r
4cda7726 105 if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) == PXE_STATFLAGS_GET_STATUS_TRANSMIT) {\r
75d0f44d 106 *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
107 }\r
108\r
4cda7726 109 if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) == PXE_STATFLAGS_GET_STATUS_COMMAND) {\r
75d0f44d 110 *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;\r
111 }\r
112\r
4cda7726 113 if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) == PXE_STATFLAGS_GET_STATUS_SOFTWARE) {\r
75d0f44d 114 *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;\r
115 }\r
116\r
117 }\r
118\r
7b4b93a2
FS
119 if (GetTransmittedBuf) {\r
120 if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) == 0) {\r
121 //\r
122 // UNDI has written some transmitted buffer addresses into the DB. Store them into Snp->RecycledTxBuf.\r
123 //\r
124 for (Index = 0; Index < MAX_XMIT_BUFFERS; Index++) {\r
125 if (Db->TxBuffer[Index] != 0) {\r
126 if (Snp->RecycledTxBufCount == Snp->MaxRecycledTxBuf) {\r
127 //\r
128 // Snp->RecycledTxBuf is full, reallocate a new one.\r
129 //\r
130 if ((Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) {\r
131 return EFI_DEVICE_ERROR;\r
132 }\r
133 Tmp = AllocatePool (sizeof (UINT64) * (Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT));\r
134 if (Tmp == NULL) {\r
135 return EFI_DEVICE_ERROR;\r
136 }\r
137 CopyMem (Tmp, Snp->RecycledTxBuf, sizeof (UINT64) * Snp->RecycledTxBufCount);\r
138 FreePool (Snp->RecycledTxBuf);\r
139 Snp->RecycledTxBuf = Tmp;\r
140 Snp->MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT;\r
141 }\r
142 Snp->RecycledTxBuf[Snp->RecycledTxBufCount] = Db->TxBuffer[Index];\r
143 Snp->RecycledTxBufCount++;\r
144 }\r
145 }\r
146 }\r
75d0f44d 147 }\r
148\r
c777c357 149 //\r
150 // Update MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support\r
151 // returning media status from GET_STATUS command\r
152 //\r
153 if (Snp->MediaStatusSupported) {\r
154 Snp->Snp.Mode->MediaPresent =\r
155 (BOOLEAN) (((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA) != 0) ? FALSE : TRUE);\r
156 }\r
157\r
75d0f44d 158 return EFI_SUCCESS;\r
159}\r
160\r
75d0f44d 161/**\r
4cda7726 162 Reads the current interrupt status and recycled transmit buffer status from a\r
163 network interface.\r
c777c357 164\r
165 This function gets the current interrupt and recycled transmit buffer status\r
4cda7726 166 from the network interface. The interrupt status is returned as a bit mask in\r
167 InterruptStatus. If InterruptStatus is NULL, the interrupt status will not be\r
168 read. If TxBuf is not NULL, a recycled transmit buffer address will be retrieved.\r
169 If a recycled transmit buffer address is returned in TxBuf, then the buffer has\r
170 been successfully transmitted, and the status for that buffer is cleared. If\r
c777c357 171 the status of the network interface is successfully collected, EFI_SUCCESS\r
4cda7726 172 will be returned. If the driver has not been initialized, EFI_DEVICE_ERROR will\r
173 be returned.\r
174\r
175 @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.\r
c777c357 176 @param InterruptStatus A pointer to the bit mask of the currently active\r
4cda7726 177 interrupts (see "Related Definitions"). If this is NULL,\r
178 the interrupt status will not be read from the device.\r
179 If this is not NULL, the interrupt status will be read\r
c777c357 180 from the device. When the interrupt status is read, it\r
181 will also be cleared. Clearing the transmit interrupt does\r
4cda7726 182 not empty the recycled transmit buffer array.\r
183 @param TxBuf Recycled transmit buffer address. The network interface\r
c777c357 184 will not transmit if its internal recycled transmit\r
4cda7726 185 buffer array is full. Reading the transmit buffer does\r
186 not clear the transmit interrupt. If this is NULL, then\r
c777c357 187 the transmit buffer status will not be read. If there\r
188 are no transmit buffers to recycle and TxBuf is not NULL,\r
4cda7726 189 TxBuf will be set to NULL.\r
190\r
191 @retval EFI_SUCCESS The status of the network interface was retrieved.\r
192 @retval EFI_NOT_STARTED The network interface has not been started.\r
c777c357 193 @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid\r
4cda7726 194 EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
c777c357 195 @retval EFI_DEVICE_ERROR The command could not be sent to the network\r
4cda7726 196 interface.\r
75d0f44d 197\r
198**/\r
199EFI_STATUS\r
200EFIAPI\r
4cda7726 201SnpUndi32GetStatus (\r
202 IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r
203 OUT UINT32 *InterruptStatus, OPTIONAL\r
204 OUT VOID **TxBuf OPTIONAL\r
75d0f44d 205 )\r
206{\r
4cda7726 207 SNP_DRIVER *Snp;\r
75d0f44d 208 EFI_TPL OldTpl;\r
209 EFI_STATUS Status;\r
210\r
4cda7726 211 if (This == NULL) {\r
75d0f44d 212 return EFI_INVALID_PARAMETER;\r
213 }\r
214\r
4cda7726 215 if (InterruptStatus == NULL && TxBuf == NULL) {\r
75d0f44d 216 return EFI_INVALID_PARAMETER;\r
217 }\r
218\r
4cda7726 219 Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
75d0f44d 220\r
221 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
222\r
4cda7726 223 if (Snp == NULL) {\r
75d0f44d 224 return EFI_DEVICE_ERROR;\r
225 }\r
226\r
4cda7726 227 switch (Snp->Mode.State) {\r
75d0f44d 228 case EfiSimpleNetworkInitialized:\r
229 break;\r
230\r
231 case EfiSimpleNetworkStopped:\r
232 Status = EFI_NOT_STARTED;\r
233 goto ON_EXIT;\r
234\r
235 default:\r
236 Status = EFI_DEVICE_ERROR;\r
237 goto ON_EXIT;\r
238 }\r
239\r
7b4b93a2
FS
240 if (Snp->RecycledTxBufCount == 0 && TxBuf != NULL) {\r
241 Status = PxeGetStatus (Snp, InterruptStatus, TRUE);\r
242 } else {\r
243 Status = PxeGetStatus (Snp, InterruptStatus, FALSE);\r
244 }\r
245\r
246 if (TxBuf != NULL) {\r
247 //\r
248 // Get a recycled buf from Snp->RecycledTxBuf\r
249 //\r
250 if (Snp->RecycledTxBufCount == 0) {\r
251 *TxBuf = NULL;\r
252 } else {\r
253 Snp->RecycledTxBufCount--;\r
254 *TxBuf = (VOID *) (UINTN) Snp->RecycledTxBuf[Snp->RecycledTxBufCount];\r
255 }\r
256 }\r
75d0f44d 257\r
258ON_EXIT:\r
259 gBS->RestoreTPL (OldTpl);\r
260\r
261 return Status;\r
262}\r