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