]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UndiRuntimeDxe/Decode.c
Import UndiRuntimeDxe.
[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 VOID
1294 UNDI_APIEntry_old (
1295 IN UINT64 cdb
1296 )
1297 /*++
1298
1299 Routine Description:
1300 This is the main SW UNDI API entry using the older nii protocol.
1301 The parameter passed in is a 64 bit flat model virtual
1302 address of the cdb. We then jump into the common routine for both old and
1303 new nii protocol entries.
1304
1305 Arguments:
1306 CdbPtr - Pointer to the command descriptor block.
1307 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
1308
1309 Returns:
1310 None
1311
1312 --*/
1313 // TODO: cdb - add argument and description to function comment
1314 {
1315 PXE_CDB *CdbPtr;
1316 NIC_DATA_INSTANCE *AdapterInfo;
1317
1318 if (cdb == (UINT64) 0) {
1319 return ;
1320
1321 }
1322
1323 CdbPtr = (PXE_CDB *) (UINTN) cdb;
1324
1325 if (CdbPtr->IFnum >= pxe->IFcnt) {
1326 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1327 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1328 return ;
1329 }
1330
1331 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1332
1333 //
1334 // entering from older entry point
1335 //
1336 AdapterInfo->VersionFlag = 0x30;
1337 UNDI_APIEntry_Common (cdb);
1338 }
1339
1340 VOID
1341 UNDI_APIEntry_new (
1342 IN UINT64 cdb
1343 )
1344 /*++
1345
1346 Routine Description:
1347 This is the main SW UNDI API entry using the newer nii protocol.
1348 The parameter passed in is a 64 bit flat model virtual
1349 address of the cdb. We then jump into the common routine for both old and
1350 new nii protocol entries.
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
1365 if (cdb == (UINT64) 0) {
1366 return ;
1367
1368 }
1369
1370 CdbPtr = (PXE_CDB *) (UINTN) cdb;
1371
1372 if (CdbPtr->IFnum >= pxe_31->IFcnt) {
1373 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1374 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1375 return ;
1376 }
1377
1378 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1379 //
1380 // entering from older entry point
1381 //
1382 AdapterInfo->VersionFlag = 0x31;
1383 UNDI_APIEntry_Common (cdb);
1384 }
1385
1386 VOID
1387 UNDI_APIEntry_Common (
1388 IN UINT64 cdb
1389 )
1390 /*++
1391
1392 Routine Description:
1393 This is the common routine for both old and new entry point procedures.
1394 The parameter passed in is a 64 bit flat model virtual
1395 address of the cdb. We then jump into the service routine pointed to by the
1396 Api_Table[OpCode].
1397
1398 Arguments:
1399 CdbPtr - Pointer to the command descriptor block.
1400 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
1401
1402 Returns:
1403 None
1404
1405 --*/
1406 // TODO: cdb - add argument and description to function comment
1407 {
1408 PXE_CDB *CdbPtr;
1409 NIC_DATA_INSTANCE *AdapterInfo;
1410 UNDI_CALL_TABLE *tab_ptr;
1411
1412 CdbPtr = (PXE_CDB *) (UINTN) cdb;
1413
1414 //
1415 // check the OPCODE range
1416 //
1417 if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||
1418 (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||
1419 (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
1420 (CdbPtr->IFnum >= pxe_31->IFcnt) ) {
1421 goto badcdb;
1422
1423 }
1424
1425 if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1426 if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {
1427 goto badcdb;
1428 }
1429 } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {
1430 goto badcdb;
1431 }
1432
1433 if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {
1434 if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {
1435 goto badcdb;
1436 }
1437 } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {
1438 goto badcdb;
1439 }
1440
1441 //
1442 // check if cpbsize and dbsize are as needed
1443 // check if opflags are as expected
1444 //
1445 tab_ptr = &api_table[CdbPtr->OpCode];
1446
1447 if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {
1448 goto badcdb;
1449 }
1450
1451 if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {
1452 goto badcdb;
1453 }
1454
1455 if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {
1456 goto badcdb;
1457
1458 }
1459
1460 AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1461
1462 //
1463 // check if UNDI_State is valid for this call
1464 //
1465 if (tab_ptr->state != (UINT16) (-1)) {
1466 //
1467 // should atleast be started
1468 //
1469 if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
1470 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1471 CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
1472 return ;
1473 }
1474 //
1475 // check if it should be initialized
1476 //
1477 if (tab_ptr->state == 2) {
1478 if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
1479 CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
1480 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1481 return ;
1482 }
1483 }
1484 }
1485 //
1486 // set the return variable for success case here
1487 //
1488 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
1489 CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
1490
1491 tab_ptr->api_ptr (CdbPtr, AdapterInfo);
1492 return ;
1493 //
1494 // %% AVL - check for command linking
1495 //
1496 badcdb:
1497 CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1498 CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
1499 return ;
1500 }
1501
1502 STATIC
1503 UINT8
1504 ChkSum (
1505 IN VOID *Buffer,
1506 IN UINT16 Len
1507 )
1508 /*++
1509
1510 Routine Description:
1511 This does an 8 bit check sum of the passed in buffer for Len bytes.
1512 This is primarily used to update the check sum in the SW UNDI header.
1513
1514 Arguments:
1515 Buffer - Pointer to the passed in buffer to check sum
1516 Len - Length of buffer to be check summed in bytes.
1517
1518 Returns:
1519 None
1520
1521 --*/
1522 {
1523 UINT8 Chksum;
1524 INT8 *Bp;
1525
1526 Chksum = 0;
1527 if ((Bp = Buffer) != NULL) {
1528 while (Len--) {
1529 Chksum = (UINT8) (Chksum +*Bp++);
1530
1531 }
1532
1533 }
1534
1535 return Chksum;
1536 }
1537
1538 VOID
1539 PxeUpdate (
1540 IN NIC_DATA_INSTANCE *NicPtr,
1541 IN PXE_SW_UNDI *PxePtr
1542 )
1543 /*++
1544
1545 Routine Description:
1546 When called with a null NicPtr, this routine decrements the number of NICs
1547 this UNDI is supporting and removes the NIC_DATA_POINTER from the array.
1548 Otherwise, it increments the number of NICs this UNDI is supported and
1549 updates the pxe.Fudge to ensure a proper check sum results.
1550
1551 Arguments:
1552 NicPtr - Pointer to the NIC data structure.
1553
1554 Returns:
1555 None
1556
1557 --*/
1558 // TODO: PxePtr - add argument and description to function comment
1559 {
1560 if (NicPtr == NULL) {
1561 if (PxePtr->IFcnt > 0) {
1562 //
1563 // number of NICs this undi supports
1564 //
1565 PxePtr->IFcnt--;
1566 }
1567
1568 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));
1569 return ;
1570 }
1571
1572 //
1573 // number of NICs this undi supports
1574 //
1575 PxePtr->IFcnt++;
1576 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));
1577
1578 return ;
1579 }
1580
1581 VOID
1582 PxeStructInit (
1583 IN PXE_SW_UNDI *PxePtr,
1584 IN UINTN VersionFlag
1585 )
1586 /*++
1587
1588 Routine Description:
1589 Initialize the !PXE structure
1590
1591 Arguments:
1592 RemainingDevicePath - Not used, always produce all possible children.
1593
1594 Returns:
1595 EFI_SUCCESS - This driver is added to Controller.
1596 other - This driver does not support this device.
1597
1598 --*/
1599 // TODO: PxePtr - add argument and description to function comment
1600 // TODO: VersionFlag - add argument and description to function comment
1601 {
1602 //
1603 // Initialize the !PXE structure
1604 //
1605 PxePtr->Signature = PXE_ROMID_SIGNATURE;
1606 PxePtr->Len = sizeof (PXE_SW_UNDI);
1607 //
1608 // cksum
1609 //
1610 PxePtr->Fudge = 0;
1611 //
1612 // number of NICs this undi supports
1613 //
1614 PxePtr->IFcnt = 0;
1615 PxePtr->Rev = PXE_ROMID_REV;
1616 PxePtr->MajorVer = PXE_ROMID_MAJORVER;
1617 PxePtr->MinorVer = PXE_ROMID_MINORVER;
1618 PxePtr->reserved1 = 0;
1619
1620 PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
1621 PXE_ROMID_IMP_FRAG_SUPPORTED |
1622 PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
1623 PXE_ROMID_IMP_NVDATA_READ_ONLY |
1624 PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
1625 PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
1626 PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
1627 PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
1628 PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |
1629 PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |
1630 PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;
1631
1632 if (VersionFlag == 0x30) {
1633 PxePtr->EntryPoint = (UINT64) UNDI_APIEntry_old;
1634 } else {
1635 PxePtr->EntryPoint = (UINT64) UNDI_APIEntry_new;
1636 PxePtr->MinorVer = PXE_ROMID_MINORVER_31;
1637 }
1638
1639 PxePtr->reserved2[0] = 0;
1640 PxePtr->reserved2[1] = 0;
1641 PxePtr->reserved2[2] = 0;
1642 PxePtr->BusCnt = 1;
1643 PxePtr->BusType[0] = PXE_BUSTYPE_PCI;
1644
1645 PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));
1646 }
1647