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