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