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