bca0add42c6bfcfc053d468cfa7d1ea5390f2ba1
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Undi / RuntimeDxe / E100b.c
1 /*++
2
3 Copyright (c) 2006, 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
14
15 E100B.C
16
17 Abstract:
18
19
20 Revision History
21
22 --*/
23
24 #include "undi32.h"
25
26 static UINT8 basic_config_cmd[22] = {
27 22, 0x08,
28 0, 0,
29 0, (UINT8)0x80,
30 0x32, 0x03,
31 1, 0,
32 0x2E, 0,
33 0x60, 0,
34 (UINT8)0xf2, 0x48,
35 0, 0x40,
36 (UINT8)0xf2, (UINT8)0x80, // 0x40=Force full-duplex
37 0x3f, 0x05,
38 };
39
40 //
41 // How to wait for the command unit to accept a command.
42 // Typically this takes 0 ticks.
43 //
44 #define wait_for_cmd_done(cmd_ioaddr) \
45 { \
46 INT16 wait_count = 2000; \
47 while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait_count >= 0) \
48 DelayIt (AdapterInfo, 10); \
49 if (wait_count == 0) \
50 DelayIt (AdapterInfo, 50); \
51 }
52
53 UINT8
54 InByte (
55 IN NIC_DATA_INSTANCE *AdapterInfo,
56 IN UINT32 Port
57 )
58 /*++
59
60 Routine Description:
61 This function calls the MemIo callback to read a byte from the device's
62 address space
63 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
64 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
65 to make undi3.0 a special case
66
67 Arguments:
68 Port - Which port to read from.
69
70 Returns:
71 Results - The data read from the port.
72
73 --*/
74 // TODO: AdapterInfo - add argument and description to function comment
75 {
76 UINT8 Results;
77
78 (*AdapterInfo->Mem_Io) (
79 AdapterInfo->Unique_ID,
80 PXE_MEM_READ,
81 1,
82 (UINT64)Port,
83 (UINT64) (UINTN) &Results
84 );
85 return Results;
86 }
87
88 UINT16
89 InWord (
90 IN NIC_DATA_INSTANCE *AdapterInfo,
91 IN UINT32 Port
92 )
93 /*++
94
95 Routine Description:
96 This function calls the MemIo callback to read a word from the device's
97 address space
98 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
99 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
100 to make undi3.0 a special case
101
102 Arguments:
103 Port - Which port to read from.
104
105 Returns:
106 Results - The data read from the port.
107
108 --*/
109 // TODO: AdapterInfo - add argument and description to function comment
110 {
111 UINT16 Results;
112
113 (*AdapterInfo->Mem_Io) (
114 AdapterInfo->Unique_ID,
115 PXE_MEM_READ,
116 2,
117 (UINT64)Port,
118 (UINT64)(UINTN)&Results
119 );
120 return Results;
121 }
122
123 UINT32
124 InLong (
125 IN NIC_DATA_INSTANCE *AdapterInfo,
126 IN UINT32 Port
127 )
128 /*++
129
130 Routine Description:
131 This function calls the MemIo callback to read a dword from the device's
132 address space
133 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
134 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
135 to make undi3.0 a special case
136
137 Arguments:
138 Port - Which port to read from.
139
140 Returns:
141 Results - The data read from the port.
142
143 --*/
144 // TODO: AdapterInfo - add argument and description to function comment
145 {
146 UINT32 Results;
147
148 (*AdapterInfo->Mem_Io) (
149 AdapterInfo->Unique_ID,
150 PXE_MEM_READ,
151 4,
152 (UINT64)Port,
153 (UINT64)(UINTN)&Results
154 );
155 return Results;
156 }
157
158 VOID
159 OutByte (
160 IN NIC_DATA_INSTANCE *AdapterInfo,
161 IN UINT8 Data,
162 IN UINT32 Port
163 )
164 /*++
165
166 Routine Description:
167 This function calls the MemIo callback to write a byte from the device's
168 address space
169 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
170 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
171 to make undi3.0 a special case
172
173 Arguments:
174 Data - Data to write to Port.
175 Port - Which port to write to.
176
177 Returns:
178 none
179
180 --*/
181 // TODO: AdapterInfo - add argument and description to function comment
182 {
183 UINT8 Val;
184
185 Val = Data;
186 (*AdapterInfo->Mem_Io) (
187 AdapterInfo->Unique_ID,
188 PXE_MEM_WRITE,
189 1,
190 (UINT64)Port,
191 (UINT64)(UINTN)(UINTN)&Val
192 );
193 return ;
194 }
195
196 VOID
197 OutWord (
198 IN NIC_DATA_INSTANCE *AdapterInfo,
199 IN UINT16 Data,
200 IN UINT32 Port
201 )
202 /*++
203
204 Routine Description:
205 This function calls the MemIo callback to write a word from the device's
206 address space
207 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
208 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
209 to make undi3.0 a special case
210
211 Arguments:
212 Data - Data to write to Port.
213 Port - Which port to write to.
214
215 Returns:
216 none
217
218 --*/
219 // TODO: AdapterInfo - add argument and description to function comment
220 {
221 UINT16 Val;
222
223 Val = Data;
224 (*AdapterInfo->Mem_Io) (
225 AdapterInfo->Unique_ID,
226 PXE_MEM_WRITE,
227 2,
228 (UINT64)Port,
229 (UINT64)(UINTN)&Val
230 );
231 return ;
232 }
233
234 VOID
235 OutLong (
236 IN NIC_DATA_INSTANCE *AdapterInfo,
237 IN UINT32 Data,
238 IN UINT32 Port
239 )
240 /*++
241
242 Routine Description:
243 This function calls the MemIo callback to write a dword from the device's
244 address space
245 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
246 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
247 to make undi3.0 a special case
248
249 Arguments:
250 Data - Data to write to Port.
251 Port - Which port to write to.
252
253 Returns:
254 none
255
256 --*/
257 // TODO: AdapterInfo - add argument and description to function comment
258 {
259 UINT32 Val;
260
261 Val = Data;
262 (*AdapterInfo->Mem_Io) (
263 AdapterInfo->Unique_ID,
264 PXE_MEM_WRITE,
265 4,
266 (UINT64)Port,
267 (UINT64)(UINTN)&Val
268 );
269 return ;
270 }
271
272 STATIC
273 UINTN
274 MapIt (
275 IN NIC_DATA_INSTANCE *AdapterInfo,
276 IN UINT64 MemAddr,
277 IN UINT32 Size,
278 IN UINT32 Direction,
279 OUT UINT64 MappedAddr
280 )
281 /*++
282
283 Routine Description:
284
285 TODO: Add function description
286
287 Arguments:
288
289 AdapterInfo - TODO: add argument description
290 MemAddr - TODO: add argument description
291 Size - TODO: add argument description
292 Direction - TODO: add argument description
293 MappedAddr - TODO: add argument description
294
295 Returns:
296
297 TODO: add return values
298
299 --*/
300 {
301 UINT64 *PhyAddr;
302
303 PhyAddr = (UINT64 *) (UINTN) MappedAddr;
304 //
305 // mapping is different for theold and new NII protocols
306 //
307 if (AdapterInfo->VersionFlag == 0x30) {
308 if (AdapterInfo->Virt2Phys_30 == (VOID *) NULL) {
309 *PhyAddr = (UINT64) AdapterInfo->MemoryPtr;
310 } else {
311 (*AdapterInfo->Virt2Phys_30) (MemAddr, (UINT64) (UINTN) PhyAddr);
312 }
313
314 if (*PhyAddr > FOUR_GIGABYTE) {
315 return PXE_STATCODE_INVALID_PARAMETER;
316 }
317 } else {
318 if (AdapterInfo->Map_Mem == (VOID *) NULL) {
319 //
320 // this UNDI cannot handle addresses beyond 4 GB without a map routine
321 //
322 if (MemAddr > FOUR_GIGABYTE) {
323 return PXE_STATCODE_INVALID_PARAMETER;
324 } else {
325 *PhyAddr = MemAddr;
326 }
327 } else {
328 (*AdapterInfo->Map_Mem) (
329 AdapterInfo->Unique_ID,
330 MemAddr,
331 Size,
332 Direction,
333 MappedAddr
334 );
335 }
336 }
337
338 return PXE_STATCODE_SUCCESS;
339 }
340
341 STATIC
342 VOID
343 UnMapIt (
344 IN NIC_DATA_INSTANCE *AdapterInfo,
345 IN UINT64 MemAddr,
346 IN UINT32 Size,
347 IN UINT32 Direction,
348 IN UINT64 MappedAddr
349 )
350 /*++
351
352 Routine Description:
353
354 TODO: Add function description
355
356 Arguments:
357
358 AdapterInfo - TODO: add argument description
359 MemAddr - TODO: add argument description
360 Size - TODO: add argument description
361 Direction - TODO: add argument description
362 MappedAddr - TODO: add argument description
363
364 Returns:
365
366 TODO: add return values
367
368 --*/
369 {
370 if (AdapterInfo->VersionFlag > 0x30) {
371 //
372 // no mapping service
373 //
374 if (AdapterInfo->UnMap_Mem != (VOID *) NULL) {
375 (*AdapterInfo->UnMap_Mem) (
376 AdapterInfo->Unique_ID,
377 MemAddr,
378 Size,
379 Direction,
380 MappedAddr
381 );
382
383 }
384 }
385
386 return ;
387 }
388
389 STATIC
390 VOID
391 DelayIt (
392 IN NIC_DATA_INSTANCE *AdapterInfo,
393 UINT16 MicroSeconds
394 )
395 /*++
396
397 Routine Description:
398
399 Arguments:
400 AdapterInfo - Pointer to the NIC data structure information
401 which the UNDI driver is layering on..
402
403 Returns:
404
405 --*/
406 // TODO: MicroSeconds - add argument and description to function comment
407 {
408 if (AdapterInfo->VersionFlag == 0x30) {
409 (*AdapterInfo->Delay_30) (MicroSeconds);
410 } else {
411 (*AdapterInfo->Delay) (AdapterInfo->Unique_ID, MicroSeconds);
412 }
413 }
414
415 STATIC
416 VOID
417 BlockIt (
418 IN NIC_DATA_INSTANCE *AdapterInfo,
419 UINT32 flag
420 )
421 /*++
422
423 Routine Description:
424
425 Arguments:
426 AdapterInfo - Pointer to the NIC data structure information
427 which the UNDI driver is layering on..
428
429 Returns:
430
431 --*/
432 // TODO: flag - add argument and description to function comment
433 {
434 if (AdapterInfo->VersionFlag == 0x30) {
435 (*AdapterInfo->Block_30) (flag);
436 } else {
437 (*AdapterInfo->Block) (AdapterInfo->Unique_ID, flag);
438 }
439 }
440
441 STATIC
442 UINT8
443 Load_Base_Regs (
444 NIC_DATA_INSTANCE *AdapterInfo
445 )
446 /*++
447
448 Routine Description:
449
450 TODO: Add function description
451
452 Arguments:
453
454 AdapterInfo - TODO: add argument description
455
456 Returns:
457
458 TODO: add return values
459
460 --*/
461 {
462 //
463 // we will use the linear (flat) memory model and fill our base registers
464 // with 0's so that the entire physical address is our offset
465 //
466 //
467 // we reset the statistics totals here because this is where we are loading stats addr
468 //
469 AdapterInfo->RxTotals = 0;
470 AdapterInfo->TxTotals = 0;
471
472 //
473 // Load the statistics block address.
474 //
475 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
476 OutLong (AdapterInfo, (UINT32) AdapterInfo->stat_phy_addr, AdapterInfo->ioaddr + SCBPointer);
477 OutByte (AdapterInfo, CU_STATSADDR, AdapterInfo->ioaddr + SCBCmd);
478 AdapterInfo->statistics->done_marker = 0;
479
480 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
481 OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);
482 OutByte (AdapterInfo, RX_ADDR_LOAD, AdapterInfo->ioaddr + SCBCmd);
483
484 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
485 OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);
486 OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);
487
488 return 0;
489 }
490
491 STATIC
492 UINT8
493 IssueCB (
494 NIC_DATA_INSTANCE *AdapterInfo,
495 TxCB *cmd_ptr
496 )
497 /*++
498
499 Routine Description:
500
501 TODO: Add function description
502
503 Arguments:
504
505 AdapterInfo - TODO: add argument description
506 cmd_ptr - TODO: add argument description
507
508 Returns:
509
510 TODO: add return values
511
512 --*/
513 {
514 UINT16 status;
515
516 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
517
518 //
519 // read the CU status, if it is idle, write the address of cb_ptr
520 // in the scbpointer and issue a cu_start,
521 // if it is suspended, remove the suspend bit in the previous command
522 // block and issue a resume
523 //
524 // Ensure that the CU Active Status bit is not on from previous CBs.
525 //
526 status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
527
528 //
529 // Skip acknowledging the interrupt if it is not already set
530 //
531
532 //
533 // ack only the cna the integer
534 //
535 if ((status & SCB_STATUS_CNA) != 0) {
536 OutWord (AdapterInfo, SCB_STATUS_CNA, AdapterInfo->ioaddr + SCBStatus);
537
538 }
539
540 if ((status & SCB_STATUS_CU_MASK) == SCB_STATUS_CU_IDLE) {
541 //
542 // give a cu_start
543 //
544 OutLong (AdapterInfo, cmd_ptr->PhysTCBAddress, AdapterInfo->ioaddr + SCBPointer);
545 OutByte (AdapterInfo, CU_START, AdapterInfo->ioaddr + SCBCmd);
546 } else {
547 //
548 // either active or suspended, give a resume
549 //
550
551 cmd_ptr->PrevTCBVirtualLinkPtr->cb_header.command &= ~(CmdSuspend | CmdIntr);
552 OutByte (AdapterInfo, CU_RESUME, AdapterInfo->ioaddr + SCBCmd);
553 }
554
555 return 0;
556 }
557
558 STATIC
559 UINT8
560 Configure (
561 NIC_DATA_INSTANCE *AdapterInfo
562 )
563 /*++
564
565 Routine Description:
566
567 TODO: Add function description
568
569 Arguments:
570
571 AdapterInfo - TODO: add argument description
572
573 Returns:
574
575 TODO: add return values
576
577 --*/
578 {
579 //
580 // all command blocks are of TxCB format
581 //
582 TxCB *cmd_ptr;
583 UINT8 *data_ptr;
584 volatile INT16 Index;
585 UINT8 my_filter;
586
587 cmd_ptr = GetFreeCB (AdapterInfo);
588 data_ptr = (UINT8 *) (&cmd_ptr->PhysTBDArrayAddres);
589
590 //
591 // start the config data right after the command header
592 //
593 for (Index = 0; Index < sizeof (basic_config_cmd); Index++) {
594 data_ptr[Index] = basic_config_cmd[Index];
595 }
596
597 my_filter = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) ? 1 : 0);
598 my_filter = (UINT8) ((my_filter | (AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) ? 0 : 2));
599
600 data_ptr[15] = (UINT8) (data_ptr[15] | my_filter);
601 data_ptr[19] = (UINT8) (AdapterInfo->Duplex ? 0xC0 : 0x80);
602 data_ptr[21] = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) ? 0x0D : 0x05);
603
604 //
605 // check if we have to use the AUI port instead
606 //
607 if ((AdapterInfo->PhyRecord[0] & 0x8000) != 0) {
608 data_ptr[15] |= 0x80;
609 data_ptr[8] = 0;
610 }
611
612 BlockIt (AdapterInfo, TRUE);
613 cmd_ptr->cb_header.command = CmdSuspend | CmdConfigure;
614
615 IssueCB (AdapterInfo, cmd_ptr);
616 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
617
618 BlockIt (AdapterInfo, FALSE);
619
620 CommandWaitForCompletion (cmd_ptr, AdapterInfo);
621
622 //
623 // restore the cb values for tx
624 //
625 cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
626 cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
627 //
628 // fields beyond the immediatedata are assumed to be safe
629 // add the CB to the free list again
630 //
631 SetFreeCB (AdapterInfo, cmd_ptr);
632 return 0;
633 }
634
635 UINT8
636 E100bSetupIAAddr (
637 NIC_DATA_INSTANCE *AdapterInfo
638 )
639 /*++
640
641 Routine Description:
642
643 TODO: Add function description
644
645 Arguments:
646
647 AdapterInfo - TODO: add argument description
648
649 Returns:
650
651 TODO: add return values
652
653 --*/
654 {
655 //
656 // all command blocks are of TxCB format
657 //
658 TxCB *cmd_ptr;
659 UINT16 *data_ptr;
660 UINT16 *eaddrs;
661
662 eaddrs = (UINT16 *) AdapterInfo->CurrentNodeAddress;
663
664 cmd_ptr = GetFreeCB (AdapterInfo);
665 data_ptr = (UINT16 *) (&cmd_ptr->PhysTBDArrayAddres);
666
667 //
668 // AVOID a bug (?!) here by marking the command already completed.
669 //
670 cmd_ptr->cb_header.command = (CmdSuspend | CmdIASetup);
671 cmd_ptr->cb_header.status = 0;
672 data_ptr[0] = eaddrs[0];
673 data_ptr[1] = eaddrs[1];
674 data_ptr[2] = eaddrs[2];
675
676 BlockIt (AdapterInfo, TRUE);
677 IssueCB (AdapterInfo, cmd_ptr);
678 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
679 BlockIt (AdapterInfo, FALSE);
680
681 CommandWaitForCompletion (cmd_ptr, AdapterInfo);
682
683 //
684 // restore the cb values for tx
685 //
686 cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
687 cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
688 //
689 // fields beyond the immediatedata are assumed to be safe
690 // add the CB to the free list again
691 //
692 SetFreeCB (AdapterInfo, cmd_ptr);
693 return 0;
694 }
695
696 STATIC
697 VOID
698 StopRU (
699 IN NIC_DATA_INSTANCE *AdapterInfo
700 )
701 /*++
702
703 Routine Description:
704 Instructs the NIC to stop receiving packets.
705
706 Arguments:
707 AdapterInfo - Pointer to the NIC data structure information
708 which the UNDI driver is layering on..
709 Returns:
710
711 --*/
712 {
713 if (AdapterInfo->Receive_Started) {
714
715 //
716 // Todo: verify that we must wait for previous command completion.
717 //
718 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
719
720 //
721 // Disable interrupts, and stop the chip's Rx process.
722 //
723 OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
724 OutWord (AdapterInfo, INT_MASK | RX_ABORT, AdapterInfo->ioaddr + SCBCmd);
725
726 AdapterInfo->Receive_Started = FALSE;
727 }
728
729 return ;
730 }
731
732 STATIC
733 INT8
734 StartRU (
735 NIC_DATA_INSTANCE *AdapterInfo
736 )
737 /*++
738
739 Routine Description:
740 Instructs the NIC to start receiving packets.
741
742 Arguments:
743 AdapterInfo - Pointer to the NIC data structure information
744 which the UNDI driver is layering on..
745 Returns:
746 0 - Successful
747 -1 - Already Started
748 --*/
749 {
750
751 if (AdapterInfo->Receive_Started) {
752 //
753 // already started
754 //
755 return -1;
756 }
757
758 AdapterInfo->cur_rx_ind = 0;
759 AdapterInfo->Int_Status = 0;
760
761 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
762
763 OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);
764 OutByte (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);
765
766 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
767
768 AdapterInfo->Receive_Started = TRUE;
769 return 0;
770 }
771
772 UINTN
773 E100bInit (
774 IN NIC_DATA_INSTANCE *AdapterInfo
775 )
776 /*++
777
778 Routine Description:
779 Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.
780
781 Arguments:
782 AdapterInfo - Pointer to the NIC data structure information
783 which the UNDI driver is layering on..
784
785 Returns:
786 0 - Successful
787 PXE_STATCODE_NOT_ENOUGH_MEMORY - Insufficient length of locked memory
788 other - Failure initializing chip
789 --*/
790 {
791 PCI_CONFIG_HEADER *CfgHdr;
792 UINTN stat;
793 UINTN rx_size;
794 UINTN tx_size;
795
796 if (AdapterInfo->MemoryLength < MEMORY_NEEDED) {
797 return PXE_STATCODE_NOT_ENOUGH_MEMORY;
798 }
799
800 stat = MapIt (
801 AdapterInfo,
802 AdapterInfo->MemoryPtr,
803 AdapterInfo->MemoryLength,
804 TO_AND_FROM_DEVICE,
805 (UINT64)(UINTN) &AdapterInfo->Mapped_MemoryPtr
806 );
807
808 if (stat != 0) {
809 return stat;
810 }
811
812 CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
813
814 //
815 // fill in the ioaddr, int... from the config space
816 //
817 AdapterInfo->int_num = CfgHdr->int_line;
818
819 //
820 // we don't need to validate integer number, what if they don't want to assign one?
821 // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)
822 // return PXE_STATCODE_DEVICE_FAILURE;
823 //
824 AdapterInfo->ioaddr = 0;
825 AdapterInfo->VendorID = CfgHdr->VendorID;
826 AdapterInfo->DeviceID = CfgHdr->DeviceID;
827 AdapterInfo->RevID = CfgHdr->RevID;
828 AdapterInfo->SubVendorID = CfgHdr->SubVendorID;
829 AdapterInfo->SubSystemID = CfgHdr->SubSystemID;
830 AdapterInfo->flash_addr = 0;
831
832 //
833 // Read the station address EEPROM before doing the reset.
834 // Perhaps this should even be done before accepting the device,
835 // then we wouldn't have a device name with which to report the error.
836 //
837 if (E100bReadEepromAndStationAddress (AdapterInfo) != 0) {
838 return PXE_STATCODE_DEVICE_FAILURE;
839
840 }
841 //
842 // ## calculate the buffer #s depending on memory given
843 // ## calculate the rx and tx ring pointers
844 //
845
846 AdapterInfo->TxBufCnt = TX_BUFFER_COUNT;
847 AdapterInfo->RxBufCnt = RX_BUFFER_COUNT;
848 rx_size = (AdapterInfo->RxBufCnt * sizeof (RxFD));
849 tx_size = (AdapterInfo->TxBufCnt * sizeof (TxCB));
850 AdapterInfo->rx_ring = (RxFD *) (UINTN) (AdapterInfo->MemoryPtr);
851 AdapterInfo->tx_ring = (TxCB *) (UINTN) (AdapterInfo->MemoryPtr + rx_size);
852 AdapterInfo->statistics = (struct speedo_stats *) (UINTN) (AdapterInfo->MemoryPtr + rx_size + tx_size);
853
854 AdapterInfo->rx_phy_addr = AdapterInfo->Mapped_MemoryPtr;
855 AdapterInfo->tx_phy_addr = AdapterInfo->Mapped_MemoryPtr + rx_size;
856 AdapterInfo->stat_phy_addr = AdapterInfo->tx_phy_addr + tx_size;
857
858 //
859 // auto detect.
860 //
861 AdapterInfo->PhyAddress = 0xFF;
862 AdapterInfo->Rx_Filter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
863 AdapterInfo->Receive_Started = FALSE;
864 AdapterInfo->mcast_list.list_len = 0;
865 return InitializeChip (AdapterInfo);
866 }
867
868 UINT8
869 E100bSetInterruptState (
870 IN NIC_DATA_INSTANCE *AdapterInfo
871 )
872 /*++
873
874 Routine Description:
875 Sets the interrupt state for the NIC.
876
877 Arguments:
878 AdapterInfo - Pointer to the NIC data structure information
879 which the UNDI driver is layering on..
880 Returns:
881 0 - Successful
882 --*/
883 {
884 //
885 // don't set receive interrupt if receiver is disabled...
886 //
887 UINT16 cmd_word;
888
889 if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {
890 cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd);
891 cmd_word &= ~INT_MASK;
892 OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd);
893 } else {
894 //
895 // disable ints, should not be given for SW Int.
896 //
897 OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
898 }
899
900 if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_SOFTWARE) != 0) {
901 //
902 // reset the bit in our mask, it is only one time!!
903 //
904 AdapterInfo->int_mask &= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE);
905 cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd);
906 cmd_word |= DRVR_INT;
907 OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd);
908 }
909
910 return 0;
911 }
912 //
913 // we are not going to disable broadcast for the WOL's sake!
914 //
915 UINTN
916 E100bSetfilter (
917 NIC_DATA_INSTANCE *AdapterInfo,
918 UINT16 new_filter,
919 UINT64 cpb,
920 UINT32 cpbsize
921 )
922 /*++
923
924 Routine Description:
925 Instructs the NIC to start receiving packets.
926
927 Arguments:
928 AdapterInfo - Pointer to the NIC data structure information
929 which the UNDI driver is layering on..
930 new_filter -
931 cpb -
932 cpbsize -
933
934 Returns:
935 0 - Successful
936 -1 - Already Started
937 --*/
938 {
939 PXE_CPB_RECEIVE_FILTERS *mc_list = (PXE_CPB_RECEIVE_FILTERS *) (UINTN)cpb;
940 UINT16 cfg_flt;
941 UINT16 old_filter;
942 UINT16 Index;
943 UINT16 Index2;
944 UINT16 mc_count;
945 TxCB *cmd_ptr;
946 struct MC_CB_STRUCT *data_ptr;
947 UINT16 mc_byte_cnt;
948
949 old_filter = AdapterInfo->Rx_Filter;
950
951 //
952 // only these bits need a change in the configuration
953 // actually change in bcast requires configure but we ignore that change
954 //
955 cfg_flt = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
956 PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
957
958 if ((old_filter & cfg_flt) != (new_filter & cfg_flt)) {
959 XmitWaitForCompletion (AdapterInfo);
960
961 if (AdapterInfo->Receive_Started) {
962 StopRU (AdapterInfo);
963 }
964
965 AdapterInfo->Rx_Filter = (UINT8) (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST);
966 Configure (AdapterInfo);
967 }
968
969 //
970 // check if mcast setting changed
971 //
972 if ( ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=
973 (old_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) ) ||
974 (mc_list != NULL) ) {
975
976
977 if (mc_list != NULL) {
978 mc_count = AdapterInfo->mcast_list.list_len = (UINT16) (cpbsize / PXE_MAC_LENGTH);
979
980 for (Index = 0; (Index < mc_count && Index < MAX_MCAST_ADDRESS_CNT); Index++) {
981 for (Index2 = 0; Index2 < PXE_MAC_LENGTH; Index2++) {
982 AdapterInfo->mcast_list.mc_list[Index][Index2] = mc_list->MCastList[Index][Index2];
983 }
984 }
985 }
986
987 //
988 // are we setting the list or resetting??
989 //
990 if ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
991 //
992 // we are setting a new list!
993 //
994 mc_count = AdapterInfo->mcast_list.list_len;
995 //
996 // count should be the actual # of bytes in the list
997 // so multiply this with 6
998 //
999 mc_byte_cnt = (UINT16) ((mc_count << 2) + (mc_count << 1));
1000 AdapterInfo->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
1001 } else {
1002 //
1003 // disabling the list in the NIC.
1004 //
1005 mc_byte_cnt = mc_count = 0;
1006 AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
1007 }
1008
1009 //
1010 // before issuing any new command!
1011 //
1012 XmitWaitForCompletion (AdapterInfo);
1013
1014 if (AdapterInfo->Receive_Started) {
1015 StopRU (AdapterInfo);
1016
1017 }
1018
1019 cmd_ptr = GetFreeCB (AdapterInfo);
1020 if (cmd_ptr == NULL) {
1021 return PXE_STATCODE_QUEUE_FULL;
1022 }
1023 //
1024 // fill the command structure and issue
1025 //
1026 data_ptr = (struct MC_CB_STRUCT *) (&cmd_ptr->PhysTBDArrayAddres);
1027 //
1028 // first 2 bytes are the count;
1029 //
1030 data_ptr->count = mc_byte_cnt;
1031 for (Index = 0; Index < mc_count; Index++) {
1032 for (Index2 = 0; Index2 < PXE_HWADDR_LEN_ETHER; Index2++) {
1033 data_ptr->m_list[Index][Index2] = AdapterInfo->mcast_list.mc_list[Index][Index2];
1034 }
1035 }
1036
1037 cmd_ptr->cb_header.command = CmdSuspend | CmdMulticastList;
1038 cmd_ptr->cb_header.status = 0;
1039
1040 BlockIt (AdapterInfo, TRUE);
1041 IssueCB (AdapterInfo, cmd_ptr);
1042 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
1043
1044 BlockIt (AdapterInfo, FALSE);
1045
1046 CommandWaitForCompletion (cmd_ptr, AdapterInfo);
1047
1048 cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
1049 cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
1050 //
1051 // fields beyond the immediatedata are assumed to be safe
1052 // add the CB to the free list again
1053 //
1054 SetFreeCB (AdapterInfo, cmd_ptr);
1055 }
1056
1057 if (new_filter != 0) {
1058 //
1059 // enable unicast and start the RU
1060 //
1061 AdapterInfo->Rx_Filter = (UINT8) (AdapterInfo->Rx_Filter | (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST));
1062 StartRU (AdapterInfo);
1063 } else {
1064 //
1065 // may be disabling everything!
1066 //
1067 if (AdapterInfo->Receive_Started) {
1068 StopRU (AdapterInfo);
1069 }
1070
1071 AdapterInfo->Rx_Filter |= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);
1072 }
1073
1074 return 0;
1075 }
1076
1077 UINTN
1078 E100bTransmit (
1079 NIC_DATA_INSTANCE *AdapterInfo,
1080 UINT64 cpb,
1081 UINT16 opflags
1082 )
1083 /*++
1084
1085 Routine Description:
1086
1087 TODO: Add function description
1088
1089 Arguments:
1090
1091 AdapterInfo - TODO: add argument description
1092 cpb - TODO: add argument description
1093 opflags - TODO: add argument description
1094
1095 Returns:
1096
1097 TODO: add return values
1098
1099 --*/
1100 {
1101 PXE_CPB_TRANSMIT_FRAGMENTS *tx_ptr_f;
1102 PXE_CPB_TRANSMIT *tx_ptr_1;
1103 TxCB *tcb_ptr;
1104 UINT64 Tmp_ptr;
1105 UINTN stat;
1106 INT32 Index;
1107 UINT16 wait_sec;
1108
1109 tx_ptr_1 = (PXE_CPB_TRANSMIT *) (UINTN) cpb;
1110 tx_ptr_f = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb;
1111
1112 //
1113 // stop reentrancy here
1114 //
1115 if (AdapterInfo->in_transmit) {
1116 return PXE_STATCODE_BUSY;
1117
1118 }
1119
1120 AdapterInfo->in_transmit = TRUE;
1121
1122 //
1123 // Prevent interrupts from changing the Tx ring from underneath us.
1124 //
1125 // Calculate the Tx descriptor entry.
1126 //
1127 if ((tcb_ptr = GetFreeCB (AdapterInfo)) == NULL) {
1128 AdapterInfo->in_transmit = FALSE;
1129 return PXE_STATCODE_QUEUE_FULL;
1130 }
1131
1132 AdapterInfo->TxTotals++;
1133
1134 tcb_ptr->cb_header.command = (CmdSuspend | CmdTx | CmdTxFlex);
1135 tcb_ptr->cb_header.status = 0;
1136
1137 //
1138 // no immediate data, set EOF in the ByteCount
1139 //
1140 tcb_ptr->ByteCount = 0x8000;
1141
1142 //
1143 // The data region is always in one buffer descriptor, Tx FIFO
1144 // threshold of 256.
1145 // 82557 multiplies the threashold value by 8, so give 256/8
1146 //
1147 tcb_ptr->Threshold = 32;
1148 if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
1149
1150 if (tx_ptr_f->FragCnt > MAX_XMIT_FRAGMENTS) {
1151 SetFreeCB (AdapterInfo, tcb_ptr);
1152 AdapterInfo->in_transmit = FALSE;
1153 return PXE_STATCODE_INVALID_PARAMETER;
1154 }
1155
1156 tcb_ptr->TBDCount = (UINT8) tx_ptr_f->FragCnt;
1157
1158 for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {
1159 stat = MapIt (
1160 AdapterInfo,
1161 tx_ptr_f->FragDesc[Index].FragAddr,
1162 tx_ptr_f->FragDesc[Index].FragLen,
1163 TO_DEVICE,
1164 (UINT64)(UINTN) &Tmp_ptr
1165 );
1166 if (stat != 0) {
1167 SetFreeCB (AdapterInfo, tcb_ptr);
1168 AdapterInfo->in_transmit = FALSE;
1169 return PXE_STATCODE_INVALID_PARAMETER;
1170 }
1171
1172 tcb_ptr->TBDArray[Index].phys_buf_addr = (UINT32) Tmp_ptr;
1173 tcb_ptr->TBDArray[Index].buf_len = tx_ptr_f->FragDesc[Index].FragLen;
1174 }
1175
1176 tcb_ptr->free_data_ptr = tx_ptr_f->FragDesc[0].FragAddr;
1177
1178 } else {
1179 //
1180 // non fragmented case
1181 //
1182 tcb_ptr->TBDCount = 1;
1183 stat = MapIt (
1184 AdapterInfo,
1185 tx_ptr_1->FrameAddr,
1186 tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,
1187 TO_DEVICE,
1188 (UINT64)(UINTN) &Tmp_ptr
1189 );
1190 if (stat != 0) {
1191 SetFreeCB (AdapterInfo, tcb_ptr);
1192 AdapterInfo->in_transmit = FALSE;
1193 return PXE_STATCODE_INVALID_PARAMETER;
1194 }
1195
1196 tcb_ptr->TBDArray[0].phys_buf_addr = (UINT32) (Tmp_ptr);
1197 tcb_ptr->TBDArray[0].buf_len = tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen;
1198 tcb_ptr->free_data_ptr = tx_ptr_1->FrameAddr;
1199 }
1200
1201 //
1202 // must wait for previous command completion only if it was a non-transmit
1203 //
1204 BlockIt (AdapterInfo, TRUE);
1205 IssueCB (AdapterInfo, tcb_ptr);
1206 BlockIt (AdapterInfo, FALSE);
1207
1208 //
1209 // see if we need to wait for completion here
1210 //
1211 if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) {
1212 //
1213 // don't wait for more than 1 second!!!
1214 //
1215 wait_sec = 1000;
1216 while (tcb_ptr->cb_header.status == 0) {
1217 DelayIt (AdapterInfo, 10);
1218 wait_sec--;
1219 if (wait_sec == 0) {
1220 break;
1221 }
1222 }
1223 //
1224 // we need to un-map any mapped buffers here
1225 //
1226 if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
1227
1228 for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {
1229 Tmp_ptr = tcb_ptr->TBDArray[Index].phys_buf_addr;
1230 UnMapIt (
1231 AdapterInfo,
1232 tx_ptr_f->FragDesc[Index].FragAddr,
1233 tx_ptr_f->FragDesc[Index].FragLen,
1234 TO_DEVICE,
1235 (UINT64) Tmp_ptr
1236 );
1237 }
1238 } else {
1239 Tmp_ptr = tcb_ptr->TBDArray[0].phys_buf_addr;
1240 UnMapIt (
1241 AdapterInfo,
1242 tx_ptr_1->FrameAddr,
1243 tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,
1244 TO_DEVICE,
1245 (UINT64) Tmp_ptr
1246 );
1247 }
1248
1249 if (tcb_ptr->cb_header.status == 0) {
1250 SetFreeCB (AdapterInfo, tcb_ptr);
1251 AdapterInfo->in_transmit = FALSE;
1252 return PXE_STATCODE_DEVICE_FAILURE;
1253 }
1254
1255 SetFreeCB (AdapterInfo, tcb_ptr);
1256 }
1257 //
1258 // CB will be set free later in get_status (or when we run out of xmit buffers
1259 //
1260 AdapterInfo->in_transmit = FALSE;
1261
1262 return 0;
1263 }
1264
1265 UINTN
1266 E100bReceive (
1267 NIC_DATA_INSTANCE *AdapterInfo,
1268 UINT64 cpb,
1269 UINT64 db
1270 )
1271 /*++
1272
1273 Routine Description:
1274
1275 TODO: Add function description
1276
1277 Arguments:
1278
1279 AdapterInfo - TODO: add argument description
1280 cpb - TODO: add argument description
1281 db - TODO: add argument description
1282
1283 Returns:
1284
1285 TODO: add return values
1286
1287 --*/
1288 {
1289 PXE_CPB_RECEIVE *rx_cpbptr;
1290 PXE_DB_RECEIVE *rx_dbptr;
1291 RxFD *rx_ptr;
1292 INT32 status;
1293 INT32 Index;
1294 UINT16 pkt_len;
1295 UINT16 ret_code;
1296 PXE_FRAME_TYPE pkt_type;
1297 UINT16 Tmp_len;
1298 EtherHeader *hdr_ptr;
1299 ret_code = PXE_STATCODE_NO_DATA;
1300 pkt_type = PXE_FRAME_TYPE_NONE;
1301 status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
1302 AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | status);
1303 //
1304 // acknoledge the interrupts
1305 //
1306 OutWord (AdapterInfo, (UINT16) (status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));
1307
1308 //
1309 // include the prev ints as well
1310 //
1311 status = AdapterInfo->Int_Status;
1312 rx_cpbptr = (PXE_CPB_RECEIVE *) (UINTN) cpb;
1313 rx_dbptr = (PXE_DB_RECEIVE *) (UINTN) db;
1314
1315 rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
1316
1317 //
1318 // be in a loop just in case (we may drop a pkt)
1319 //
1320 while ((status = rx_ptr->cb_header.status) & RX_COMPLETE) {
1321
1322 AdapterInfo->RxTotals++;
1323 //
1324 // If we own the next entry, it's a new packet. Send it up.
1325 //
1326 if (rx_ptr->forwarded) {
1327 goto FreeRFD;
1328
1329 }
1330
1331 //
1332 // discard bad frames
1333 //
1334
1335 //
1336 // crc, align, dma overrun, too short, receive error (v22 no coll)
1337 //
1338 if ((status & 0x0D90) != 0) {
1339 goto FreeRFD;
1340
1341 }
1342
1343 //
1344 // make sure the status is OK
1345 //
1346 if ((status & 0x02000) == 0) {
1347 goto FreeRFD;
1348 }
1349
1350 pkt_len = (UINT16) (rx_ptr->ActualCount & 0x3fff);
1351
1352 if (pkt_len != 0) {
1353
1354 Tmp_len = pkt_len;
1355 if (pkt_len > rx_cpbptr->BufferLen) {
1356 Tmp_len = (UINT16) rx_cpbptr->BufferLen;
1357 }
1358
1359 CopyMem ((INT8 *) (UINTN) rx_cpbptr->BufferAddr, (INT8 *) &rx_ptr->RFDBuffer, Tmp_len);
1360
1361 hdr_ptr = (EtherHeader *) &rx_ptr->RFDBuffer;
1362 //
1363 // fill the CDB and break the loop
1364 //
1365
1366 //
1367 // includes header
1368 //
1369 rx_dbptr->FrameLen = pkt_len;
1370 rx_dbptr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
1371
1372 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1373 if (hdr_ptr->dest_addr[Index] != AdapterInfo->CurrentNodeAddress[Index]) {
1374 break;
1375 }
1376 }
1377
1378 if (Index >= PXE_HWADDR_LEN_ETHER) {
1379 pkt_type = PXE_FRAME_TYPE_UNICAST;
1380 } else {
1381 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1382 if (hdr_ptr->dest_addr[Index] != AdapterInfo->BroadcastNodeAddress[Index]) {
1383 break;
1384 }
1385 }
1386
1387 if (Index >= PXE_HWADDR_LEN_ETHER) {
1388 pkt_type = PXE_FRAME_TYPE_BROADCAST;
1389 } else {
1390 if ((hdr_ptr->dest_addr[0] & 1) == 1) {
1391 //
1392 // mcast
1393 //
1394
1395 pkt_type = PXE_FRAME_TYPE_MULTICAST;
1396 } else {
1397 pkt_type = PXE_FRAME_TYPE_PROMISCUOUS;
1398 }
1399 }
1400 }
1401
1402 rx_dbptr->Type = pkt_type;
1403 rx_dbptr->Protocol = hdr_ptr->type;
1404
1405 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1406 rx_dbptr->SrcAddr[Index] = hdr_ptr->src_addr[Index];
1407 rx_dbptr->DestAddr[Index] = hdr_ptr->dest_addr[Index];
1408 }
1409
1410 rx_ptr->forwarded = TRUE;
1411 //
1412 // success
1413 //
1414 ret_code = 0;
1415 Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind);
1416 AdapterInfo->cur_rx_ind++;
1417 if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) {
1418 AdapterInfo->cur_rx_ind = 0;
1419 }
1420 break;
1421 }
1422
1423 FreeRFD:
1424 Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind);
1425 AdapterInfo->cur_rx_ind++;
1426 if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) {
1427 AdapterInfo->cur_rx_ind = 0;
1428 }
1429
1430 rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
1431 }
1432
1433 if (pkt_type == PXE_FRAME_TYPE_NONE) {
1434 AdapterInfo->Int_Status &= (~SCB_STATUS_FR);
1435 }
1436
1437 status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
1438 if ((status & SCB_RUS_NO_RESOURCES) != 0) {
1439 //
1440 // start the receive unit here!
1441 // leave all the filled frames,
1442 //
1443 SetupReceiveQueues (AdapterInfo);
1444 OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);
1445 OutWord (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);
1446 AdapterInfo->cur_rx_ind = 0;
1447 }
1448
1449 return ret_code;
1450 }
1451
1452 INT16
1453 E100bReadEepromAndStationAddress (
1454 NIC_DATA_INSTANCE *AdapterInfo
1455 )
1456 /*++
1457
1458 Routine Description:
1459
1460 TODO: Add function description
1461
1462 Arguments:
1463
1464 AdapterInfo - TODO: add argument description
1465
1466 Returns:
1467
1468 TODO: add return values
1469
1470 --*/
1471 {
1472 INT32 Index;
1473 INT32 Index2;
1474 UINT16 sum;
1475 UINT16 eeprom_len;
1476 UINT8 addr_len;
1477 UINT16 *eedata;
1478
1479 eedata = (UINT16 *) (&AdapterInfo->NVData[0]);
1480
1481 sum = 0;
1482 addr_len = E100bGetEepromAddrLen (AdapterInfo);
1483
1484 //
1485 // in words
1486 //
1487 AdapterInfo->NVData_Len = eeprom_len = (UINT16) (1 << addr_len);
1488 for (Index2 = 0, Index = 0; Index < eeprom_len; Index++) {
1489 UINT16 value;
1490 value = E100bReadEeprom (AdapterInfo, Index, addr_len);
1491 eedata[Index] = value;
1492 sum = (UINT16) (sum + value);
1493 if (Index < 3) {
1494 AdapterInfo->PermNodeAddress[Index2++] = (UINT8) value;
1495 AdapterInfo->PermNodeAddress[Index2++] = (UINT8) (value >> 8);
1496 }
1497 }
1498
1499 if (sum != 0xBABA) {
1500 return -1;
1501 }
1502
1503 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1504 AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];
1505 }
1506
1507 for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1508 AdapterInfo->BroadcastNodeAddress[Index] = 0xff;
1509 }
1510
1511 for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
1512 AdapterInfo->CurrentNodeAddress[Index] = 0;
1513 AdapterInfo->PermNodeAddress[Index] = 0;
1514 AdapterInfo->BroadcastNodeAddress[Index] = 0;
1515 }
1516
1517 return 0;
1518 }
1519
1520 //
1521 // CBList is a circular linked list
1522 // 1) When all are free, Tail->next == Head and FreeCount == # allocated
1523 // 2) When none are free, Tail == Head and FreeCount == 0
1524 // 3) when one is free, Tail == Head and Freecount == 1
1525 // 4) First non-Free frame is always at Tail->next
1526 //
1527 UINT8
1528 SetupCBlink (
1529 NIC_DATA_INSTANCE *AdapterInfo
1530 )
1531 /*++
1532
1533 Routine Description:
1534
1535 TODO: Add function description
1536
1537 Arguments:
1538
1539 AdapterInfo - TODO: add argument description
1540
1541 Returns:
1542
1543 TODO: add return values
1544
1545 --*/
1546 {
1547 TxCB *head_ptr;
1548 TxCB *tail_ptr;
1549 TxCB *cur_ptr;
1550 INT32 Index;
1551 UINTN array_off;
1552
1553 cur_ptr = &(AdapterInfo->tx_ring[0]);
1554 array_off = (UINTN) (&cur_ptr->TBDArray) - (UINTN) cur_ptr;
1555 for (Index = 0; Index < AdapterInfo->TxBufCnt; Index++) {
1556 cur_ptr[Index].cb_header.status = 0;
1557 cur_ptr[Index].cb_header.command = 0;
1558
1559 cur_ptr[Index].PhysTCBAddress =
1560 (UINT32) AdapterInfo->tx_phy_addr + (Index * sizeof (TxCB));
1561
1562 cur_ptr[Index].PhysArrayAddr = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);
1563 cur_ptr[Index].PhysTBDArrayAddres = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);
1564
1565 cur_ptr->free_data_ptr = (UINT64) 0;
1566
1567 if (Index < AdapterInfo->TxBufCnt - 1) {
1568 cur_ptr[Index].cb_header.link = cur_ptr[Index].PhysTCBAddress + sizeof (TxCB);
1569 cur_ptr[Index].NextTCBVirtualLinkPtr = &cur_ptr[Index + 1];
1570 cur_ptr[Index + 1].PrevTCBVirtualLinkPtr = &cur_ptr[Index];
1571 }
1572 }
1573
1574 head_ptr = &cur_ptr[0];
1575 tail_ptr = &cur_ptr[AdapterInfo->TxBufCnt - 1];
1576 tail_ptr->cb_header.link = head_ptr->PhysTCBAddress;
1577 tail_ptr->NextTCBVirtualLinkPtr = head_ptr;
1578 head_ptr->PrevTCBVirtualLinkPtr = tail_ptr;
1579
1580 AdapterInfo->FreeCBCount = AdapterInfo->TxBufCnt;
1581 AdapterInfo->FreeTxHeadPtr = head_ptr;
1582 //
1583 // set tail of the free list, next to this would be either in use
1584 // or the head itself
1585 //
1586 AdapterInfo->FreeTxTailPtr = tail_ptr;
1587
1588 AdapterInfo->xmit_done_head = AdapterInfo->xmit_done_tail = 0;
1589
1590 return 0;
1591 }
1592
1593 TxCB *
1594 GetFreeCB (
1595 NIC_DATA_INSTANCE *AdapterInfo
1596 )
1597 /*++
1598
1599 Routine Description:
1600
1601 TODO: Add function description
1602
1603 Arguments:
1604
1605 AdapterInfo - TODO: add argument description
1606
1607 Returns:
1608
1609 TODO: add return values
1610
1611 --*/
1612 {
1613 TxCB *free_cb_ptr;
1614
1615 //
1616 // claim any hanging free CBs
1617 //
1618 if (AdapterInfo->FreeCBCount <= 1) {
1619 CheckCBList (AdapterInfo);
1620 }
1621
1622 //
1623 // don't use up the last CB problem if the previous CB that the CU used
1624 // becomes the last CB we submit because of the SUSPEND bit we set.
1625 // the CU thinks it was never cleared.
1626 //
1627
1628 if (AdapterInfo->FreeCBCount <= 1) {
1629 return NULL;
1630 }
1631
1632 BlockIt (AdapterInfo, TRUE);
1633 free_cb_ptr = AdapterInfo->FreeTxHeadPtr;
1634 AdapterInfo->FreeTxHeadPtr = free_cb_ptr->NextTCBVirtualLinkPtr;
1635 --AdapterInfo->FreeCBCount;
1636 BlockIt (AdapterInfo, FALSE);
1637 return free_cb_ptr;
1638 }
1639
1640 VOID
1641 SetFreeCB (
1642 IN NIC_DATA_INSTANCE *AdapterInfo,
1643 IN TxCB *cb_ptr
1644 )
1645 /*++
1646
1647 Routine Description:
1648
1649 TODO: Add function description
1650
1651 Arguments:
1652
1653 AdapterInfo - TODO: add argument description
1654 cb_ptr - TODO: add argument description
1655
1656 Returns:
1657
1658 TODO: add return values
1659
1660 --*/
1661 {
1662 //
1663 // here we assume cb are returned in the order they are taken out
1664 // and we link the newly freed cb at the tail of free cb list
1665 //
1666 cb_ptr->cb_header.status = 0;
1667 cb_ptr->free_data_ptr = (UINT64) 0;
1668
1669 AdapterInfo->FreeTxTailPtr = cb_ptr;
1670 ++AdapterInfo->FreeCBCount;
1671 return ;
1672 }
1673
1674 UINT16
1675 next (
1676 IN UINT16 ind
1677 )
1678 /*++
1679
1680 Routine Description:
1681
1682 TODO: Add function description
1683
1684 Arguments:
1685
1686 ind - TODO: add argument description
1687
1688 Returns:
1689
1690 TODO: add return values
1691
1692 --*/
1693 {
1694 UINT16 Tmp;
1695
1696 Tmp = (UINT16) (ind + 1);
1697 if (Tmp >= (TX_BUFFER_COUNT << 1)) {
1698 Tmp = 0;
1699 }
1700
1701 return Tmp;
1702 }
1703
1704 UINT16
1705 CheckCBList (
1706 IN NIC_DATA_INSTANCE *AdapterInfo
1707 )
1708 /*++
1709
1710 Routine Description:
1711
1712 TODO: Add function description
1713
1714 Arguments:
1715
1716 AdapterInfo - TODO: add argument description
1717
1718 Returns:
1719
1720 TODO: add return values
1721
1722 --*/
1723 {
1724 TxCB *Tmp_ptr;
1725 UINT16 cnt;
1726
1727 cnt = 0;
1728 while (1) {
1729 Tmp_ptr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;
1730 if ((Tmp_ptr->cb_header.status & CMD_STATUS_MASK) != 0) {
1731 //
1732 // check if Q is full
1733 //
1734 if (next (AdapterInfo->xmit_done_tail) != AdapterInfo->xmit_done_head) {
1735 AdapterInfo->xmit_done[AdapterInfo->xmit_done_tail] = Tmp_ptr->free_data_ptr;
1736
1737 UnMapIt (
1738 AdapterInfo,
1739 Tmp_ptr->free_data_ptr,
1740 Tmp_ptr->TBDArray[0].buf_len,
1741 TO_DEVICE,
1742 (UINT64) Tmp_ptr->TBDArray[0].phys_buf_addr
1743 );
1744
1745 AdapterInfo->xmit_done_tail = next (AdapterInfo->xmit_done_tail);
1746 }
1747
1748 SetFreeCB (AdapterInfo, Tmp_ptr);
1749 } else {
1750 break;
1751 }
1752 }
1753
1754 return cnt;
1755 }
1756 //
1757 // Description : Initialize the RFD list list by linking each element together
1758 // in a circular list. The simplified memory model is used.
1759 // All data is in the RFD. The RFDs are linked together and the
1760 // last one points back to the first one. When the current RFD
1761 // is processed (frame received), its EL bit is set and the EL
1762 // bit in the previous RXFD is cleared.
1763 // Allocation done during INIT, this is making linked list.
1764 //
1765 UINT8
1766 SetupReceiveQueues (
1767 IN NIC_DATA_INSTANCE *AdapterInfo
1768 )
1769 /*++
1770
1771 Routine Description:
1772
1773 TODO: Add function description
1774
1775 Arguments:
1776
1777 AdapterInfo - TODO: add argument description
1778
1779 Returns:
1780
1781 TODO: add return values
1782
1783 --*/
1784 {
1785 RxFD *rx_ptr;
1786 RxFD *tail_ptr;
1787 UINT16 Index;
1788
1789 AdapterInfo->cur_rx_ind = 0;
1790 rx_ptr = (&AdapterInfo->rx_ring[0]);
1791
1792 for (Index = 0; Index < AdapterInfo->RxBufCnt; Index++) {
1793 rx_ptr[Index].cb_header.status = 0;
1794 rx_ptr[Index].cb_header.command = 0;
1795 rx_ptr[Index].RFDSize = RX_BUFFER_SIZE;
1796 rx_ptr[Index].ActualCount = 0;
1797 //
1798 // RBDs not used, simple memory model
1799 //
1800 rx_ptr[Index].rx_buf_addr = (UINT32) (-1);
1801
1802 //
1803 // RBDs not used, simple memory model
1804 //
1805 rx_ptr[Index].forwarded = FALSE;
1806
1807 //
1808 // don't use Tmp_ptr if it is beyond the last one
1809 //
1810 if (Index < AdapterInfo->RxBufCnt - 1) {
1811 rx_ptr[Index].cb_header.link = (UINT32) AdapterInfo->rx_phy_addr + ((Index + 1) * sizeof (RxFD));
1812 }
1813 }
1814
1815 tail_ptr = (&AdapterInfo->rx_ring[AdapterInfo->RxBufCnt - 1]);
1816 tail_ptr->cb_header.link = (UINT32) AdapterInfo->rx_phy_addr;
1817
1818 //
1819 // set the EL bit
1820 //
1821 tail_ptr->cb_header.command = 0xC000;
1822 AdapterInfo->RFDTailPtr = tail_ptr;
1823 return 0;
1824 }
1825
1826 VOID
1827 Recycle_RFD (
1828 IN NIC_DATA_INSTANCE *AdapterInfo,
1829 IN UINT16 rx_index
1830 )
1831 /*++
1832
1833 Routine Description:
1834
1835 TODO: Add function description
1836
1837 Arguments:
1838
1839 AdapterInfo - TODO: add argument description
1840 rx_index - TODO: add argument description
1841
1842 Returns:
1843
1844 TODO: add return values
1845
1846 --*/
1847 {
1848 RxFD *rx_ptr;
1849 RxFD *tail_ptr;
1850 //
1851 // change the EL bit and change the AdapterInfo->RxTailPtr
1852 // rx_ptr is assumed to be the head of the Q
1853 // AdapterInfo->rx_forwarded[rx_index] = FALSE;
1854 //
1855 rx_ptr = &AdapterInfo->rx_ring[rx_index];
1856 tail_ptr = AdapterInfo->RFDTailPtr;
1857 //
1858 // set el_bit and suspend bit
1859 //
1860 rx_ptr->cb_header.command = 0xc000;
1861 rx_ptr->cb_header.status = 0;
1862 rx_ptr->ActualCount = 0;
1863 rx_ptr->forwarded = FALSE;
1864 AdapterInfo->RFDTailPtr = rx_ptr;
1865 //
1866 // resetting the el_bit.
1867 //
1868 tail_ptr->cb_header.command = 0;
1869 //
1870 // check the receive unit, fix if there is any problem
1871 //
1872 return ;
1873 }
1874 //
1875 // Serial EEPROM section.
1876 //
1877 // EEPROM_Ctrl bits.
1878 //
1879 #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
1880 #define EE_CS 0x02 /* EEPROM chip select. */
1881 #define EE_DI 0x04 /* EEPROM chip data in. */
1882 #define EE_WRITE_0 0x01
1883 #define EE_WRITE_1 0x05
1884 #define EE_DO 0x08 /* EEPROM chip data out. */
1885 #define EE_ENB (0x4800 | EE_CS)
1886
1887 //
1888 // Delay between EEPROM clock transitions.
1889 // This will actually work with no delay on 33Mhz PCI.
1890 //
1891 #define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
1892
1893 //
1894 // The EEPROM commands include the alway-set leading bit.
1895 //
1896 #define EE_WRITE_CMD 5 // 101b
1897 #define EE_READ_CMD 6 // 110b
1898 #define EE_ERASE_CMD (7 << 6)
1899
1900 STATIC
1901 VOID
1902 shift_bits_out (
1903 IN NIC_DATA_INSTANCE *AdapterInfo,
1904 IN UINT16 val,
1905 IN UINT8 num_bits
1906 )
1907 /*++
1908
1909 Routine Description:
1910
1911 TODO: Add function description
1912
1913 Arguments:
1914
1915 AdapterInfo - TODO: add argument description
1916 val - TODO: add argument description
1917 num_bits - TODO: add argument description
1918
1919 Returns:
1920
1921 TODO: add return values
1922
1923 --*/
1924 {
1925 INT32 Index;
1926 UINT8 Tmp;
1927 UINT32 EEAddr;
1928
1929 EEAddr = AdapterInfo->ioaddr + SCBeeprom;
1930
1931 for (Index = num_bits; Index >= 0; Index--) {
1932 INT16 dataval;
1933
1934 //
1935 // will be 0 or 4
1936 //
1937 dataval = (INT16) ((val & (1 << Index)) ? EE_DI : 0);
1938
1939 //
1940 // mask off the data_in bit
1941 //
1942 Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) &~EE_DI);
1943 Tmp = (UINT8) (Tmp | dataval);
1944 OutByte (AdapterInfo, Tmp, EEAddr);
1945 eeprom_delay (100);
1946 //
1947 // raise the eeprom clock
1948 //
1949 OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
1950 eeprom_delay (150);
1951 //
1952 // lower the eeprom clock
1953 //
1954 OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
1955 eeprom_delay (150);
1956 }
1957 }
1958
1959 STATIC
1960 UINT16
1961 shift_bits_in (
1962 IN NIC_DATA_INSTANCE *AdapterInfo
1963 )
1964 /*++
1965
1966 Routine Description:
1967
1968 TODO: Add function description
1969
1970 Arguments:
1971
1972 AdapterInfo - TODO: add argument description
1973
1974 Returns:
1975
1976 TODO: add return values
1977
1978 --*/
1979 {
1980 UINT8 Tmp;
1981 INT32 Index;
1982 UINT16 retval;
1983 UINT32 EEAddr;
1984
1985 EEAddr = AdapterInfo->ioaddr + SCBeeprom;
1986
1987 retval = 0;
1988 for (Index = 15; Index >= 0; Index--) {
1989 //
1990 // raise the clock
1991 //
1992
1993 //
1994 // mask off the data_in bit
1995 //
1996 Tmp = InByte (AdapterInfo, EEAddr);
1997 OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
1998 eeprom_delay (100);
1999 Tmp = InByte (AdapterInfo, EEAddr);
2000 retval = (UINT16) ((retval << 1) | ((Tmp & EE_DO) ? 1 : 0));
2001 //
2002 // lower the clock
2003 //
2004 OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
2005 eeprom_delay (100);
2006 }
2007
2008 return retval;
2009 }
2010
2011 STATIC
2012 BOOLEAN
2013 E100bSetEepromLockOut (
2014 IN NIC_DATA_INSTANCE *AdapterInfo
2015 )
2016 /*++
2017
2018 Routine Description:
2019 This routine sets the EEPROM lockout bit to gain exclusive access to the
2020 eeprom. the access bit is the most significant bit in the General Control
2021 Register 2 in the SCB space.
2022
2023 Arguments:
2024 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2025
2026 Returns:
2027 TRUE - if it got the access
2028 FALSE - if it fails to get the exclusive access
2029
2030 --*/
2031 {
2032 UINTN wait;
2033 UINT8 tmp;
2034
2035 if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||
2036 (AdapterInfo->RevID >= D102_REVID)) {
2037
2038 wait = 500;
2039
2040 while (wait--) {
2041
2042 tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
2043 tmp |= GCR2_EEPROM_ACCESS_SEMAPHORE;
2044 OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);
2045
2046 DelayIt (AdapterInfo, 50);
2047 tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
2048
2049 if (tmp & GCR2_EEPROM_ACCESS_SEMAPHORE) {
2050 return TRUE;
2051 }
2052 }
2053
2054 return FALSE;
2055 }
2056
2057 return TRUE;
2058 }
2059
2060 STATIC
2061 VOID
2062 E100bReSetEepromLockOut (
2063 IN NIC_DATA_INSTANCE *AdapterInfo
2064 )
2065 /*++
2066
2067 Routine Description:
2068 This routine Resets the EEPROM lockout bit to giveup access to the
2069 eeprom. the access bit is the most significant bit in the General Control
2070 Register 2 in the SCB space.
2071
2072 Arguments:
2073 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2074
2075 Returns:
2076 None
2077
2078 --*/
2079 {
2080 UINT8 tmp;
2081
2082 if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||
2083 (AdapterInfo->RevID >= D102_REVID)) {
2084
2085 tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
2086 tmp &= ~(GCR2_EEPROM_ACCESS_SEMAPHORE);
2087 OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);
2088
2089 DelayIt (AdapterInfo, 50);
2090 }
2091 }
2092
2093 UINT16
2094 E100bReadEeprom (
2095 IN NIC_DATA_INSTANCE *AdapterInfo,
2096 IN INT32 Location,
2097 IN UINT8 AddrLen
2098 )
2099 /*++
2100
2101 Routine Description:
2102 Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
2103
2104 Arguments:
2105 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2106 Location - Word offset into the MAC address to read.
2107 AddrLen - Number of bits of address length.
2108
2109 Returns:
2110 RetVal - The word read from the EEPROM.
2111
2112 --*/
2113 {
2114 UINT16 RetVal;
2115 UINT8 Tmp;
2116
2117 UINT32 EEAddr;
2118 UINT16 ReadCmd;
2119
2120 EEAddr = AdapterInfo->ioaddr + SCBeeprom;
2121 ReadCmd = (UINT16) (Location | (EE_READ_CMD << AddrLen));
2122
2123 RetVal = 0;
2124
2125 //
2126 // get exclusive access to the eeprom first!
2127 //
2128 E100bSetEepromLockOut (AdapterInfo);
2129
2130 //
2131 // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK
2132 // to write the opcode+data value out one bit at a time in DI starting at msb
2133 // and then out a 1 to sk, wait, out 0 to SK and wait
2134 // repeat this for all the bits to be written
2135 //
2136
2137 //
2138 // 11110010b
2139 //
2140 Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);
2141 OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);
2142
2143 //
2144 // 3 for the read opcode 110b
2145 //
2146 shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + AddrLen));
2147
2148 //
2149 // read the eeprom word one bit at a time
2150 //
2151 RetVal = shift_bits_in (AdapterInfo);
2152
2153 //
2154 // Terminate the EEPROM access and leave eeprom in a clean state.
2155 //
2156 Tmp = InByte (AdapterInfo, EEAddr);
2157 Tmp &= ~(EE_CS | EE_DI);
2158 OutByte (AdapterInfo, Tmp, EEAddr);
2159
2160 //
2161 // raise the clock and lower the eeprom shift clock
2162 //
2163 OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
2164 eeprom_delay (100);
2165
2166 OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
2167 eeprom_delay (100);
2168
2169 //
2170 // giveup access to the eeprom
2171 //
2172 E100bReSetEepromLockOut (AdapterInfo);
2173
2174 return RetVal;
2175 }
2176
2177 UINT8
2178 E100bGetEepromAddrLen (
2179 IN NIC_DATA_INSTANCE *AdapterInfo
2180 )
2181 /*++
2182
2183 Routine Description:
2184 Using the NIC data structure information, read the EEPROM to determine how many bits of address length
2185 this EEPROM is in Words.
2186
2187 Arguments:
2188 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2189
2190 Returns:
2191 RetVal - The word read from the EEPROM.
2192
2193 --*/
2194 {
2195 UINT8 Tmp;
2196 UINT8 AddrLen;
2197 UINT32 EEAddr;
2198 //
2199 // assume 64word eeprom (so,6 bits of address_length)
2200 //
2201 UINT16 ReadCmd;
2202
2203 EEAddr = AdapterInfo->ioaddr + SCBeeprom;
2204 ReadCmd = (EE_READ_CMD << 6);
2205
2206 //
2207 // get exclusive access to the eeprom first!
2208 //
2209 E100bSetEepromLockOut (AdapterInfo);
2210
2211 //
2212 // address we are trying to read is 0
2213 // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK
2214 // to write the opcode+data value out one bit at a time in DI starting at msb
2215 // and then out a 1 to sk, wait, out 0 to SK and wait
2216 // repeat this for all the bits to be written
2217 //
2218 Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);
2219
2220 //
2221 // enable eeprom access
2222 //
2223 OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);
2224
2225 //
2226 // 3 for opcode, 6 for the default address len
2227 //
2228 shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + 6));
2229
2230 //
2231 // (in case of a 64 word eeprom).
2232 // read the "dummy zero" from EE_DO to say that the address we wrote
2233 // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"
2234 //
2235
2236 //
2237 // assume the smallest
2238 //
2239 AddrLen = 6;
2240 Tmp = InByte (AdapterInfo, EEAddr);
2241 while ((AddrLen < 8) && ((Tmp & EE_DO) != 0)) {
2242 OutByte (AdapterInfo, (UINT8) (Tmp &~EE_DI), EEAddr);
2243 eeprom_delay (100);
2244
2245 //
2246 // raise the eeprom clock
2247 //
2248 OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
2249 eeprom_delay (150);
2250
2251 //
2252 // lower the eeprom clock
2253 //
2254 OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
2255 eeprom_delay (150);
2256 Tmp = InByte (AdapterInfo, EEAddr);
2257 AddrLen++;
2258 }
2259
2260 //
2261 // read the eeprom word, even though we don't need this
2262 //
2263 shift_bits_in (AdapterInfo);
2264
2265 //
2266 // Terminate the EEPROM access.
2267 //
2268 Tmp = InByte (AdapterInfo, EEAddr);
2269 Tmp &= ~(EE_CS | EE_DI);
2270 OutByte (AdapterInfo, Tmp, EEAddr);
2271
2272 //
2273 // raise the clock and lower the eeprom shift clock
2274 //
2275 OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
2276 eeprom_delay (100);
2277
2278 OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
2279 eeprom_delay (100);
2280
2281 //
2282 // giveup access to the eeprom!
2283 //
2284 E100bReSetEepromLockOut (AdapterInfo);
2285
2286 return AddrLen;
2287 }
2288
2289 UINTN
2290 E100bStatistics (
2291 NIC_DATA_INSTANCE *AdapterInfo,
2292 UINT64 DBaddr,
2293 UINT16 DBsize
2294 )
2295 /*++
2296
2297 Routine Description:
2298
2299 TODO: Add function description
2300
2301 Arguments:
2302
2303 AdapterInfo - TODO: add argument description
2304 DBaddr - TODO: add argument description
2305 DBsize - TODO: add argument description
2306
2307 Returns:
2308
2309 TODO: add return values
2310
2311 --*/
2312 {
2313 PXE_DB_STATISTICS db;
2314 //
2315 // wait upto one second (each wait is 100 micro s)
2316 //
2317 UINT32 Wait;
2318 Wait = 10000;
2319 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
2320
2321 //
2322 // Clear statistics done marker.
2323 //
2324 AdapterInfo->statistics->done_marker = 0;
2325
2326 //
2327 // Issue statistics dump (or dump w/ reset) command.
2328 //
2329 OutByte (
2330 AdapterInfo,
2331 (UINT8) (DBsize ? CU_SHOWSTATS : CU_DUMPSTATS),
2332 (UINT32) (AdapterInfo->ioaddr + SCBCmd)
2333 );
2334
2335 //
2336 // Wait for command to complete.
2337 //
2338 // zero the db here just to chew up a little more time.
2339 //
2340
2341 ZeroMem ((VOID *) &db, sizeof db);
2342
2343 while (Wait != 0) {
2344 //
2345 // Wait a bit before checking.
2346 //
2347
2348 DelayIt (AdapterInfo, 100);
2349
2350 //
2351 // Look for done marker at end of statistics.
2352 //
2353
2354 switch (AdapterInfo->statistics->done_marker) {
2355 case 0xA005:
2356 case 0xA007:
2357 break;
2358
2359 default:
2360 Wait--;
2361 continue;
2362 }
2363
2364 //
2365 // if we did not "continue" from the above switch, we are done,
2366 //
2367 break;
2368 }
2369
2370 //
2371 // If this is a reset, we are out of here!
2372 //
2373 if (DBsize == 0) {
2374 return PXE_STATCODE_SUCCESS;
2375 }
2376
2377 //
2378 // Convert NIC statistics counter format to EFI/UNDI
2379 // specification statistics counter format.
2380 //
2381
2382 //
2383 // 54 3210 fedc ba98 7654 3210
2384 // db.Supported = 01 0000 0100 1101 0001 0111;
2385 //
2386 db.Supported = 0x104D17;
2387
2388 //
2389 // Statistics from the NIC
2390 //
2391
2392 db.Data[0x01] = AdapterInfo->statistics->rx_good_frames;
2393
2394 db.Data[0x02] = AdapterInfo->statistics->rx_runt_errs;
2395
2396 db.Data[0x08] = AdapterInfo->statistics->rx_crc_errs +
2397 AdapterInfo->statistics->rx_align_errs;
2398
2399 db.Data[0x04] = db.Data[0x02] +
2400 db.Data[0x08] +
2401 AdapterInfo->statistics->rx_resource_errs +
2402 AdapterInfo->statistics->rx_overrun_errs;
2403
2404 db.Data[0x00] = db.Data[0x01] + db.Data[0x04];
2405
2406 db.Data[0x0B] = AdapterInfo->statistics->tx_good_frames;
2407
2408 db.Data[0x0E] = AdapterInfo->statistics->tx_coll16_errs +
2409 AdapterInfo->statistics->tx_late_colls +
2410 AdapterInfo->statistics->tx_underruns +
2411 AdapterInfo->statistics->tx_one_colls +
2412 AdapterInfo->statistics->tx_multi_colls;
2413
2414 db.Data[0x14] = AdapterInfo->statistics->tx_total_colls;
2415
2416 db.Data[0x0A] = db.Data[0x0B] +
2417 db.Data[0x0E] +
2418 AdapterInfo->statistics->tx_lost_carrier;
2419
2420 if (DBsize > sizeof db) {
2421 DBsize = sizeof db;
2422 }
2423
2424 CopyMem ((VOID *) (UINTN) DBaddr, (VOID *) &db, (UINTN) DBsize);
2425
2426 return PXE_STATCODE_SUCCESS;
2427 }
2428
2429 UINTN
2430 E100bReset (
2431 IN NIC_DATA_INSTANCE *AdapterInfo,
2432 IN INT32 OpFlags
2433 )
2434 /*++
2435
2436 Routine Description:
2437
2438 TODO: Add function description
2439
2440 Arguments:
2441
2442 AdapterInfo - TODO: add argument description
2443 OpFlags - TODO: add argument description
2444
2445 Returns:
2446
2447 TODO: add return values
2448
2449 --*/
2450 {
2451
2452 UINT16 save_filter;
2453 //
2454 // disable the interrupts
2455 //
2456 OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
2457
2458 //
2459 // wait for the tx queue to complete
2460 //
2461 CheckCBList (AdapterInfo);
2462
2463 XmitWaitForCompletion (AdapterInfo);
2464
2465 if (AdapterInfo->Receive_Started) {
2466 StopRU (AdapterInfo);
2467 }
2468
2469 InitializeChip (AdapterInfo);
2470
2471 //
2472 // check the opflags and restart receive filters
2473 //
2474 if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
2475
2476 save_filter = AdapterInfo->Rx_Filter;
2477 //
2478 // if we give the filter same as Rx_Filter,
2479 // this routine will not set mcast list (it thinks there is no change)
2480 // to force it, we will reset that flag in the Rx_Filter
2481 //
2482 AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
2483 E100bSetfilter (AdapterInfo, save_filter, (UINT64) 0, (UINT32) 0);
2484 }
2485
2486 if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
2487 //
2488 // disable the interrupts
2489 //
2490 AdapterInfo->int_mask = 0;
2491 }
2492 //
2493 // else leave the interrupt in the pre-set state!!!
2494 //
2495 E100bSetInterruptState (AdapterInfo);
2496
2497 return 0;
2498 }
2499
2500 UINTN
2501 E100bShutdown (
2502 IN NIC_DATA_INSTANCE *AdapterInfo
2503 )
2504 /*++
2505
2506 Routine Description:
2507
2508 TODO: Add function description
2509
2510 Arguments:
2511
2512 AdapterInfo - TODO: add argument description
2513
2514 Returns:
2515
2516 TODO: add return values
2517
2518 --*/
2519 {
2520 //
2521 // disable the interrupts
2522 //
2523 OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
2524
2525 //
2526 // stop the receive unit
2527 //
2528 if (AdapterInfo->Receive_Started) {
2529 StopRU (AdapterInfo);
2530 }
2531
2532 //
2533 // wait for the tx queue to complete
2534 //
2535 CheckCBList (AdapterInfo);
2536 if (AdapterInfo->FreeCBCount != AdapterInfo->TxBufCnt) {
2537 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
2538 }
2539
2540 //
2541 // we do not want to reset the phy, it takes a long time to renegotiate the
2542 // link after that (3-4 seconds)
2543 //
2544 InitializeChip (AdapterInfo);
2545 SelectiveReset (AdapterInfo);
2546 return 0;
2547 }
2548
2549 VOID
2550 MdiWrite (
2551 IN NIC_DATA_INSTANCE *AdapterInfo,
2552 IN UINT8 RegAddress,
2553 IN UINT8 PhyAddress,
2554 IN UINT16 DataValue
2555 )
2556 /*++
2557
2558 Routine Description:
2559 This routine will write a value to the specified MII register
2560 of an external MDI compliant device (e.g. PHY 100). The command will
2561 execute in polled mode.
2562
2563 Arguments:
2564 AdapterInfo - pointer to the structure that contains the NIC's context.
2565 RegAddress - The MII register that we are writing to
2566 PhyAddress - The MDI address of the Phy component.
2567 DataValue - The value that we are writing to the MII register.
2568
2569 Returns:
2570 nothing
2571 --*/
2572 {
2573 UINT32 WriteCommand;
2574
2575 WriteCommand = ((UINT32) DataValue) |
2576 ((UINT32)(RegAddress << 16)) |
2577 ((UINT32)(PhyAddress << 21)) |
2578 ((UINT32)(MDI_WRITE << 26));
2579
2580 //
2581 // Issue the write command to the MDI control register.
2582 //
2583 OutLong (AdapterInfo, WriteCommand, AdapterInfo->ioaddr + SCBCtrlMDI);
2584
2585 //
2586 // wait 20usec before checking status
2587 //
2588 DelayIt (AdapterInfo, 20);
2589
2590 //
2591 // poll for the mdi write to complete
2592 while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &
2593 MDI_PHY_READY) == 0){
2594 DelayIt (AdapterInfo, 20);
2595 }
2596 }
2597
2598 VOID
2599 MdiRead (
2600 IN NIC_DATA_INSTANCE *AdapterInfo,
2601 IN UINT8 RegAddress,
2602 IN UINT8 PhyAddress,
2603 IN OUT UINT16 *DataValue
2604 )
2605 /*++
2606
2607 Routine Description:
2608 This routine will read a value from the specified MII register
2609 of an external MDI compliant device (e.g. PHY 100), and return
2610 it to the calling routine. The command will execute in polled mode.
2611
2612 Arguments:
2613 AdapterInfo - pointer to the structure that contains the NIC's context.
2614 RegAddress - The MII register that we are reading from
2615 PhyAddress - The MDI address of the Phy component.
2616 DataValue - pointer to the value that we read from the MII register.
2617
2618 Returns:
2619
2620 --*/
2621 {
2622 UINT32 ReadCommand;
2623
2624 ReadCommand = ((UINT32) (RegAddress << 16)) |
2625 ((UINT32) (PhyAddress << 21)) |
2626 ((UINT32) (MDI_READ << 26));
2627
2628 //
2629 // Issue the read command to the MDI control register.
2630 //
2631 OutLong (AdapterInfo, ReadCommand, AdapterInfo->ioaddr + SCBCtrlMDI);
2632
2633 //
2634 // wait 20usec before checking status
2635 //
2636 DelayIt (AdapterInfo, 20);
2637
2638 //
2639 // poll for the mdi read to complete
2640 //
2641 while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &
2642 MDI_PHY_READY) == 0) {
2643 DelayIt (AdapterInfo, 20);
2644
2645 }
2646
2647 *DataValue = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI);
2648 }
2649
2650 VOID
2651 PhyReset (
2652 NIC_DATA_INSTANCE *AdapterInfo
2653 )
2654 /*++
2655
2656 Routine Description:
2657 This routine will reset the PHY that the adapter is currently
2658 configured to use.
2659
2660 Arguments:
2661 AdapterInfo - pointer to the structure that contains the NIC's context.
2662
2663 Returns:
2664
2665 --*/
2666 {
2667 UINT16 MdiControlReg;
2668
2669 MdiControlReg = (MDI_CR_AUTO_SELECT |
2670 MDI_CR_RESTART_AUTO_NEG |
2671 MDI_CR_RESET);
2672
2673 //
2674 // Write the MDI control register with our new Phy configuration
2675 //
2676 MdiWrite (
2677 AdapterInfo,
2678 MDI_CONTROL_REG,
2679 AdapterInfo->PhyAddress,
2680 MdiControlReg
2681 );
2682
2683 return ;
2684 }
2685
2686 BOOLEAN
2687 PhyDetect (
2688 NIC_DATA_INSTANCE *AdapterInfo
2689 )
2690 /*++
2691
2692 Routine Description:
2693 This routine will detect what phy we are using, set the line
2694 speed, FDX or HDX, and configure the phy if necessary.
2695
2696 The following combinations are supported:
2697 - TX or T4 PHY alone at PHY address 1
2698 - T4 or TX PHY at address 1 and MII PHY at address 0
2699 - 82503 alone (10Base-T mode, no full duplex support)
2700 - 82503 and MII PHY (TX or T4) at address 0
2701
2702 The sequence / priority of detection is as follows:
2703 - PHY 1 with cable termination
2704 - PHY 0 with cable termination
2705 - PHY 1 (if found) without cable termination
2706 - 503 interface
2707
2708 Additionally auto-negotiation capable (NWAY) and parallel
2709 detection PHYs are supported. The flow-chart is described in
2710 the 82557 software writer's manual.
2711
2712 NOTE: 1. All PHY MDI registers are read in polled mode.
2713 2. The routines assume that the 82557 has been RESET and we have
2714 obtained the virtual memory address of the CSR.
2715 3. PhyDetect will not RESET the PHY.
2716 4. If FORCEFDX is set, SPEED should also be set. The driver will
2717 check the values for inconsistency with the detected PHY
2718 technology.
2719 5. PHY 1 (the PHY on the adapter) may have an address in the range
2720 1 through 31 inclusive. The driver will accept addresses in
2721 this range.
2722 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
2723 is detected.
2724
2725 Arguments:
2726 AdapterInfo - pointer to the structure that contains the NIC's context.
2727
2728 Returns:
2729 TRUE - If a Phy was detected, and configured correctly.
2730 FALSE - If a valid phy could not be detected and configured.
2731
2732 --*/
2733 {
2734 UINT16 *eedata;
2735 UINT16 MdiControlReg;
2736 UINT16 MdiStatusReg;
2737 BOOLEAN FoundPhy1;
2738 UINT8 ReNegotiateTime;
2739
2740 eedata = (UINT16 *) (&AdapterInfo->NVData[0]);
2741
2742 FoundPhy1 = FALSE;
2743 ReNegotiateTime = 35;
2744 //
2745 // EEPROM word [6] contains the Primary PHY record in which the least 3 bits
2746 // indicate the PHY address
2747 // and word [7] contains the secondary PHY record
2748 //
2749 AdapterInfo->PhyRecord[0] = eedata[6];
2750 AdapterInfo->PhyRecord[1] = eedata[7];
2751 AdapterInfo->PhyAddress = (UINT8) (AdapterInfo->PhyRecord[0] & 7);
2752
2753 //
2754 // Check for a phy address over-ride of 32 which indicates force use of 82503
2755 // not detecting the link in this case
2756 //
2757 if (AdapterInfo->PhyAddress == 32) {
2758 //
2759 // 503 interface over-ride
2760 // Record the current speed and duplex. We will be in half duplex
2761 // mode unless the user used the force full duplex over-ride.
2762 //
2763 AdapterInfo->LinkSpeed = 10;
2764 return (TRUE);
2765 }
2766
2767 //
2768 // If the Phy Address is between 1-31 then we must first look for phy 1,
2769 // at that address.
2770 //
2771 if ((AdapterInfo->PhyAddress > 0) && (AdapterInfo->PhyAddress < 32)) {
2772
2773 //
2774 // Read the MDI control and status registers at phy 1
2775 // and check if we found a valid phy
2776 //
2777 MdiRead (
2778 AdapterInfo,
2779 MDI_CONTROL_REG,
2780 AdapterInfo->PhyAddress,
2781 &MdiControlReg
2782 );
2783
2784 MdiRead (
2785 AdapterInfo,
2786 MDI_STATUS_REG,
2787 AdapterInfo->PhyAddress,
2788 &MdiStatusReg
2789 );
2790
2791 if (!((MdiControlReg == 0xffff) ||
2792 ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {
2793
2794 //
2795 // we have a valid phy1
2796 // Read the status register again because of sticky bits
2797 //
2798 FoundPhy1 = TRUE;
2799 MdiRead (
2800 AdapterInfo,
2801 MDI_STATUS_REG,
2802 AdapterInfo->PhyAddress,
2803 &MdiStatusReg
2804 );
2805
2806 //
2807 // If there is a valid link then use this Phy.
2808 //
2809 if (MdiStatusReg & MDI_SR_LINK_STATUS) {
2810 return (SetupPhy(AdapterInfo));
2811 }
2812 }
2813 }
2814
2815 //
2816 // Next try to detect a PHY at address 0x00 because there was no Phy 1,
2817 // or Phy 1 didn't have link, or we had a phy 0 over-ride
2818 //
2819
2820 //
2821 // Read the MDI control and status registers at phy 0
2822 //
2823 MdiRead (AdapterInfo, MDI_CONTROL_REG, 0, &MdiControlReg);
2824 MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
2825
2826 //
2827 // check if we found a valid phy 0
2828 //
2829 if (((MdiControlReg == 0xffff) ||
2830 ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {
2831
2832 //
2833 // we don't have a valid phy at address 0
2834 // if phy address was forced to 0, then error out because we
2835 // didn't find a phy at that address
2836 //
2837 if (AdapterInfo->PhyAddress == 0x0000) {
2838 return (FALSE);
2839 } else {
2840 //
2841 // at this point phy1 does not have link and there is no phy 0 at all
2842 // if we are forced to detect the cable, error out here!
2843 //
2844 if (AdapterInfo->CableDetect != 0) {
2845 return FALSE;
2846
2847 }
2848
2849 if (FoundPhy1) {
2850 //
2851 // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
2852 //
2853 return SetupPhy (AdapterInfo);
2854 } else {
2855 //
2856 // didn't find phy 0 or phy 1, so assume a 503 interface
2857 //
2858 AdapterInfo->PhyAddress = 32;
2859
2860 //
2861 // Record the current speed and duplex. We'll be in half duplex
2862 // mode unless the user used the force full duplex over-ride.
2863 //
2864 AdapterInfo->LinkSpeed = 10;
2865 return (TRUE);
2866 }
2867 }
2868 } else {
2869 //
2870 // We have a valid phy at address 0. If phy 0 has a link then we use
2871 // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link)
2872 // if phy 1 is present, or phy 0 if phy 1 is not present
2873 // If phy 1 was present, then we must isolate phy 1 before we enable
2874 // phy 0 to see if Phy 0 has a link.
2875 //
2876 if (FoundPhy1) {
2877 //
2878 // isolate phy 1
2879 //
2880 MdiWrite (
2881 AdapterInfo,
2882 MDI_CONTROL_REG,
2883 AdapterInfo->PhyAddress,
2884 MDI_CR_ISOLATE
2885 );
2886
2887 //
2888 // wait 100 microseconds for the phy to isolate.
2889 //
2890 DelayIt (AdapterInfo, 100);
2891 }
2892
2893 //
2894 // Since this Phy is at address 0, we must enable it. So clear
2895 // the isolate bit, and set the auto-speed select bit
2896 //
2897 MdiWrite (
2898 AdapterInfo,
2899 MDI_CONTROL_REG,
2900 0,
2901 MDI_CR_AUTO_SELECT
2902 );
2903
2904 //
2905 // wait 100 microseconds for the phy to be enabled.
2906 //
2907 DelayIt (AdapterInfo, 100);
2908
2909 //
2910 // restart the auto-negotion process
2911 //
2912 MdiWrite (
2913 AdapterInfo,
2914 MDI_CONTROL_REG,
2915 0,
2916 MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT
2917 );
2918
2919 //
2920 // wait no more than 3.5 seconds for auto-negotiation to complete
2921 //
2922 while (ReNegotiateTime) {
2923 //
2924 // Read the status register twice because of sticky bits
2925 //
2926 MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
2927 MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
2928
2929 if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) {
2930 break;
2931 }
2932
2933 DelayIt (AdapterInfo, 100);
2934 ReNegotiateTime--;
2935 }
2936
2937 //
2938 // Read the status register again because of sticky bits
2939 //
2940 MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
2941
2942 //
2943 // If the link was not set
2944 //
2945 if ((MdiStatusReg & MDI_SR_LINK_STATUS) == 0) {
2946 //
2947 // PHY1 does not have a link and phy 0 does not have a link
2948 // do not proceed if we need to detect the link!
2949 //
2950 if (AdapterInfo->CableDetect != 0) {
2951 return FALSE;
2952 }
2953
2954 //
2955 // the link wasn't set, so use phy 1 if phy 1 was present
2956 //
2957 if (FoundPhy1) {
2958 //
2959 // isolate phy 0
2960 //
2961 MdiWrite (AdapterInfo, MDI_CONTROL_REG, 0, MDI_CR_ISOLATE);
2962
2963 //
2964 // wait 100 microseconds for the phy to isolate.
2965 //
2966 DelayIt (AdapterInfo, 100);
2967
2968 //
2969 // Now re-enable PHY 1
2970 //
2971 MdiWrite (
2972 AdapterInfo,
2973 MDI_CONTROL_REG,
2974 AdapterInfo->PhyAddress,
2975 MDI_CR_AUTO_SELECT
2976 );
2977
2978 //
2979 // wait 100 microseconds for the phy to be enabled
2980 //
2981 DelayIt (AdapterInfo, 100);
2982
2983 //
2984 // restart the auto-negotion process
2985 //
2986 MdiWrite (
2987 AdapterInfo,
2988 MDI_CONTROL_REG,
2989 AdapterInfo->PhyAddress,
2990 MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT
2991 );
2992
2993 //
2994 // Don't wait for it to complete (we didn't have link earlier)
2995 //
2996 return (SetupPhy (AdapterInfo));
2997 }
2998 }
2999
3000 //
3001 // Definitely using Phy 0
3002 //
3003 AdapterInfo->PhyAddress = 0;
3004 return (SetupPhy(AdapterInfo));
3005 }
3006 }
3007
3008 BOOLEAN
3009 SetupPhy (
3010 IN NIC_DATA_INSTANCE *AdapterInfo
3011 )
3012 /*++
3013
3014 Routine Description:
3015 This routine will setup phy 1 or phy 0 so that it is configured
3016 to match a speed and duplex over-ride option. If speed or
3017 duplex mode is not explicitly specified in the registry, the
3018 driver will skip the speed and duplex over-ride code, and
3019 assume the adapter is automatically setting the line speed, and
3020 the duplex mode. At the end of this routine, any truly Phy
3021 specific code will be executed (each Phy has its own quirks,
3022 and some require that certain special bits are set).
3023
3024 NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
3025 same time. If FORCEDPX is set without speed being set, the driver
3026 will encouter a fatal error and log a message into the event viewer.
3027
3028 Arguments:
3029 AdapterInfo - pointer to the structure that contains the NIC's context.
3030
3031 Returns:
3032 TRUE - If the phy could be configured correctly
3033 FALSE - If the phy couldn't be configured correctly, because an
3034 unsupported over-ride option was used
3035
3036 --*/
3037 {
3038 UINT16 MdiControlReg;
3039 UINT16 MdiStatusReg;
3040 UINT16 MdiIdLowReg;
3041 UINT16 MdiIdHighReg;
3042 UINT16 MdiMiscReg;
3043 UINT32 PhyId;
3044 BOOLEAN ForcePhySetting;
3045
3046 ForcePhySetting = FALSE;
3047
3048 //
3049 // If we are NOT forcing a setting for line speed or full duplex, then
3050 // we won't force a link setting, and we'll jump down to the phy
3051 // specific code.
3052 //
3053 if (((AdapterInfo->LinkSpeedReq) || (AdapterInfo->DuplexReq))) {
3054 //
3055 // Find out what kind of technology this Phy is capable of.
3056 //
3057 MdiRead (
3058 AdapterInfo,
3059 MDI_STATUS_REG,
3060 AdapterInfo->PhyAddress,
3061 &MdiStatusReg
3062 );
3063
3064 //
3065 // Read the MDI control register at our phy
3066 //
3067 MdiRead (
3068 AdapterInfo,
3069 MDI_CONTROL_REG,
3070 AdapterInfo->PhyAddress,
3071 &MdiControlReg
3072 );
3073
3074 //
3075 // Now check the validity of our forced option. If the force option is
3076 // valid, then force the setting. If the force option is not valid,
3077 // we'll set a flag indicating that we should error out.
3078 //
3079
3080 //
3081 // If speed is forced to 10mb
3082 //
3083 if (AdapterInfo->LinkSpeedReq == 10) {
3084 //
3085 // If half duplex is forced
3086 //
3087 if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {
3088 if (MdiStatusReg & MDI_SR_10T_HALF_DPX) {
3089
3090 MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
3091 ForcePhySetting = TRUE;
3092 }
3093 } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {
3094
3095 //
3096 // If full duplex is forced
3097 //
3098 if (MdiStatusReg & MDI_SR_10T_FULL_DPX) {
3099
3100 MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
3101 MdiControlReg |= MDI_CR_FULL_HALF;
3102 ForcePhySetting = TRUE;
3103 }
3104 } else {
3105 //
3106 // If auto duplex (we actually set phy to 1/2)
3107 //
3108 if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX)) {
3109
3110 MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
3111 ForcePhySetting = TRUE;
3112 }
3113 }
3114 }
3115
3116 //
3117 // If speed is forced to 100mb
3118 //
3119 else if (AdapterInfo->LinkSpeedReq == 100) {
3120 //
3121 // If half duplex is forced
3122 //
3123 if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {
3124 if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {
3125
3126 MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
3127 MdiControlReg |= MDI_CR_10_100;
3128 ForcePhySetting = TRUE;
3129 }
3130 } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {
3131 //
3132 // If full duplex is forced
3133 //
3134 if (MdiStatusReg & MDI_SR_TX_FULL_DPX) {
3135 MdiControlReg &= ~MDI_CR_AUTO_SELECT;
3136 MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);
3137 ForcePhySetting = TRUE;
3138 }
3139 } else {
3140 //
3141 // If auto duplex (we set phy to 1/2)
3142 //
3143 if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {
3144
3145 MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
3146 MdiControlReg |= MDI_CR_10_100;
3147 ForcePhySetting = TRUE;
3148 }
3149 }
3150 }
3151
3152 if (!ForcePhySetting) {
3153 return (FALSE);
3154 }
3155
3156 //
3157 // Write the MDI control register with our new Phy configuration
3158 //
3159 MdiWrite (
3160 AdapterInfo,
3161 MDI_CONTROL_REG,
3162 AdapterInfo->PhyAddress,
3163 MdiControlReg
3164 );
3165
3166 //
3167 // wait 100 milliseconds for auto-negotiation to complete
3168 //
3169 DelayIt (AdapterInfo, 100);
3170 }
3171
3172 //
3173 // Find out specifically what Phy this is. We do this because for certain
3174 // phys there are specific bits that must be set so that the phy and the
3175 // 82557 work together properly.
3176 //
3177
3178 MdiRead (
3179 AdapterInfo,
3180 PHY_ID_REG_1,
3181 AdapterInfo->PhyAddress,
3182 &MdiIdLowReg
3183 );
3184 MdiRead (
3185 AdapterInfo,
3186 PHY_ID_REG_2,
3187 AdapterInfo->PhyAddress,
3188 &MdiIdHighReg
3189 );
3190
3191 PhyId = ((UINT32) MdiIdLowReg | ((UINT32) MdiIdHighReg << 16));
3192
3193 //
3194 // And out the revsion field of the Phy ID so that we'll be able to detect
3195 // future revs of the same Phy.
3196 //
3197 PhyId &= PHY_MODEL_REV_ID_MASK;
3198
3199 //
3200 // Handle the National TX
3201 //
3202 if (PhyId == PHY_NSC_TX) {
3203
3204 MdiRead (
3205 AdapterInfo,
3206 NSC_CONG_CONTROL_REG,
3207 AdapterInfo->PhyAddress,
3208 &MdiMiscReg
3209 );
3210
3211 MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);
3212
3213 MdiWrite (
3214 AdapterInfo,
3215 NSC_CONG_CONTROL_REG,
3216 AdapterInfo->PhyAddress,
3217 MdiMiscReg
3218 );
3219 }
3220
3221 FindPhySpeedAndDpx (AdapterInfo, PhyId);
3222
3223 //
3224 // We put a hardware fix on to our adapters to work-around the PHY_100 errata
3225 // described below. The following code is only compiled in, if we wanted
3226 // to attempt a software workaround to the PHY_100 A/B step problem.
3227 //
3228
3229 return (TRUE);
3230 }
3231
3232 VOID
3233 FindPhySpeedAndDpx (
3234 IN NIC_DATA_INSTANCE *AdapterInfo,
3235 IN UINT32 PhyId
3236 )
3237 /*++
3238
3239 Routine Description:
3240 This routine will figure out what line speed and duplex mode
3241 the PHY is currently using.
3242
3243 Arguments:
3244 AdapterInfo - pointer to the structure that contains the NIC's context.
3245 PhyId - The ID of the PHY in question.
3246
3247 Returns:
3248 NOTHING
3249 --*/
3250 {
3251 UINT16 MdiStatusReg;
3252 UINT16 MdiMiscReg;
3253 UINT16 MdiOwnAdReg;
3254 UINT16 MdiLinkPartnerAdReg;
3255
3256 //
3257 // If there was a speed and/or duplex override, then set our current
3258 // value accordingly
3259 //
3260 AdapterInfo->LinkSpeed = AdapterInfo->LinkSpeedReq;
3261 AdapterInfo->Duplex = (UINT8) ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) ?
3262 FULL_DUPLEX : HALF_DUPLEX);
3263
3264 //
3265 // If speed and duplex were forced, then we know our current settings, so
3266 // we'll just return. Otherwise, we'll need to figure out what NWAY set
3267 // us to.
3268 //
3269 if (AdapterInfo->LinkSpeed && AdapterInfo->Duplex) {
3270 return ;
3271
3272 }
3273 //
3274 // If we didn't have a valid link, then we'll assume that our current
3275 // speed is 10mb half-duplex.
3276 //
3277
3278 //
3279 // Read the status register twice because of sticky bits
3280 //
3281 MdiRead (
3282 AdapterInfo,
3283 MDI_STATUS_REG,
3284 AdapterInfo->PhyAddress,
3285 &MdiStatusReg
3286 );
3287 MdiRead (
3288 AdapterInfo,
3289 MDI_STATUS_REG,
3290 AdapterInfo->PhyAddress,
3291 &MdiStatusReg
3292 );
3293
3294 //
3295 // If there wasn't a valid link then use default speed & duplex
3296 //
3297 if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) {
3298
3299 AdapterInfo->LinkSpeed = 10;
3300 AdapterInfo->Duplex = HALF_DUPLEX;
3301 return ;
3302 }
3303
3304 //
3305 // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
3306 // 1 and 0 of extended register 0, to get the current speed and duplex
3307 // settings.
3308 //
3309 if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID)) {
3310 //
3311 // Read extended register 0
3312 //
3313 MdiRead (
3314 AdapterInfo,
3315 EXTENDED_REG_0,
3316 AdapterInfo->PhyAddress,
3317 &MdiMiscReg
3318 );
3319
3320 //
3321 // Get current speed setting
3322 //
3323 if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) {
3324 AdapterInfo->LinkSpeed = 100;
3325 } else {
3326 AdapterInfo->LinkSpeed = 10;
3327 }
3328
3329 //
3330 // Get current duplex setting -- if bit is set then FDX is enabled
3331 //
3332 if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) {
3333 AdapterInfo->Duplex = FULL_DUPLEX;
3334 } else {
3335 AdapterInfo->Duplex = HALF_DUPLEX;
3336 }
3337
3338 return ;
3339 }
3340 //
3341 // Read our link partner's advertisement register
3342 //
3343 MdiRead (
3344 AdapterInfo,
3345 AUTO_NEG_LINK_PARTNER_REG,
3346 AdapterInfo->PhyAddress,
3347 &MdiLinkPartnerAdReg
3348 );
3349
3350 //
3351 // See if Auto-Negotiation was complete (bit 5, reg 1)
3352 //
3353 MdiRead (
3354 AdapterInfo,
3355 MDI_STATUS_REG,
3356 AdapterInfo->PhyAddress,
3357 &MdiStatusReg
3358 );
3359
3360 //
3361 // If a True NWAY connection was made, then we can detect speed/duplex by
3362 // ANDing our adapter's advertised abilities with our link partner's
3363 // advertised ablilities, and then assuming that the highest common
3364 // denominator was chosed by NWAY.
3365 //
3366 if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
3367 (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) {
3368
3369 //
3370 // Read our advertisement register
3371 //
3372 MdiRead (
3373 AdapterInfo,
3374 AUTO_NEG_ADVERTISE_REG,
3375 AdapterInfo->PhyAddress,
3376 &MdiOwnAdReg
3377 );
3378
3379 //
3380 // AND the two advertisement registers together, and get rid of any
3381 // extraneous bits.
3382 //
3383 MdiOwnAdReg = (UINT16) (MdiOwnAdReg & (MdiLinkPartnerAdReg & NWAY_LP_ABILITY));
3384
3385 //
3386 // Get speed setting
3387 //
3388 if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE)) {
3389 AdapterInfo->LinkSpeed = 100;
3390 } else {
3391 AdapterInfo->LinkSpeed = 10;
3392 }
3393
3394 //
3395 // Get duplex setting -- use priority resolution algorithm
3396 //
3397 if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) {
3398 AdapterInfo->Duplex = HALF_DUPLEX;
3399 return ;
3400 } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) {
3401 AdapterInfo->Duplex = FULL_DUPLEX;
3402 return ;
3403 } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) {
3404 AdapterInfo->Duplex = HALF_DUPLEX;
3405 return ;
3406 } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) {
3407 AdapterInfo->Duplex = FULL_DUPLEX;
3408 return ;
3409 } else {
3410 AdapterInfo->Duplex = HALF_DUPLEX;
3411 return ;
3412 }
3413 }
3414
3415 //
3416 // If we are connected to a dumb (non-NWAY) repeater or hub, and the line
3417 // speed was determined automatically by parallel detection, then we have
3418 // no way of knowing exactly what speed the PHY is set to unless that PHY
3419 // has a propietary register which indicates speed in this situation. The
3420 // NSC TX PHY does have such a register. Also, since NWAY didn't establish
3421 // the connection, the duplex setting should HALF duplex.
3422 //
3423 AdapterInfo->Duplex = HALF_DUPLEX;
3424
3425 if (PhyId == PHY_NSC_TX) {
3426 //
3427 // Read register 25 to get the SPEED_10 bit
3428 //
3429 MdiRead (
3430 AdapterInfo,
3431 NSC_SPEED_IND_REG,
3432 AdapterInfo->PhyAddress,
3433 &MdiMiscReg
3434 );
3435
3436 //
3437 // If bit 6 was set then we're at 10mb
3438 //
3439 if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) {
3440 AdapterInfo->LinkSpeed = 10;
3441 } else {
3442 AdapterInfo->LinkSpeed = 100;
3443 }
3444 }
3445
3446 //
3447 // If we don't know what line speed we are set at, then we'll default to
3448 // 10mbs
3449 //
3450 else {
3451 AdapterInfo->LinkSpeed = 10;
3452 }
3453 }
3454
3455 VOID
3456 XmitWaitForCompletion (
3457 NIC_DATA_INSTANCE *AdapterInfo
3458 )
3459 /*++
3460
3461 Routine Description:
3462
3463 TODO: Add function description
3464
3465 Arguments:
3466
3467 AdapterInfo - TODO: add argument description
3468
3469 Returns:
3470
3471 TODO: add return values
3472
3473 --*/
3474 {
3475 TxCB *TxPtr;
3476
3477 if (AdapterInfo->FreeCBCount == AdapterInfo->TxBufCnt) {
3478 return ;
3479 }
3480
3481 //
3482 // used xmit cb list starts right after the free tail (ends before the
3483 // free head ptr)
3484 //
3485 TxPtr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;
3486 while (TxPtr != AdapterInfo->FreeTxHeadPtr) {
3487 CommandWaitForCompletion (TxPtr, AdapterInfo);
3488 SetFreeCB (AdapterInfo, TxPtr);
3489 TxPtr = TxPtr->NextTCBVirtualLinkPtr;
3490 }
3491 }
3492
3493 INT8
3494 CommandWaitForCompletion (
3495 TxCB *cmd_ptr,
3496 NIC_DATA_INSTANCE *AdapterInfo
3497 )
3498 /*++
3499
3500 Routine Description:
3501
3502 TODO: Add function description
3503
3504 Arguments:
3505
3506 cmd_ptr - TODO: add argument description
3507 AdapterInfo - TODO: add argument description
3508
3509 Returns:
3510
3511 TODO: add return values
3512
3513 --*/
3514 {
3515 INT16 wait;
3516 wait = 5000;
3517 while ((cmd_ptr->cb_header.status == 0) && (--wait > 0)) {
3518 DelayIt (AdapterInfo, 10);
3519 }
3520
3521 if (cmd_ptr->cb_header.status == 0) {
3522 return -1;
3523 }
3524
3525 return 0;
3526 }
3527
3528 STATIC
3529 INT8
3530 SoftwareReset (
3531 NIC_DATA_INSTANCE *AdapterInfo
3532 )
3533 /*++
3534
3535 Routine Description:
3536
3537 TODO: Add function description
3538
3539 Arguments:
3540
3541 AdapterInfo - TODO: add argument description
3542
3543 Returns:
3544
3545 TODO: add return values
3546
3547 --*/
3548 {
3549 UINT8 tco_stat;
3550 UINT16 wait;
3551
3552 tco_stat = 0;
3553
3554 //
3555 // Reset the chip: stop Tx and Rx processes and clear counters.
3556 // This takes less than 10usec and will easily finish before the next
3557 // action.
3558 //
3559
3560 OutLong (AdapterInfo, PORT_RESET, AdapterInfo->ioaddr + SCBPort);
3561 //
3562 // wait for 5 milli seconds here!
3563 //
3564 DelayIt (AdapterInfo, 5000);
3565 //
3566 // TCO Errata work around for 559s only
3567 // -----------------------------------------------------------------------------------
3568 // TCO Workaround Code
3569 // haifa workaround
3570 // -----------------------------------------------------------------------------------
3571 // 1. Issue SW-RST ^^^ (already done above)
3572 // 2. Issue a redundant Set CU Base CMD immediately
3573 // Do not set the General Pointer before the Set CU Base cycle
3574 // Do not check the SCB CMD before the Set CU Base cycle
3575 // 3. Wait for the SCB-CMD to be cleared
3576 // this indicates the transition to post-driver
3577 // 4. Poll the TCO-Req bit in the PMDR to be cleared
3578 // this indicates the tco activity has stopped for real
3579 // 5. Proceed with the nominal Driver Init:
3580 // Actual Set CU & RU Base ...
3581 //
3582 // Check for ICH2 device ID. If this is an ICH2,
3583 // do the TCO workaround code.
3584 //
3585 if (AdapterInfo->VendorID == D102_DEVICE_ID ||
3586 AdapterInfo->VendorID == ICH3_DEVICE_ID_1 ||
3587 AdapterInfo->VendorID == ICH3_DEVICE_ID_2 ||
3588 AdapterInfo->VendorID == ICH3_DEVICE_ID_3 ||
3589 AdapterInfo->VendorID == ICH3_DEVICE_ID_4 ||
3590 AdapterInfo->VendorID == ICH3_DEVICE_ID_5 ||
3591 AdapterInfo->VendorID == ICH3_DEVICE_ID_6 ||
3592 AdapterInfo->VendorID == ICH3_DEVICE_ID_7 ||
3593 AdapterInfo->VendorID == ICH3_DEVICE_ID_8 ||
3594 AdapterInfo->RevID >= 8) { // do the TCO fix
3595 //
3596 // donot load the scb pointer but just give load_cu cmd.
3597 //
3598 OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);
3599 //
3600 // wait for command to be accepted.
3601 //
3602 wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
3603 //
3604 // read PMDR register and check bit 1 in it to see if TCO is active
3605 //
3606
3607 //
3608 // wait for 5 milli seconds
3609 //
3610 wait = 5000;
3611 while (wait) {
3612 tco_stat = InByte (AdapterInfo, AdapterInfo->ioaddr + 0x1b);
3613 if ((tco_stat & 2) == 0) {
3614 //
3615 // is the activity bit clear??
3616 //
3617 break;
3618 }
3619
3620 wait--;
3621 DelayIt (AdapterInfo, 1);
3622 }
3623
3624 if ((tco_stat & 2) != 0) {
3625 //
3626 // not zero??
3627 //
3628 return -1;
3629 }
3630 }
3631
3632 return 0;
3633 }
3634
3635 UINT8
3636 SelectiveReset (
3637 IN NIC_DATA_INSTANCE *AdapterInfo
3638 )
3639 /*++
3640
3641 Routine Description:
3642
3643 TODO: Add function description
3644
3645 Arguments:
3646
3647 AdapterInfo - TODO: add argument description
3648
3649 Returns:
3650
3651 TODO: add return values
3652
3653 --*/
3654 {
3655 UINT16 wait;
3656 UINT32 stat;
3657
3658 wait = 10;
3659 stat = 0;
3660 OutLong (AdapterInfo, POR_SELECTIVE_RESET, AdapterInfo->ioaddr + SCBPort);
3661 //
3662 // wait for this to complete
3663 //
3664
3665 //
3666 // wait for 2 milli seconds here!
3667 //
3668 DelayIt (AdapterInfo, 2000);
3669 while (wait > 0) {
3670 wait--;
3671 stat = InLong (AdapterInfo, AdapterInfo->ioaddr + SCBPort);
3672 if (stat == 0) {
3673 break;
3674 }
3675
3676 //
3677 // wait for 1 milli second
3678 //
3679 DelayIt (AdapterInfo, 1000);
3680 }
3681
3682 if (stat != 0) {
3683 return PXE_STATCODE_DEVICE_FAILURE;
3684 }
3685
3686 return 0;
3687 }
3688
3689 UINT16
3690 InitializeChip (
3691 IN NIC_DATA_INSTANCE *AdapterInfo
3692 )
3693 /*++
3694
3695 Routine Description:
3696
3697 TODO: Add function description
3698
3699 Arguments:
3700
3701 AdapterInfo - TODO: add argument description
3702
3703 Returns:
3704
3705 TODO: add return values
3706
3707 --*/
3708 {
3709 UINT16 ret_val;
3710 if (SoftwareReset (AdapterInfo) != 0) {
3711 return PXE_STATCODE_DEVICE_FAILURE;
3712 }
3713
3714 //
3715 // disable interrupts
3716 //
3717 OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
3718
3719 //
3720 // Load the base registers with 0s (we will give the complete address as
3721 // offset later when we issue any command
3722 //
3723 if ((ret_val = Load_Base_Regs (AdapterInfo)) != 0) {
3724 return ret_val;
3725 }
3726
3727 if ((ret_val = SetupCBlink (AdapterInfo)) != 0) {
3728 return ret_val;
3729 }
3730
3731 if ((ret_val = SetupReceiveQueues (AdapterInfo)) != 0) {
3732 return ret_val;
3733 }
3734
3735 //
3736 // detect the PHY only if we need to detect the cable as requested by the
3737 // initialize parameters
3738 //
3739 AdapterInfo->PhyAddress = 0xFF;
3740
3741 if (AdapterInfo->CableDetect != 0) {
3742 if (!PhyDetect (AdapterInfo)) {
3743 return PXE_STATCODE_DEVICE_FAILURE;
3744 }
3745 }
3746
3747 if ((ret_val = E100bSetupIAAddr (AdapterInfo)) != 0) {
3748 return ret_val;
3749 }
3750
3751 if ((ret_val = Configure (AdapterInfo)) != 0) {
3752 return ret_val;
3753 }
3754
3755 return 0;
3756 }
3757
3758 #pragma data_seg()