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