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