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