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