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