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