add UndiRuntimeDxe from MdeModulePkg to OptionRomPkg.
[mirror_edk2.git] / OptionRomPkg / UndiRuntimeDxe / Decode.c
1 /** @file
2 Provides the basic UNID functions.
3
4 Copyright (c) 2006 - 2007, 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 OpFlags = CdbPtr->OpFlags;
561 NewFilter = (UINT16) (OpFlags & 0x1F);
562
563 switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
564 case PXE_OPFLAGS_RECEIVE_FILTER_READ:
565
566 //
567 // not expecting a cpb, not expecting any filter bits
568 //
569 if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {
570 goto BadCdb;
571
572 }
573
574 if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
575 goto JustRead;
576
577 }
578
579 NewFilter = (UINT16) (NewFilter | AdapterInfo->Rx_Filter);
580 //
581 // all other flags are ignored except mcast_reset
582 //
583 break;
584
585 case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
586 //
587 // there should be atleast one other filter bit set.
588 //
589 if (NewFilter == 0) {
590 //
591 // nothing to enable
592 //
593 goto BadCdb;
594 }
595
596 if (CdbPtr->CPBsize != 0) {
597 //
598 // this must be a multicast address list!
599 // don't accept the list unless selective_mcast is set
600 // don't accept confusing mcast settings with this
601 //
602 if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
603 ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
604 ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
605 ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) {
606 goto BadCdb;
607 }
608
609 MacAddr = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr));
610 MacCount = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR);
611
612 for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) {
613 if (MacAddr[0] != 0x01 || MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) {
614 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
615 CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB;
616 return ;
617 }
618 }
619 }
620
621 //
622 // check selective mcast case enable case
623 //
624 if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
625 if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
626 ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) {
627 goto BadCdb;
628
629 }
630 //
631 // if no cpb, make sure we have an old list
632 //
633 if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) {
634 goto BadCdb;
635 }
636 }
637 //
638 // if you want to enable anything, you got to have unicast
639 // and you have what you already enabled!
640 //
641 NewFilter = (UINT16) (NewFilter | (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter));
642
643 break;
644
645 case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
646
647 //
648 // mcast list not expected, i.e. no cpb here!
649 //
650 if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {
651 goto BadCdb;
652 }
653
654 NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter);
655
656 break;
657
658 default:
659 goto BadCdb;
660 }
661
662 if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {
663 AdapterInfo->mcast_list.list_len = 0;
664 NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
665 }
666
667 E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);
668
669 JustRead:
670 //
671 // give the current mcast list
672 //
673 if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) {
674 //
675 // copy the mc list to db
676 //
677
678 DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;
679 ptr1 = (UINT8 *) (&DbPtr->MCastList[0]);
680
681 //
682 // DbPtr->mc_count = AdapterInfo->mcast_list.list_len;
683 //
684 copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH);
685
686 if (copy_len > CdbPtr->DBsize) {
687 copy_len = CdbPtr->DBsize;
688
689 }
690
691 ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]);
692 for (Index = 0; Index < copy_len; Index++) {
693 ptr1[Index] = ptr2[Index];
694 }
695 }
696 //
697 // give the stat flags here
698 //
699 if (AdapterInfo->Receive_Started) {
700 CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->Rx_Filter);
701
702 }
703
704 return ;
705
706 BadCdb:
707 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
708 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
709 }
710
711
712 /**
713 This routine is used to get the current station and broadcast MAC addresses, and to change the
714 current station MAC address.
715
716 @param CdbPtr Pointer to the command descriptor block.
717 @param AdapterInfo Pointer to the NIC data structure information which
718 the UNDI driver is layering on..
719
720 @return None
721
722 **/
723 VOID
724 UNDI_StnAddr (
725 IN PXE_CDB *CdbPtr,
726 IN NIC_DATA_INSTANCE *AdapterInfo
727 )
728 {
729 PXE_CPB_STATION_ADDRESS *CpbPtr;
730 PXE_DB_STATION_ADDRESS *DbPtr;
731 UINT16 Index;
732
733 if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
734 //
735 // configure the permanent address.
736 // change the AdapterInfo->CurrentNodeAddress field.
737 //
738 if (CompareMem (
739 &AdapterInfo->CurrentNodeAddress[0],
740 &AdapterInfo->PermNodeAddress[0],
741 PXE_MAC_LENGTH
742 ) != 0) {
743 for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
744 AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];
745 }
746
747 E100bSetupIAAddr (AdapterInfo);
748 }
749 }
750
751 if (CdbPtr->CPBaddr != (UINT64) 0) {
752 CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);
753 //
754 // configure the new address
755 //
756 for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
757 AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index];
758 }
759
760 E100bSetupIAAddr (AdapterInfo);
761 }
762
763 if (CdbPtr->DBaddr != (UINT64) 0) {
764 DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);
765 //
766 // fill it with the new values
767 //
768 for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
769 DbPtr->StationAddr[Index] = AdapterInfo->CurrentNodeAddress[Index];
770 DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index];
771 DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index];
772 }
773 }
774
775 return ;
776 }
777
778
779 /**
780 This routine is used to read and clear the NIC traffic statistics. This command is supported only
781 if the !PXE structure's Implementation flags say so.
782 Results will be parsed out in the following manner:
783 CdbPtr->DBaddr.Data[0] R Total Frames (Including frames with errors and dropped frames)
784 CdbPtr->DBaddr.Data[1] R Good Frames (All frames copied into receive buffer)
785 CdbPtr->DBaddr.Data[2] R Undersize Frames (Frames below minimum length for media <64 for ethernet)
786 CdbPtr->DBaddr.Data[4] R Dropped Frames (Frames that were dropped because receive buffers were full)
787 CdbPtr->DBaddr.Data[8] R CRC Error Frames (Frames with alignment or CRC errors)
788 CdbPtr->DBaddr.Data[A] T Total Frames (Including frames with errors and dropped frames)
789 CdbPtr->DBaddr.Data[B] T Good Frames (All frames copied into transmit buffer)
790 CdbPtr->DBaddr.Data[C] T Undersize Frames (Frames below minimum length for media <64 for ethernet)
791 CdbPtr->DBaddr.Data[E] T Dropped Frames (Frames that were dropped because of collisions)
792 CdbPtr->DBaddr.Data[14] T Total Collision Frames (Total collisions on this subnet)
793
794 @param CdbPtr Pointer to the command descriptor block.
795 @param AdapterInfo Pointer to the NIC data structure information which
796 the UNDI driver is layering on..
797
798 @return None
799
800 **/
801 VOID
802 UNDI_Statistics (
803 IN PXE_CDB *CdbPtr,
804 IN NIC_DATA_INSTANCE *AdapterInfo
805 )
806 {
807 if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {
808 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
809 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
810 return ;
811 }
812
813 if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {
814 //
815 // Reset the statistics
816 //
817 CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0);
818 } else {
819 CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize);
820 }
821
822 return ;
823 }
824
825
826 /**
827 This routine is used to translate a multicast IP address to a multicast MAC address.
828 This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP
829 address being appended to it. Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].
830
831 @param CdbPtr Pointer to the command descriptor block.
832 @param AdapterInfo Pointer to the NIC data structure information which
833 the UNDI driver is layering on..
834
835 @return None
836
837 **/
838 VOID
839 UNDI_ip2mac (
840 IN PXE_CDB *CdbPtr,
841 IN NIC_DATA_INSTANCE *AdapterInfo
842 )
843 {
844 PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;
845 PXE_DB_MCAST_IP_TO_MAC *DbPtr;
846 UINT8 *TmpPtr;
847
848 CpbPtr = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;
849 DbPtr = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;
850
851 if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
852 //
853 // for now this is not supported
854 //
855 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
856 CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED;
857 return ;
858 }
859
860 TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4);
861 //
862 // check if the ip given is a mcast IP
863 //
864 if ((TmpPtr[0] & 0xF0) != 0xE0) {
865 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
866 CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB;
867 }
868 //
869 // take the last 23 bits in IP.
870 // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur
871 // casting the mac array (in the middle) to a UINT32 pointer and accessing
872 // the UINT32 content hung the system...
873 //
874 DbPtr->MAC[0] = 0x01;
875 DbPtr->MAC[1] = 0x00;
876 DbPtr->MAC[2] = 0x5e;
877 DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);
878 DbPtr->MAC[4] = (UINT8) TmpPtr[2];
879 DbPtr->MAC[5] = (UINT8) TmpPtr[3];
880
881 return ;
882 }
883
884
885 /**
886 This routine is used to read and write non-volatile storage on the NIC (if supported). The NVRAM
887 could be EEPROM, FLASH, or battery backed RAM.
888 This is an optional function according to the UNDI specification (or will be......)
889
890 @param CdbPtr Pointer to the command descriptor block.
891 @param AdapterInfo Pointer to the NIC data structure information which
892 the UNDI driver is layering on..
893
894 @return None
895
896 **/
897 VOID
898 UNDI_NVData (
899 IN PXE_CDB *CdbPtr,
900 IN NIC_DATA_INSTANCE *AdapterInfo
901 )
902 {
903 PXE_DB_NVDATA *DbPtr;
904 UINT16 Index;
905
906 if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {
907
908 if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) {
909 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
910 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
911 return ;
912 }
913
914 DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;
915
916 for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {
917 DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index];
918
919 }
920
921 } else {
922 //
923 // no write for now
924 //
925 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
926 CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED;
927 }
928
929 return ;
930 }
931
932
933 /**
934 This routine returns the current interrupt status and/or the transmitted buffer addresses.
935 If the current interrupt status is returned, pending interrupts will be acknowledged by this
936 command. Transmitted buffer addresses that are written to the DB are removed from the transmit
937 buffer queue.
938 Normally, this command would be polled with interrupts disabled.
939 The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].
940 The interrupt status is returned in CdbPtr->StatFlags.
941
942 @param CdbPtr Pointer to the command descriptor block.
943 @param AdapterInfo Pointer to the NIC data structure information which
944 the UNDI driver is layering on..
945
946 @return None
947
948 **/
949 VOID
950 UNDI_Status (
951 IN PXE_CDB *CdbPtr,
952 IN NIC_DATA_INSTANCE *AdapterInfo
953 )
954 {
955 PXE_DB_GET_STATUS *DbPtr;
956 PXE_DB_GET_STATUS TmpGetStatus;
957 UINT16 Index;
958 UINT16 Status;
959 UINT16 NumEntries;
960 RxFD *RxPtr;
961
962 //
963 // Fill in temporary GetStatus storage.
964 //
965 RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
966
967 if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {
968 TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;
969 } else {
970 TmpGetStatus.RxFrameLen = 0;
971 }
972
973 TmpGetStatus.reserved = 0;
974
975 //
976 // Fill in size of next available receive packet and
977 // reserved field in caller's DB storage.
978 //
979 DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;
980
981 if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {
982 CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);
983 } else {
984 CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);
985 }
986
987 //
988 //
989 //
990 if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
991 //
992 // DBsize of zero is invalid if Tx buffers are requested.
993 //
994 if (CdbPtr->DBsize == 0) {
995 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
996 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
997 return ;
998 }
999
1000 //
1001 // remember this b4 we overwrite
1002 //
1003 NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));
1004
1005 //
1006 // We already filled in 2 UINT32s.
1007 //
1008 CdbPtr->DBsize = sizeof (UINT32) * 2;
1009
1010 //
1011 // will claim any hanging free CBs
1012 //
1013 CheckCBList (AdapterInfo);
1014
1015 if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {
1016 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;
1017 } else {
1018 for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
1019 if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {
1020 DbPtr->TxBuffer[Index] = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];
1021 AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);
1022 CdbPtr->DBsize += sizeof (UINT64);
1023 } else {
1024 break;
1025 }
1026 }
1027 }
1028
1029 if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {
1030 CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;
1031
1032 }
1033 //
1034 // check for a receive buffer and give it's size in db
1035 //
1036 }
1037 //
1038 //
1039 //
1040 if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
1041
1042 Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
1043 AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status);
1044
1045 //
1046 // acknoledge the interrupts
1047 //
1048 OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));
1049
1050 //
1051 // report all the outstanding interrupts
1052 //
1053 Status = AdapterInfo->Int_Status;
1054 if ((Status & SCB_STATUS_FR) != 0) {
1055 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
1056 }
1057
1058 if ((Status & SCB_STATUS_SWI) != 0) {
1059 CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;
1060 }
1061 }
1062
1063 return ;
1064 }
1065
1066
1067 /**
1068 This routine is used to fill media header(s) in transmit packet(s).
1069 Copies the MAC address into the media header whether it is dealing
1070 with fragmented or non-fragmented packets.
1071
1072 @param CdbPtr Pointer to the command descriptor block.
1073 @param AdapterInfo Pointer to the NIC data structure information which
1074 the UNDI driver is layering on..
1075
1076 @return None
1077
1078 **/
1079 VOID
1080 UNDI_FillHeader (
1081 IN PXE_CDB *CdbPtr,
1082 IN NIC_DATA_INSTANCE *AdapterInfo
1083 )
1084 {
1085 PXE_CPB_FILL_HEADER *Cpb;
1086 PXE_CPB_FILL_HEADER_FRAGMENTED *Cpbf;
1087 EtherHeader *MacHeader;
1088 UINTN Index;
1089
1090 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1091 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1092 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1093 return ;
1094 }
1095
1096 if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
1097 Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;
1098
1099 //
1100 // assume 1st fragment is big enough for the mac header
1101 //
1102 if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
1103 //
1104 // no buffers given
1105 //
1106 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1107 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1108 return ;
1109 }
1110
1111 MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr;
1112 //
1113 // we don't swap the protocol bytes
1114 //
1115 MacHeader->type = Cpbf->Protocol;
1116
1117 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1118 MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index];
1119 MacHeader->src_addr[Index] = Cpbf->SrcAddr[Index];
1120 }
1121 } else {
1122 Cpb = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;
1123
1124 MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader;
1125 //
1126 // we don't swap the protocol bytes
1127 //
1128 MacHeader->type = Cpb->Protocol;
1129
1130 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1131 MacHeader->dest_addr[Index] = Cpb->DestAddr[Index];
1132 MacHeader->src_addr[Index] = Cpb->SrcAddr[Index];
1133 }
1134 }
1135
1136 return ;
1137 }
1138
1139
1140 /**
1141 This routine is used to place a packet into the transmit queue. The data buffers given to
1142 this command are to be considered locked and the application or network driver loses
1143 ownership of these buffers and must not free or relocate them until the ownership returns.
1144 When the packets are transmitted, a transmit complete interrupt is generated (if interrupts
1145 are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status
1146 command.
1147 Some implementations and adapters support transmitting multiple packets with one transmit
1148 command. If this feature is supported, the transmit CPBs can be linked in one transmit
1149 command.
1150 All UNDIs support fragmented frames, now all network devices or protocols do. If a fragmented
1151 frame CPB is given to UNDI and the network device does not support fragmented frames
1152 (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer
1153 before transmitting.
1154
1155 @param CdbPtr Pointer to the command descriptor block.
1156 @param AdapterInfo Pointer to the NIC data structure information which
1157 the UNDI driver is layering on..
1158
1159 @return None
1160
1161 **/
1162 VOID
1163 UNDI_Transmit (
1164 IN PXE_CDB *CdbPtr,
1165 IN NIC_DATA_INSTANCE *AdapterInfo
1166 )
1167 {
1168
1169 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1170 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1171 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1172 return ;
1173 }
1174
1175 CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags);
1176
1177 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
1178 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1179 }
1180
1181 return ;
1182 }
1183
1184
1185 /**
1186 When the network adapter has received a frame, this command is used to copy the frame
1187 into the driver/application storage location. Once a frame has been copied, it is
1188 removed from the receive queue.
1189
1190 @param CdbPtr Pointer to the command descriptor block.
1191 @param AdapterInfo Pointer to the NIC data structure information which
1192 the UNDI driver is layering on..
1193
1194 @return None
1195
1196 **/
1197 VOID
1198 UNDI_Receive (
1199 IN PXE_CDB *CdbPtr,
1200 IN NIC_DATA_INSTANCE *AdapterInfo
1201 )
1202 {
1203
1204 //
1205 // check if RU has started...
1206 //
1207 if (!AdapterInfo->Receive_Started) {
1208 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1209 CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
1210 return ;
1211 }
1212
1213
1214 CdbPtr->StatCode = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr);
1215 if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
1216 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1217
1218 }
1219
1220 return ;
1221 }
1222
1223
1224
1225 /**
1226 This is the main SW UNDI API entry using the newer nii protocol.
1227 The parameter passed in is a 64 bit flat model virtual
1228 address of the cdb. We then jump into the common routine for both old and
1229 new nii protocol entries.
1230
1231 @param CdbPtr Pointer to the command descriptor block.
1232 @param AdapterInfo Pointer to the NIC data structure information which
1233 the UNDI driver is layering on..
1234
1235 @return None
1236
1237 **/
1238 // TODO: cdb - add argument and description to function comment
1239 VOID
1240 UNDI_APIEntry_new (
1241 IN UINT64 cdb
1242 )
1243 {
1244 PXE_CDB *CdbPtr;
1245 NIC_DATA_INSTANCE *AdapterInfo;
1246
1247 if (cdb == (UINT64) 0) {
1248 return ;
1249
1250 }
1251
1252 CdbPtr = (PXE_CDB *) (UINTN) cdb;
1253
1254 if (CdbPtr->IFnum >= pxe_31->IFcnt) {
1255 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1256 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1257 return ;
1258 }
1259
1260 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1261 //
1262 // entering from older entry point
1263 //
1264 AdapterInfo->VersionFlag = 0x31;
1265 UNDI_APIEntry_Common (cdb);
1266 }
1267
1268
1269 /**
1270 This is the common routine for both old and new entry point procedures.
1271 The parameter passed in is a 64 bit flat model virtual
1272 address of the cdb. We then jump into the service routine pointed to by the
1273 Api_Table[OpCode].
1274
1275 @param CdbPtr Pointer to the command descriptor block.
1276 @param AdapterInfo Pointer to the NIC data structure information which
1277 the UNDI driver is layering on..
1278
1279 @return None
1280
1281 **/
1282 // TODO: cdb - add argument and description to function comment
1283 VOID
1284 UNDI_APIEntry_Common (
1285 IN UINT64 cdb
1286 )
1287 {
1288 PXE_CDB *CdbPtr;
1289 NIC_DATA_INSTANCE *AdapterInfo;
1290 UNDI_CALL_TABLE *tab_ptr;
1291
1292 CdbPtr = (PXE_CDB *) (UINTN) cdb;
1293
1294 //
1295 // check the OPCODE range
1296 //
1297 if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||
1298 (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||
1299 (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
1300 (CdbPtr->IFnum >= pxe_31->IFcnt) ) {
1301 goto badcdb;
1302
1303 }
1304
1305 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1306 if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {
1307 goto badcdb;
1308 }
1309 } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {
1310 goto badcdb;
1311 }
1312
1313 if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {
1314 if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {
1315 goto badcdb;
1316 }
1317 } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {
1318 goto badcdb;
1319 }
1320
1321 //
1322 // check if cpbsize and dbsize are as needed
1323 // check if opflags are as expected
1324 //
1325 tab_ptr = &api_table[CdbPtr->OpCode];
1326
1327 if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {
1328 goto badcdb;
1329 }
1330
1331 if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {
1332 goto badcdb;
1333 }
1334
1335 if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {
1336 goto badcdb;
1337
1338 }
1339
1340 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1341
1342 //
1343 // check if UNDI_State is valid for this call
1344 //
1345 if (tab_ptr->state != (UINT16) (-1)) {
1346 //
1347 // should atleast be started
1348 //
1349 if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
1350 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1351 CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
1352 return ;
1353 }
1354 //
1355 // check if it should be initialized
1356 //
1357 if (tab_ptr->state == 2) {
1358 if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
1359 CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
1360 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1361 return ;
1362 }
1363 }
1364 }
1365 //
1366 // set the return variable for success case here
1367 //
1368 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
1369 CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
1370
1371 tab_ptr->api_ptr (CdbPtr, AdapterInfo);
1372 return ;
1373 //
1374 // %% AVL - check for command linking
1375 //
1376 badcdb:
1377 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1378 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1379 return ;
1380 }
1381
1382
1383 /**
1384 When called with a null NicPtr, this routine decrements the number of NICs
1385 this UNDI is supporting and removes the NIC_DATA_POINTER from the array.
1386 Otherwise, it increments the number of NICs this UNDI is supported and
1387 updates the pxe.Fudge to ensure a proper check sum results.
1388
1389 @param NicPtr Pointer to the NIC data structure.
1390
1391 @return None
1392
1393 **/
1394 VOID
1395 PxeUpdate (
1396 IN NIC_DATA_INSTANCE *NicPtr,
1397 IN PXE_SW_UNDI *PxePtr
1398 )
1399 {
1400 if (NicPtr == NULL) {
1401 if (PxePtr->IFcnt > 0) {
1402 //
1403 // number of NICs this undi supports
1404 //
1405 PxePtr->IFcnt--;
1406 }
1407
1408 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));
1409 return ;
1410 }
1411
1412 //
1413 // number of NICs this undi supports
1414 //
1415 PxePtr->IFcnt++;
1416 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));
1417
1418 return ;
1419 }
1420
1421
1422 /**
1423 Initialize the !PXE structure
1424
1425 @param PxePtr Pointer to SW_UNDI data structure.
1426
1427 @retval EFI_SUCCESS This driver is added to Controller.
1428 @retval other This driver does not support this device.
1429
1430 **/
1431 VOID
1432 PxeStructInit (
1433 IN PXE_SW_UNDI *PxePtr
1434 )
1435 {
1436 //
1437 // Initialize the !PXE structure
1438 //
1439 PxePtr->Signature = PXE_ROMID_SIGNATURE;
1440 PxePtr->Len = sizeof (PXE_SW_UNDI);
1441 //
1442 // cksum
1443 //
1444 PxePtr->Fudge = 0;
1445 //
1446 // number of NICs this undi supports
1447 //
1448 PxePtr->IFcnt = 0;
1449 PxePtr->Rev = PXE_ROMID_REV;
1450 PxePtr->MajorVer = PXE_ROMID_MAJORVER;
1451 PxePtr->MinorVer = PXE_ROMID_MINORVER;
1452 PxePtr->reserved1 = 0;
1453
1454 PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
1455 PXE_ROMID_IMP_FRAG_SUPPORTED |
1456 PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
1457 PXE_ROMID_IMP_NVDATA_READ_ONLY |
1458 PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
1459 PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
1460 PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
1461 PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
1462 PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |
1463 PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |
1464 PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;
1465
1466 PxePtr->EntryPoint = (UINT64) (UINTN) UNDI_APIEntry_new;
1467 PxePtr->MinorVer = PXE_ROMID_MINORVER_31;
1468
1469 PxePtr->reserved2[0] = 0;
1470 PxePtr->reserved2[1] = 0;
1471 PxePtr->reserved2[2] = 0;
1472 PxePtr->BusCnt = 1;
1473 PxePtr->BusType[0] = PXE_BUSTYPE_PCI;
1474
1475 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));
1476 }
1477