]> git.proxmox.com Git - mirror_edk2.git/blame - OptionRomPkg/UndiRuntimeDxe/Decode.c
Update the copyright notice format
[mirror_edk2.git] / OptionRomPkg / UndiRuntimeDxe / Decode.c
CommitLineData
51ebae6b 1/** @file\r
2 Provides the basic UNID functions.\r
3\r
ac1ca104
HT
4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
51ebae6b 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Undi32.h"\r
16\r
17//\r
18// Global variables defined in this file\r
19//\r
20UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] = { \\r
21 {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, (UINT16)(ANY_STATE),UNDI_GetState },\\r
22 {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,0,(UINT16)(ANY_STATE),UNDI_Start },\\r
23 {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UNDI_Stop },\\r
24 {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STARTED, UNDI_GetInitInfo },\\r
25 {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_STARTED, UNDI_GetConfigInfo },\\r
26 {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),MUST_BE_STARTED,UNDI_Initialize },\\r
27 {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Reset },\\r
28 {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, MUST_BE_INITIALIZED,UNDI_Shutdown },\\r
29 {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Interrupt },\\r
30 {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_RecFilter },\\r
31 {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_StnAddr },\\r
32 {PXE_CPBSIZE_NOT_USED, (UINT16)(DONT_CHECK), (UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Statistics },\\r
33 {sizeof(PXE_CPB_MCAST_IP_TO_MAC),sizeof(PXE_DB_MCAST_IP_TO_MAC), (UINT16)(DONT_CHECK),MUST_BE_INITIALIZED, UNDI_ip2mac },\\r
34 {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_NVData },\\r
35 {PXE_CPBSIZE_NOT_USED,(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Status },\\r
36 {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_FillHeader },\\r
37 {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Transmit },\\r
38 {sizeof(PXE_CPB_RECEIVE),sizeof(PXE_DB_RECEIVE),0,MUST_BE_INITIALIZED, UNDI_Receive } \\r
39};\r
40\r
41//\r
42// end of global variables\r
43//\r
44\r
45\r
46/**\r
47 This routine determines the operational state of the UNDI. It updates the state flags in the\r
48 Command Descriptor Block based on information derived from the AdapterInfo instance data.\r
49 To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of\r
50 the command execution.\r
51 The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command\r
52 has successfully completed.\r
53 Keep in mind the AdapterInfo->State is the active state of the adapter (based on software\r
54 interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected\r
55 to the caller of the UNDI API.\r
56\r
57 @param CdbPtr Pointer to the command descriptor block.\r
58 @param AdapterInfo Pointer to the NIC data structure information which\r
59 the UNDI driver is layering on..\r
60\r
61 @return None\r
62\r
63**/\r
64VOID\r
65UNDI_GetState (\r
66 IN PXE_CDB *CdbPtr,\r
67 IN NIC_DATA_INSTANCE *AdapterInfo\r
68 )\r
69{\r
70 CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->State);\r
71 return ;\r
72}\r
73\r
74\r
75/**\r
76 This routine is used to change the operational state of the UNDI from stopped to started.\r
77 It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise\r
78 the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the\r
79 UNDI as having already been started.\r
80 This routine is modified to reflect the undi 1.1 specification changes. The\r
81 changes in the spec are mainly in the callback routines, the new spec adds\r
82 3 more callbacks and a unique id.\r
83 Since this UNDI supports both old and new undi specifications,\r
84 The NIC's data structure is filled in with the callback routines (depending\r
85 on the version) pointed to in the caller's CpbPtr. This seeds the Delay,\r
86 Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem\r
87 and Sync_Mem routines and a unique id variable for the new version.\r
88 This is the function which an external entity (SNP, O/S, etc) would call\r
89 to provide it's I/O abstraction to the UNDI.\r
90 It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.\r
91\r
92 @param CdbPtr Pointer to the command descriptor block.\r
93 @param AdapterInfo Pointer to the NIC data structure information which\r
94 the UNDI driver is layering on..\r
95\r
96 @return None\r
97\r
98**/\r
99VOID\r
100UNDI_Start (\r
101 IN PXE_CDB *CdbPtr,\r
102 IN NIC_DATA_INSTANCE *AdapterInfo\r
103 )\r
104{\r
105 PXE_CPB_START_30 *CpbPtr;\r
106 PXE_CPB_START_31 *CpbPtr_31;\r
107\r
108 //\r
109 // check if it is already started.\r
110 //\r
111 if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_STOPPED) {\r
112 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
113 CdbPtr->StatCode = PXE_STATCODE_ALREADY_STARTED;\r
114 return ;\r
115 }\r
116\r
117 if (CdbPtr->CPBsize != sizeof(PXE_CPB_START_30) &&\r
118 CdbPtr->CPBsize != sizeof(PXE_CPB_START_31)) {\r
119\r
120 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
121 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
122 return ;\r
123 }\r
124\r
125 CpbPtr = (PXE_CPB_START_30 *) (UINTN) (CdbPtr->CPBaddr);\r
126 CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);\r
127\r
128 if (AdapterInfo->VersionFlag == 0x30) {\r
129 AdapterInfo->Delay_30 = (bsptr_30) (UINTN) CpbPtr->Delay;\r
130 AdapterInfo->Virt2Phys_30 = (virtphys_30) (UINTN) CpbPtr->Virt2Phys;\r
131 AdapterInfo->Block_30 = (block_30) (UINTN) CpbPtr->Block;\r
132 //\r
133 // patch for old buggy 3.0 code:\r
134 // In EFI1.0 undi used to provide the full (absolute) I/O address to the\r
135 // i/o calls and SNP used to provide a callback that used GlobalIoFncs and\r
136 // everything worked fine! In EFI 1.1, UNDI is not using the full\r
137 // i/o or memory address to access the device, The base values for the i/o\r
138 // and memory address is abstracted by the device specific PciIoFncs and\r
139 // UNDI only uses the offset values. Since UNDI3.0 cannot provide any\r
140 // identification to SNP, SNP cannot use nic specific PciIoFncs callback!\r
141 //\r
142 // To fix this and make undi3.0 work with SNP in EFI1.1 we\r
143 // use a TmpMemIo function that is defined in init.c\r
144 // This breaks the runtime driver feature of undi, but what to do\r
145 // if we have to provide the 3.0 compatibility (including the 3.0 bugs)\r
146 //\r
147 // This TmpMemIo function also takes a UniqueId parameter\r
148 // (as in undi3.1 design) and so initialize the UniqueId as well here\r
149 // Note: AdapterInfo->Mem_Io_30 is just filled for consistency with other\r
150 // parameters but never used, we only use Mem_Io field in the In/Out routines\r
151 // inside e100b.c.\r
152 //\r
153 AdapterInfo->Mem_Io_30 = (mem_io_30) (UINTN) CpbPtr->Mem_IO;\r
154 AdapterInfo->Mem_Io = (mem_io) (UINTN) TmpMemIo;\r
155 AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo;\r
156\r
157 } else {\r
158 AdapterInfo->Delay = (bsptr) (UINTN) CpbPtr_31->Delay;\r
159 AdapterInfo->Virt2Phys = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;\r
160 AdapterInfo->Block = (block) (UINTN) CpbPtr_31->Block;\r
161 AdapterInfo->Mem_Io = (mem_io) (UINTN) CpbPtr_31->Mem_IO;\r
162\r
163 AdapterInfo->Map_Mem = (map_mem) (UINTN) CpbPtr_31->Map_Mem;\r
164 AdapterInfo->UnMap_Mem = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;\r
165 AdapterInfo->Sync_Mem = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;\r
166 AdapterInfo->Unique_ID = CpbPtr_31->Unique_ID;\r
167 }\r
168\r
169 AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;\r
170\r
171 return ;\r
172}\r
173\r
174\r
175/**\r
176 This routine is used to change the operational state of the UNDI from started to stopped.\r
177 It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise\r
178 the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the\r
179 UNDI as having already not been shut down.\r
180 The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..\r
181 It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.\r
182\r
183 @param CdbPtr Pointer to the command descriptor block.\r
184 @param AdapterInfo Pointer to the NIC data structure information which\r
185 the UNDI driver is layering on..\r
186\r
187 @return None\r
188\r
189**/\r
190VOID\r
191UNDI_Stop (\r
192 IN PXE_CDB *CdbPtr,\r
193 IN NIC_DATA_INSTANCE *AdapterInfo\r
194 )\r
195{\r
196 if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
197 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
198 CdbPtr->StatCode = PXE_STATCODE_NOT_SHUTDOWN;\r
199 return ;\r
200 }\r
201\r
202 AdapterInfo->Delay_30 = 0;\r
203 AdapterInfo->Virt2Phys_30 = 0;\r
204 AdapterInfo->Block_30 = 0;\r
205\r
206 AdapterInfo->Delay = 0;\r
207 AdapterInfo->Virt2Phys = 0;\r
208 AdapterInfo->Block = 0;\r
209\r
210 AdapterInfo->Map_Mem = 0;\r
211 AdapterInfo->UnMap_Mem = 0;\r
212 AdapterInfo->Sync_Mem = 0;\r
213\r
214 AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STOPPED;\r
215\r
216 return ;\r
217}\r
218\r
219\r
220/**\r
221 This routine is used to retrieve the initialization information that is needed by drivers and\r
222 applications to initialize the UNDI. This will fill in data in the Data Block structure that is\r
223 pointed to by the caller's CdbPtr->DBaddr. The fields filled in are as follows:\r
224 MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,\r
225 MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.\r
226 In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection. (APRIORI knowledge)\r
227\r
228 @param CdbPtr Pointer to the command descriptor block.\r
229 @param AdapterInfo Pointer to the NIC data structure information which\r
230 the UNDI driver is layering on..\r
231\r
232 @return None\r
233\r
234**/\r
235VOID\r
236UNDI_GetInitInfo (\r
237 IN PXE_CDB *CdbPtr,\r
238 IN NIC_DATA_INSTANCE *AdapterInfo\r
239 )\r
240{\r
241 PXE_DB_GET_INIT_INFO *DbPtr;\r
242\r
243 DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);\r
244\r
245 DbPtr->MemoryRequired = MEMORY_NEEDED;\r
246 DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;\r
247 DbPtr->LinkSpeeds[0] = 10;\r
248 DbPtr->LinkSpeeds[1] = 100;\r
249 DbPtr->LinkSpeeds[2] = DbPtr->LinkSpeeds[3] = 0;\r
250 DbPtr->NvCount = MAX_EEPROM_LEN;\r
251 DbPtr->NvWidth = 4;\r
252 DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;\r
253 DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;\r
254 DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;\r
255\r
256 DbPtr->TxBufCnt = TX_BUFFER_COUNT;\r
257 DbPtr->TxBufSize = sizeof (TxCB);\r
258 DbPtr->RxBufCnt = RX_BUFFER_COUNT;\r
259 DbPtr->RxBufSize = sizeof (RxFD);\r
260\r
261 DbPtr->IFtype = PXE_IFTYPE_ETHERNET;\r
262 DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED |\r
263 PXE_DUPLEX_FORCE_FULL_SUPPORTED;\r
264 DbPtr->SupportedLoopBackModes = PXE_LOOPBACK_INTERNAL_SUPPORTED |\r
265 PXE_LOOPBACK_EXTERNAL_SUPPORTED;\r
266\r
135ec2db 267 CdbPtr->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |\r
268 PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);\r
51ebae6b 269 return ;\r
270}\r
271\r
272\r
273/**\r
274 This routine is used to retrieve the configuration information about the NIC being controlled by\r
275 this driver. This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.\r
276 The fields filled in are as follows:\r
277 DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.\r
278 In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.\r
279\r
280 @param CdbPtr Pointer to the command descriptor block.\r
281 @param AdapterInfo Pointer to the NIC data structure information which\r
282 the UNDI driver is layering on..\r
283\r
284 @return None\r
285\r
286**/\r
287VOID\r
288UNDI_GetConfigInfo (\r
289 IN PXE_CDB *CdbPtr,\r
290 IN NIC_DATA_INSTANCE *AdapterInfo\r
291 )\r
292{\r
293 UINT16 Index;\r
294 PXE_DB_GET_CONFIG_INFO *DbPtr;\r
295\r
296 DbPtr = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);\r
297\r
298 DbPtr->pci.BusType = PXE_BUSTYPE_PCI;\r
299 DbPtr->pci.Bus = AdapterInfo->Bus;\r
300 DbPtr->pci.Device = AdapterInfo->Device;\r
301 DbPtr->pci.Function = AdapterInfo->Function;\r
302\r
303 for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {\r
304 DbPtr->pci.Config.Dword[Index] = AdapterInfo->Config[Index];\r
305 }\r
306\r
307 return ;\r
308}\r
309\r
310\r
311/**\r
312 This routine resets the network adapter and initializes the UNDI using the parameters supplied in\r
313 the CPB. This command must be issued before the network adapter can be setup to transmit and\r
314 receive packets.\r
315 Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block\r
316 of non-swappable memory may need to be allocated. The address of this memory must be passed to\r
317 UNDI during the Initialize in the CPB. This memory is used primarily for transmit and receive buffers.\r
318 The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with information\r
319 that was passed in the CPB and the NIC is initialized.\r
320 If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
321 Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of\r
322 the UNDI is now initialized.\r
323\r
324 @param CdbPtr Pointer to the command descriptor block.\r
325 @param AdapterInfo Pointer to the NIC data structure information which\r
326 the UNDI driver is layering on..\r
327\r
328 @return None\r
329\r
330**/\r
331VOID\r
332UNDI_Initialize (\r
333 IN PXE_CDB *CdbPtr,\r
334 NIC_DATA_INSTANCE *AdapterInfo\r
335 )\r
336{\r
337 PXE_CPB_INITIALIZE *CpbPtr;\r
338\r
339 if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&\r
340 (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) {\r
341 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
342 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
343 return ;\r
344 }\r
345\r
346 //\r
347 // check if it is already initialized\r
348 //\r
349 if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
350 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
351 CdbPtr->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;\r
352 return ;\r
353 }\r
354\r
355 CpbPtr = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;\r
356\r
357 if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) {\r
358 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
359 CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB;\r
360 return ;\r
361 }\r
362\r
363 //\r
364 // default behaviour is to detect the cable, if the 3rd param is 1,\r
365 // do not do that\r
366 //\r
367 AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);\r
368 AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed;\r
369 AdapterInfo->DuplexReq = CpbPtr->DuplexMode;\r
370 AdapterInfo->LoopBack = CpbPtr->LoopBackMode;\r
371 AdapterInfo->MemoryPtr = CpbPtr->MemoryAddr;\r
372 AdapterInfo->MemoryLength = CpbPtr->MemoryLength;\r
373\r
374 CdbPtr->StatCode = (PXE_STATCODE) E100bInit (AdapterInfo);\r
375\r
376 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
377 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
378 } else {\r
379 AdapterInfo->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;\r
380 }\r
381\r
382 return ;\r
383}\r
384\r
385\r
386/**\r
387 This routine resets the network adapter and initializes the UNDI using the parameters supplied in\r
388 the CPB. The transmit and receive queues are emptied and any pending interrupts are cleared.\r
389 If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
390\r
391 @param CdbPtr Pointer to the command descriptor block.\r
392 @param AdapterInfo Pointer to the NIC data structure information which\r
393 the UNDI driver is layering on..\r
394\r
395 @return None\r
396\r
397**/\r
398VOID\r
399UNDI_Reset (\r
400 IN PXE_CDB *CdbPtr,\r
401 IN NIC_DATA_INSTANCE *AdapterInfo\r
402 )\r
403{\r
404 if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&\r
405 CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&\r
406 CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS ) {\r
407\r
408 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
409 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
410 return ;\r
411 }\r
412\r
413 CdbPtr->StatCode = (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags);\r
414\r
415 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
416 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
417 }\r
418}\r
419\r
420\r
421/**\r
422 This routine resets the network adapter and leaves it in a safe state for another driver to\r
423 initialize. Any pending transmits or receives are lost. Receive filters and external\r
424 interrupt enables are disabled. Once the UNDI has been shutdown, it can then be stopped\r
425 or initialized again.\r
426 If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
427 Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing the state of\r
428 the NIC as being started.\r
429\r
430 @param CdbPtr Pointer to the command descriptor block.\r
431 @param AdapterInfo Pointer to the NIC data structure information which\r
432 the UNDI driver is layering on..\r
433\r
434 @return None\r
435\r
436**/\r
437VOID\r
438UNDI_Shutdown (\r
439 IN PXE_CDB *CdbPtr,\r
440 IN NIC_DATA_INSTANCE *AdapterInfo\r
441 )\r
442{\r
443 //\r
444 // do the shutdown stuff here\r
445 //\r
446 CdbPtr->StatCode = (UINT16) E100bShutdown (AdapterInfo);\r
447\r
448 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
449 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
450 } else {\r
451 AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;\r
452 }\r
453\r
454 return ;\r
455}\r
456\r
457\r
458/**\r
459 This routine can be used to read and/or change the current external interrupt enable\r
460 settings. Disabling an external interrupt enable prevents and external (hardware)\r
461 interrupt from being signaled by the network device. Internally the interrupt events\r
462 can still be polled by using the UNDI_GetState command.\r
463 The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.\r
464\r
465 @param CdbPtr Pointer to the command descriptor block.\r
466 @param AdapterInfo Pointer to the NIC data structure information which\r
467 the UNDI driver is layering on..\r
468\r
469 @return None\r
470\r
471**/\r
472VOID\r
473UNDI_Interrupt (\r
474 IN PXE_CDB *CdbPtr,\r
475 IN NIC_DATA_INSTANCE *AdapterInfo\r
476 )\r
477{\r
478 UINT8 IntMask;\r
479\r
480 IntMask = (UINT8)(UINTN)(CdbPtr->OpFlags & (PXE_OPFLAGS_INTERRUPT_RECEIVE |\r
481 PXE_OPFLAGS_INTERRUPT_TRANSMIT |\r
482 PXE_OPFLAGS_INTERRUPT_COMMAND |\r
483 PXE_OPFLAGS_INTERRUPT_SOFTWARE));\r
484\r
485 switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {\r
486 case PXE_OPFLAGS_INTERRUPT_READ:\r
487 break;\r
488\r
489 case PXE_OPFLAGS_INTERRUPT_ENABLE:\r
490 if (IntMask == 0) {\r
491 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
492 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
493 return ;\r
494 }\r
495\r
496 AdapterInfo->int_mask = IntMask;\r
497 E100bSetInterruptState (AdapterInfo);\r
498 break;\r
499\r
500 case PXE_OPFLAGS_INTERRUPT_DISABLE:\r
501 if (IntMask != 0) {\r
502 AdapterInfo->int_mask = (UINT16) (AdapterInfo->int_mask & ~(IntMask));\r
503 E100bSetInterruptState (AdapterInfo);\r
504 break;\r
505 }\r
506\r
507 //\r
508 // else fall thru.\r
509 //\r
510 default:\r
511 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
512 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
513 return ;\r
514 }\r
515\r
516 if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {\r
517 CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;\r
518\r
519 }\r
520\r
521 if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {\r
522 CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;\r
523\r
524 }\r
525\r
526 if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {\r
527 CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;\r
528\r
529 }\r
530\r
531 return ;\r
532}\r
533\r
534\r
535/**\r
536 This routine is used to read and change receive filters and, if supported, read\r
537 and change multicast MAC address filter list.\r
538\r
539 @param CdbPtr Pointer to the command descriptor block.\r
540 @param AdapterInfo Pointer to the NIC data structure information which\r
541 the UNDI driver is layering on..\r
542\r
543 @return None\r
544\r
545**/\r
546VOID\r
547UNDI_RecFilter (\r
548 IN PXE_CDB *CdbPtr,\r
549 IN NIC_DATA_INSTANCE *AdapterInfo\r
550 )\r
551{\r
552 UINT16 NewFilter;\r
553 UINT16 OpFlags;\r
554 PXE_DB_RECEIVE_FILTERS *DbPtr;\r
555 UINT8 *MacAddr;\r
556 UINTN MacCount;\r
557 UINT16 Index;\r
558 UINT16 copy_len;\r
559 UINT8 *ptr1;\r
560 UINT8 *ptr2;\r
cd417925 561 BOOLEAN InvalidMacAddr;\r
562 \r
51ebae6b 563 OpFlags = CdbPtr->OpFlags;\r
564 NewFilter = (UINT16) (OpFlags & 0x1F);\r
565\r
566 switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {\r
567 case PXE_OPFLAGS_RECEIVE_FILTER_READ:\r
568\r
569 //\r
570 // not expecting a cpb, not expecting any filter bits\r
571 //\r
572 if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {\r
573 goto BadCdb;\r
574\r
575 }\r
576\r
577 if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {\r
578 goto JustRead;\r
579\r
580 }\r
581\r
582 NewFilter = (UINT16) (NewFilter | AdapterInfo->Rx_Filter);\r
583 //\r
584 // all other flags are ignored except mcast_reset\r
585 //\r
586 break;\r
587\r
588 case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:\r
589 //\r
590 // there should be atleast one other filter bit set.\r
591 //\r
592 if (NewFilter == 0) {\r
593 //\r
594 // nothing to enable\r
595 //\r
596 goto BadCdb;\r
597 }\r
598\r
599 if (CdbPtr->CPBsize != 0) {\r
600 //\r
601 // this must be a multicast address list!\r
602 // don't accept the list unless selective_mcast is set\r
603 // don't accept confusing mcast settings with this\r
604 //\r
605 if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||\r
606 ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||\r
607 ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||\r
608 ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) {\r
609 goto BadCdb;\r
610 }\r
611\r
612 MacAddr = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr));\r
613 MacCount = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR);\r
614\r
cd417925 615 //\r
616 // The format of Ethernet multicast address for IPv6 is defined in RFC2464,\r
617 // for IPv4 is defined in RFC1112. Check whether the address is valid.\r
618 //\r
619 InvalidMacAddr = FALSE;\r
620 \r
51ebae6b 621 for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) {\r
cd417925 622 if (MacAddr[0] == 0x01) {\r
623 //\r
624 // This multicast MAC address is mapped from IPv4 address.\r
625 //\r
626 if (MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) {\r
627 InvalidMacAddr = TRUE;\r
628 } \r
629 } else if (MacAddr[0] == 0x33) {\r
630 //\r
631 // This multicast MAC address is mapped from IPv6 address.\r
632 //\r
633 if (MacAddr[1] != 0x33) {\r
634 InvalidMacAddr = TRUE;\r
635 }\r
636 } else {\r
637 InvalidMacAddr = TRUE;\r
638 }\r
639\r
640 if (InvalidMacAddr) {\r
51ebae6b 641 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
642 CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB;\r
643 return ;\r
644 }\r
645 }\r
646 }\r
647\r
648 //\r
649 // check selective mcast case enable case\r
650 //\r
651 if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {\r
652 if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||\r
653 ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) {\r
654 goto BadCdb;\r
655\r
656 }\r
657 //\r
658 // if no cpb, make sure we have an old list\r
659 //\r
660 if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) {\r
661 goto BadCdb;\r
662 }\r
663 }\r
664 //\r
665 // if you want to enable anything, you got to have unicast\r
666 // and you have what you already enabled!\r
667 //\r
668 NewFilter = (UINT16) (NewFilter | (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter));\r
669\r
670 break;\r
671\r
672 case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:\r
673\r
674 //\r
675 // mcast list not expected, i.e. no cpb here!\r
676 //\r
677 if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {\r
678 goto BadCdb;\r
679 }\r
680\r
681 NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter);\r
682\r
683 break;\r
684\r
685 default:\r
686 goto BadCdb;\r
687 }\r
688\r
689 if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {\r
690 AdapterInfo->mcast_list.list_len = 0;\r
691 NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);\r
692 }\r
693\r
694 E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);\r
695\r
696JustRead:\r
697 //\r
698 // give the current mcast list\r
699 //\r
700 if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) {\r
701 //\r
702 // copy the mc list to db\r
703 //\r
704\r
705 DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;\r
706 ptr1 = (UINT8 *) (&DbPtr->MCastList[0]);\r
707\r
708 //\r
709 // DbPtr->mc_count = AdapterInfo->mcast_list.list_len;\r
710 //\r
711 copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH);\r
712\r
713 if (copy_len > CdbPtr->DBsize) {\r
714 copy_len = CdbPtr->DBsize;\r
715\r
716 }\r
717\r
718 ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]);\r
719 for (Index = 0; Index < copy_len; Index++) {\r
720 ptr1[Index] = ptr2[Index];\r
721 }\r
722 }\r
723 //\r
724 // give the stat flags here\r
725 //\r
726 if (AdapterInfo->Receive_Started) {\r
727 CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->Rx_Filter);\r
728\r
729 }\r
730\r
731 return ;\r
732\r
733BadCdb:\r
734 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
735 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
736}\r
737\r
738\r
739/**\r
740 This routine is used to get the current station and broadcast MAC addresses, and to change the\r
741 current station MAC address.\r
742\r
743 @param CdbPtr Pointer to the command descriptor block.\r
744 @param AdapterInfo Pointer to the NIC data structure information which\r
745 the UNDI driver is layering on..\r
746\r
747 @return None\r
748\r
749**/\r
750VOID\r
751UNDI_StnAddr (\r
752 IN PXE_CDB *CdbPtr,\r
753 IN NIC_DATA_INSTANCE *AdapterInfo\r
754 )\r
755{\r
756 PXE_CPB_STATION_ADDRESS *CpbPtr;\r
757 PXE_DB_STATION_ADDRESS *DbPtr;\r
758 UINT16 Index;\r
759\r
760 if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {\r
761 //\r
762 // configure the permanent address.\r
763 // change the AdapterInfo->CurrentNodeAddress field.\r
764 //\r
765 if (CompareMem (\r
766 &AdapterInfo->CurrentNodeAddress[0],\r
767 &AdapterInfo->PermNodeAddress[0],\r
768 PXE_MAC_LENGTH\r
769 ) != 0) {\r
770 for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
771 AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];\r
772 }\r
773\r
774 E100bSetupIAAddr (AdapterInfo);\r
775 }\r
776 }\r
777\r
778 if (CdbPtr->CPBaddr != (UINT64) 0) {\r
779 CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);\r
780 //\r
781 // configure the new address\r
782 //\r
783 for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
784 AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index];\r
785 }\r
786\r
787 E100bSetupIAAddr (AdapterInfo);\r
788 }\r
789\r
790 if (CdbPtr->DBaddr != (UINT64) 0) {\r
791 DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);\r
792 //\r
793 // fill it with the new values\r
794 //\r
795 for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
796 DbPtr->StationAddr[Index] = AdapterInfo->CurrentNodeAddress[Index];\r
797 DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index];\r
798 DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index];\r
799 }\r
800 }\r
801\r
802 return ;\r
803}\r
804\r
805\r
806/**\r
807 This routine is used to read and clear the NIC traffic statistics. This command is supported only\r
808 if the !PXE structure's Implementation flags say so.\r
809 Results will be parsed out in the following manner:\r
810 CdbPtr->DBaddr.Data[0] R Total Frames (Including frames with errors and dropped frames)\r
811 CdbPtr->DBaddr.Data[1] R Good Frames (All frames copied into receive buffer)\r
812 CdbPtr->DBaddr.Data[2] R Undersize Frames (Frames below minimum length for media <64 for ethernet)\r
813 CdbPtr->DBaddr.Data[4] R Dropped Frames (Frames that were dropped because receive buffers were full)\r
814 CdbPtr->DBaddr.Data[8] R CRC Error Frames (Frames with alignment or CRC errors)\r
815 CdbPtr->DBaddr.Data[A] T Total Frames (Including frames with errors and dropped frames)\r
816 CdbPtr->DBaddr.Data[B] T Good Frames (All frames copied into transmit buffer)\r
817 CdbPtr->DBaddr.Data[C] T Undersize Frames (Frames below minimum length for media <64 for ethernet)\r
818 CdbPtr->DBaddr.Data[E] T Dropped Frames (Frames that were dropped because of collisions)\r
819 CdbPtr->DBaddr.Data[14] T Total Collision Frames (Total collisions on this subnet)\r
820\r
821 @param CdbPtr Pointer to the command descriptor block.\r
822 @param AdapterInfo Pointer to the NIC data structure information which\r
823 the UNDI driver is layering on..\r
824\r
825 @return None\r
826\r
827**/\r
828VOID\r
829UNDI_Statistics (\r
830 IN PXE_CDB *CdbPtr,\r
831 IN NIC_DATA_INSTANCE *AdapterInfo\r
832 )\r
833{\r
834 if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {\r
835 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
836 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
837 return ;\r
838 }\r
839\r
840 if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {\r
841 //\r
842 // Reset the statistics\r
843 //\r
844 CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0);\r
845 } else {\r
846 CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize);\r
847 }\r
848\r
849 return ;\r
850}\r
851\r
852\r
853/**\r
854 This routine is used to translate a multicast IP address to a multicast MAC address.\r
855 This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP\r
856 address being appended to it. Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].\r
857\r
858 @param CdbPtr Pointer to the command descriptor block.\r
859 @param AdapterInfo Pointer to the NIC data structure information which\r
860 the UNDI driver is layering on..\r
861\r
862 @return None\r
863\r
864**/\r
865VOID\r
866UNDI_ip2mac (\r
867 IN PXE_CDB *CdbPtr,\r
868 IN NIC_DATA_INSTANCE *AdapterInfo\r
869 )\r
870{\r
871 PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;\r
872 PXE_DB_MCAST_IP_TO_MAC *DbPtr;\r
873 UINT8 *TmpPtr;\r
874\r
875 CpbPtr = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;\r
876 DbPtr = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;\r
877\r
878 if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {\r
879 //\r
880 // for now this is not supported\r
881 //\r
882 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
883 CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED;\r
884 return ;\r
885 }\r
886\r
887 TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4);\r
888 //\r
889 // check if the ip given is a mcast IP\r
890 //\r
891 if ((TmpPtr[0] & 0xF0) != 0xE0) {\r
892 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
893 CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB;\r
894 }\r
895 //\r
896 // take the last 23 bits in IP.\r
897 // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur\r
898 // casting the mac array (in the middle) to a UINT32 pointer and accessing\r
899 // the UINT32 content hung the system...\r
900 //\r
901 DbPtr->MAC[0] = 0x01;\r
902 DbPtr->MAC[1] = 0x00;\r
903 DbPtr->MAC[2] = 0x5e;\r
904 DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);\r
905 DbPtr->MAC[4] = (UINT8) TmpPtr[2];\r
906 DbPtr->MAC[5] = (UINT8) TmpPtr[3];\r
907\r
908 return ;\r
909}\r
910\r
911\r
912/**\r
913 This routine is used to read and write non-volatile storage on the NIC (if supported). The NVRAM\r
914 could be EEPROM, FLASH, or battery backed RAM.\r
915 This is an optional function according to the UNDI specification (or will be......)\r
916\r
917 @param CdbPtr Pointer to the command descriptor block.\r
918 @param AdapterInfo Pointer to the NIC data structure information which\r
919 the UNDI driver is layering on..\r
920\r
921 @return None\r
922\r
923**/\r
924VOID\r
925UNDI_NVData (\r
926 IN PXE_CDB *CdbPtr,\r
927 IN NIC_DATA_INSTANCE *AdapterInfo\r
928 )\r
929{\r
930 PXE_DB_NVDATA *DbPtr;\r
931 UINT16 Index;\r
932\r
933 if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {\r
934\r
935 if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) {\r
936 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
937 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
938 return ;\r
939 }\r
940\r
941 DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;\r
942\r
943 for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {\r
944 DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index];\r
945\r
946 }\r
947\r
948 } else {\r
949 //\r
950 // no write for now\r
951 //\r
952 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
953 CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED;\r
954 }\r
955\r
956 return ;\r
957}\r
958\r
959\r
960/**\r
961 This routine returns the current interrupt status and/or the transmitted buffer addresses.\r
962 If the current interrupt status is returned, pending interrupts will be acknowledged by this\r
963 command. Transmitted buffer addresses that are written to the DB are removed from the transmit\r
964 buffer queue.\r
965 Normally, this command would be polled with interrupts disabled.\r
966 The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].\r
967 The interrupt status is returned in CdbPtr->StatFlags.\r
968\r
969 @param CdbPtr Pointer to the command descriptor block.\r
970 @param AdapterInfo Pointer to the NIC data structure information which\r
971 the UNDI driver is layering on..\r
972\r
973 @return None\r
974\r
975**/\r
976VOID\r
977UNDI_Status (\r
978 IN PXE_CDB *CdbPtr,\r
979 IN NIC_DATA_INSTANCE *AdapterInfo\r
980 )\r
981{\r
982 PXE_DB_GET_STATUS *DbPtr;\r
983 PXE_DB_GET_STATUS TmpGetStatus;\r
984 UINT16 Index;\r
985 UINT16 Status;\r
986 UINT16 NumEntries;\r
987 RxFD *RxPtr;\r
988\r
989 //\r
990 // Fill in temporary GetStatus storage.\r
991 //\r
992 RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];\r
993\r
994 if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {\r
995 TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;\r
996 } else {\r
997 TmpGetStatus.RxFrameLen = 0;\r
998 }\r
999\r
1000 TmpGetStatus.reserved = 0;\r
1001\r
1002 //\r
1003 // Fill in size of next available receive packet and\r
1004 // reserved field in caller's DB storage.\r
1005 //\r
1006 DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;\r
1007\r
1008 if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {\r
1009 CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);\r
1010 } else {\r
1011 CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);\r
1012 }\r
1013\r
1014 //\r
1015 //\r
1016 //\r
1017 if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {\r
1018 //\r
1019 // DBsize of zero is invalid if Tx buffers are requested.\r
1020 //\r
1021 if (CdbPtr->DBsize == 0) {\r
1022 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1023 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
1024 return ;\r
1025 }\r
1026\r
1027 //\r
1028 // remember this b4 we overwrite\r
1029 //\r
1030 NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));\r
1031\r
1032 //\r
1033 // We already filled in 2 UINT32s.\r
1034 //\r
1035 CdbPtr->DBsize = sizeof (UINT32) * 2;\r
1036\r
1037 //\r
1038 // will claim any hanging free CBs\r
1039 //\r
1040 CheckCBList (AdapterInfo);\r
1041\r
1042 if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {\r
1043 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;\r
1044 } else {\r
1045 for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {\r
1046 if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {\r
1047 DbPtr->TxBuffer[Index] = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];\r
1048 AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);\r
1049 CdbPtr->DBsize += sizeof (UINT64);\r
1050 } else {\r
1051 break;\r
1052 }\r
1053 }\r
1054 }\r
1055\r
1056 if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {\r
1057 CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;\r
1058\r
1059 }\r
1060 //\r
1061 // check for a receive buffer and give it's size in db\r
1062 //\r
1063 }\r
1064 //\r
1065 //\r
1066 //\r
1067 if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {\r
1068\r
1069 Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);\r
1070 AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status);\r
1071\r
1072 //\r
1073 // acknoledge the interrupts\r
1074 //\r
1075 OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));\r
1076\r
1077 //\r
1078 // report all the outstanding interrupts\r
1079 //\r
1080 Status = AdapterInfo->Int_Status;\r
1081 if ((Status & SCB_STATUS_FR) != 0) {\r
1082 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;\r
1083 }\r
1084\r
1085 if ((Status & SCB_STATUS_SWI) != 0) {\r
1086 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;\r
1087 }\r
1088 }\r
1089\r
135ec2db 1090 //\r
1091 // Return current media status\r
1092 //\r
1093 if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {\r
1094 AdapterInfo->PhyAddress = 0xFF;\r
1095 AdapterInfo->CableDetect = 1;\r
1096\r
1097 if (!PhyDetect (AdapterInfo)) {\r
1098 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;\r
1099 }\r
1100 }\r
1101\r
51ebae6b 1102 return ;\r
1103}\r
1104\r
1105\r
1106/**\r
1107 This routine is used to fill media header(s) in transmit packet(s).\r
1108 Copies the MAC address into the media header whether it is dealing\r
1109 with fragmented or non-fragmented packets.\r
1110\r
1111 @param CdbPtr Pointer to the command descriptor block.\r
1112 @param AdapterInfo Pointer to the NIC data structure information which\r
1113 the UNDI driver is layering on..\r
1114\r
1115 @return None\r
1116\r
1117**/\r
1118VOID\r
1119UNDI_FillHeader (\r
1120 IN PXE_CDB *CdbPtr,\r
1121 IN NIC_DATA_INSTANCE *AdapterInfo\r
1122 )\r
1123{\r
1124 PXE_CPB_FILL_HEADER *Cpb;\r
1125 PXE_CPB_FILL_HEADER_FRAGMENTED *Cpbf;\r
1126 EtherHeader *MacHeader;\r
1127 UINTN Index;\r
1128\r
1129 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1130 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1131 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
1132 return ;\r
1133 }\r
1134\r
1135 if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {\r
1136 Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;\r
1137\r
1138 //\r
1139 // assume 1st fragment is big enough for the mac header\r
1140 //\r
1141 if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {\r
1142 //\r
1143 // no buffers given\r
1144 //\r
1145 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1146 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
1147 return ;\r
1148 }\r
1149\r
1150 MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr;\r
1151 //\r
1152 // we don't swap the protocol bytes\r
1153 //\r
1154 MacHeader->type = Cpbf->Protocol;\r
1155\r
1156 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {\r
1157 MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index];\r
1158 MacHeader->src_addr[Index] = Cpbf->SrcAddr[Index];\r
1159 }\r
1160 } else {\r
1161 Cpb = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;\r
1162\r
1163 MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader;\r
1164 //\r
1165 // we don't swap the protocol bytes\r
1166 //\r
1167 MacHeader->type = Cpb->Protocol;\r
1168\r
1169 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {\r
1170 MacHeader->dest_addr[Index] = Cpb->DestAddr[Index];\r
1171 MacHeader->src_addr[Index] = Cpb->SrcAddr[Index];\r
1172 }\r
1173 }\r
1174\r
1175 return ;\r
1176}\r
1177\r
1178\r
1179/**\r
1180 This routine is used to place a packet into the transmit queue. The data buffers given to\r
1181 this command are to be considered locked and the application or network driver loses\r
1182 ownership of these buffers and must not free or relocate them until the ownership returns.\r
1183 When the packets are transmitted, a transmit complete interrupt is generated (if interrupts\r
1184 are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status\r
1185 command.\r
1186 Some implementations and adapters support transmitting multiple packets with one transmit\r
1187 command. If this feature is supported, the transmit CPBs can be linked in one transmit\r
1188 command.\r
1189 All UNDIs support fragmented frames, now all network devices or protocols do. If a fragmented\r
1190 frame CPB is given to UNDI and the network device does not support fragmented frames\r
1191 (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer\r
1192 before transmitting.\r
1193\r
1194 @param CdbPtr Pointer to the command descriptor block.\r
1195 @param AdapterInfo Pointer to the NIC data structure information which\r
1196 the UNDI driver is layering on..\r
1197\r
1198 @return None\r
1199\r
1200**/\r
1201VOID\r
1202UNDI_Transmit (\r
1203 IN PXE_CDB *CdbPtr,\r
1204 IN NIC_DATA_INSTANCE *AdapterInfo\r
1205 )\r
1206{\r
1207\r
1208 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1209 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1210 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
1211 return ;\r
1212 }\r
1213\r
1214 CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags);\r
1215\r
1216 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
1217 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1218 }\r
1219\r
1220 return ;\r
1221}\r
1222\r
1223\r
1224/**\r
1225 When the network adapter has received a frame, this command is used to copy the frame\r
1226 into the driver/application storage location. Once a frame has been copied, it is\r
1227 removed from the receive queue.\r
1228\r
1229 @param CdbPtr Pointer to the command descriptor block.\r
1230 @param AdapterInfo Pointer to the NIC data structure information which\r
1231 the UNDI driver is layering on..\r
1232\r
1233 @return None\r
1234\r
1235**/\r
1236VOID\r
1237UNDI_Receive (\r
1238 IN PXE_CDB *CdbPtr,\r
1239 IN NIC_DATA_INSTANCE *AdapterInfo\r
1240 )\r
1241{\r
1242\r
1243 //\r
1244 // check if RU has started...\r
1245 //\r
1246 if (!AdapterInfo->Receive_Started) {\r
1247 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1248 CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;\r
1249 return ;\r
1250 }\r
1251\r
1252\r
1253 CdbPtr->StatCode = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr);\r
1254 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
1255 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1256\r
1257 }\r
1258\r
1259 return ;\r
1260}\r
1261\r
1262\r
1263\r
1264/**\r
1265 This is the main SW UNDI API entry using the newer nii protocol.\r
1266 The parameter passed in is a 64 bit flat model virtual\r
1267 address of the cdb. We then jump into the common routine for both old and\r
1268 new nii protocol entries.\r
1269\r
1270 @param CdbPtr Pointer to the command descriptor block.\r
1271 @param AdapterInfo Pointer to the NIC data structure information which\r
1272 the UNDI driver is layering on..\r
1273\r
1274 @return None\r
1275\r
1276**/\r
1277// TODO: cdb - add argument and description to function comment\r
1278VOID\r
1279UNDI_APIEntry_new (\r
1280 IN UINT64 cdb\r
1281 )\r
1282{\r
1283 PXE_CDB *CdbPtr;\r
1284 NIC_DATA_INSTANCE *AdapterInfo;\r
1285\r
1286 if (cdb == (UINT64) 0) {\r
1287 return ;\r
1288\r
1289 }\r
1290\r
1291 CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1292\r
1293 if (CdbPtr->IFnum >= pxe_31->IFcnt) {\r
1294 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1295 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
1296 return ;\r
1297 }\r
1298\r
1299 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1300 //\r
1301 // entering from older entry point\r
1302 //\r
1303 AdapterInfo->VersionFlag = 0x31;\r
1304 UNDI_APIEntry_Common (cdb);\r
1305}\r
1306\r
1307\r
1308/**\r
1309 This is the common routine for both old and new entry point procedures.\r
1310 The parameter passed in is a 64 bit flat model virtual\r
1311 address of the cdb. We then jump into the service routine pointed to by the\r
1312 Api_Table[OpCode].\r
1313\r
1314 @param CdbPtr Pointer to the command descriptor block.\r
1315 @param AdapterInfo Pointer to the NIC data structure information which\r
1316 the UNDI driver is layering on..\r
1317\r
1318 @return None\r
1319\r
1320**/\r
1321// TODO: cdb - add argument and description to function comment\r
1322VOID\r
1323UNDI_APIEntry_Common (\r
1324 IN UINT64 cdb\r
1325 )\r
1326{\r
1327 PXE_CDB *CdbPtr;\r
1328 NIC_DATA_INSTANCE *AdapterInfo;\r
1329 UNDI_CALL_TABLE *tab_ptr;\r
1330\r
1331 CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1332\r
1333 //\r
1334 // check the OPCODE range\r
1335 //\r
1336 if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||\r
1337 (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||\r
1338 (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||\r
1339 (CdbPtr->IFnum >= pxe_31->IFcnt) ) {\r
1340 goto badcdb;\r
1341\r
1342 }\r
1343\r
1344 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1345 if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {\r
1346 goto badcdb;\r
1347 }\r
1348 } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {\r
1349 goto badcdb;\r
1350 }\r
1351\r
1352 if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {\r
1353 if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {\r
1354 goto badcdb;\r
1355 }\r
1356 } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {\r
1357 goto badcdb;\r
1358 }\r
1359\r
1360 //\r
1361 // check if cpbsize and dbsize are as needed\r
1362 // check if opflags are as expected\r
1363 //\r
1364 tab_ptr = &api_table[CdbPtr->OpCode];\r
1365\r
1366 if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {\r
1367 goto badcdb;\r
1368 }\r
1369\r
1370 if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {\r
1371 goto badcdb;\r
1372 }\r
1373\r
1374 if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {\r
1375 goto badcdb;\r
1376\r
1377 }\r
1378\r
1379 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1380\r
1381 //\r
1382 // check if UNDI_State is valid for this call\r
1383 //\r
1384 if (tab_ptr->state != (UINT16) (-1)) {\r
1385 //\r
1386 // should atleast be started\r
1387 //\r
1388 if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {\r
1389 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1390 CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;\r
1391 return ;\r
1392 }\r
1393 //\r
1394 // check if it should be initialized\r
1395 //\r
1396 if (tab_ptr->state == 2) {\r
1397 if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
1398 CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;\r
1399 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1400 return ;\r
1401 }\r
1402 }\r
1403 }\r
1404 //\r
1405 // set the return variable for success case here\r
1406 //\r
1407 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;\r
1408 CdbPtr->StatCode = PXE_STATCODE_SUCCESS;\r
1409\r
1410 tab_ptr->api_ptr (CdbPtr, AdapterInfo);\r
1411 return ;\r
1412 //\r
1413 // %% AVL - check for command linking\r
1414 //\r
1415badcdb:\r
1416 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1417 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;\r
1418 return ;\r
1419}\r
1420\r
1421\r
1422/**\r
1423 When called with a null NicPtr, this routine decrements the number of NICs\r
1424 this UNDI is supporting and removes the NIC_DATA_POINTER from the array.\r
1425 Otherwise, it increments the number of NICs this UNDI is supported and\r
1426 updates the pxe.Fudge to ensure a proper check sum results.\r
1427\r
1428 @param NicPtr Pointer to the NIC data structure.\r
1429\r
1430 @return None\r
1431\r
1432**/\r
1433VOID\r
1434PxeUpdate (\r
1435 IN NIC_DATA_INSTANCE *NicPtr,\r
1436 IN PXE_SW_UNDI *PxePtr\r
1437 )\r
1438{\r
1439 if (NicPtr == NULL) {\r
1440 if (PxePtr->IFcnt > 0) {\r
1441 //\r
1442 // number of NICs this undi supports\r
1443 //\r
1444 PxePtr->IFcnt--;\r
1445 }\r
1446\r
1447 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));\r
1448 return ;\r
1449 }\r
1450\r
1451 //\r
1452 // number of NICs this undi supports\r
1453 //\r
1454 PxePtr->IFcnt++;\r
1455 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));\r
1456\r
1457 return ;\r
1458}\r
1459\r
1460\r
1461/**\r
1462 Initialize the !PXE structure\r
1463\r
1464 @param PxePtr Pointer to SW_UNDI data structure.\r
1465\r
1466 @retval EFI_SUCCESS This driver is added to Controller.\r
1467 @retval other This driver does not support this device.\r
1468\r
1469**/\r
1470VOID\r
1471PxeStructInit (\r
1472 IN PXE_SW_UNDI *PxePtr\r
1473 )\r
1474{\r
1475 //\r
1476 // Initialize the !PXE structure\r
1477 //\r
1478 PxePtr->Signature = PXE_ROMID_SIGNATURE;\r
1479 PxePtr->Len = sizeof (PXE_SW_UNDI);\r
1480 //\r
1481 // cksum\r
1482 //\r
1483 PxePtr->Fudge = 0;\r
1484 //\r
1485 // number of NICs this undi supports\r
1486 //\r
1487 PxePtr->IFcnt = 0;\r
1488 PxePtr->Rev = PXE_ROMID_REV;\r
1489 PxePtr->MajorVer = PXE_ROMID_MAJORVER;\r
1490 PxePtr->MinorVer = PXE_ROMID_MINORVER;\r
1491 PxePtr->reserved1 = 0;\r
1492\r
1493 PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |\r
1494 PXE_ROMID_IMP_FRAG_SUPPORTED |\r
1495 PXE_ROMID_IMP_CMD_LINK_SUPPORTED |\r
1496 PXE_ROMID_IMP_NVDATA_READ_ONLY |\r
1497 PXE_ROMID_IMP_STATION_ADDR_SETTABLE |\r
1498 PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |\r
1499 PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |\r
1500 PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |\r
1501 PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |\r
1502 PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |\r
1503 PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;\r
1504\r
1505 PxePtr->EntryPoint = (UINT64) (UINTN) UNDI_APIEntry_new;\r
1506 PxePtr->MinorVer = PXE_ROMID_MINORVER_31;\r
1507\r
1508 PxePtr->reserved2[0] = 0;\r
1509 PxePtr->reserved2[1] = 0;\r
1510 PxePtr->reserved2[2] = 0;\r
1511 PxePtr->BusCnt = 1;\r
1512 PxePtr->BusType[0] = PXE_BUSTYPE_PCI;\r
1513\r
1514 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));\r
1515}\r
1516\r