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