git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1459 6f19259b...
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Undi / RuntimeDxe / E100b.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13 \r
14 \r
15 E100B.C\r
16\r
17Abstract:\r
18\r
19\r
20Revision History\r
21\r
22--*/\r
23\r
24#include "undi32.h"\r
25\r
26static 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
53UINT8\r
54InByte (\r
55 IN NIC_DATA_INSTANCE *AdapterInfo,\r
56 IN UINT32 Port\r
57 )\r
58/*++\r
59\r
60Routine 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
67Arguments:\r
68 Port - Which port to read from.\r
69\r
70Returns:\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
88UINT16\r
89InWord (\r
90 IN NIC_DATA_INSTANCE *AdapterInfo,\r
91 IN UINT32 Port\r
92 )\r
93/*++\r
94\r
95Routine 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
102Arguments:\r
103 Port - Which port to read from.\r
104\r
105Returns:\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
123UINT32\r
124InLong (\r
125 IN NIC_DATA_INSTANCE *AdapterInfo,\r
126 IN UINT32 Port\r
127 )\r
128/*++\r
129\r
130Routine 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
137Arguments:\r
138 Port - Which port to read from.\r
139\r
140Returns:\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
158VOID\r
159OutByte (\r
160 IN NIC_DATA_INSTANCE *AdapterInfo,\r
161 IN UINT8 Data,\r
162 IN UINT32 Port\r
163 )\r
164/*++\r
165\r
166Routine 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
173Arguments:\r
174 Data - Data to write to Port.\r
175 Port - Which port to write to.\r
176\r
177Returns:\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
196VOID\r
197OutWord (\r
198 IN NIC_DATA_INSTANCE *AdapterInfo,\r
199 IN UINT16 Data,\r
200 IN UINT32 Port\r
201 )\r
202/*++\r
203\r
204Routine 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
211Arguments:\r
212 Data - Data to write to Port.\r
213 Port - Which port to write to.\r
214\r
215Returns:\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
234VOID\r
235OutLong (\r
236 IN NIC_DATA_INSTANCE *AdapterInfo,\r
237 IN UINT32 Data,\r
238 IN UINT32 Port\r
239 )\r
240/*++\r
241\r
242Routine 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
249Arguments:\r
250 Data - Data to write to Port.\r
251 Port - Which port to write to.\r
252\r
253Returns:\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
272UINTN\r
273MapIt (\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
282Routine Description:\r
283\r
284 TODO: Add function description\r
285\r
286Arguments:\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
294Returns:\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
340VOID\r
341UnMapIt (\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
350Routine Description:\r
351\r
352 TODO: Add function description\r
353\r
354Arguments:\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
362Returns:\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
387VOID\r
388DelayIt (\r
389 IN NIC_DATA_INSTANCE *AdapterInfo,\r
390 UINT16 MicroSeconds\r
391 )\r
392/*++\r
393\r
394Routine Description:\r
395\r
396Arguments:\r
397 AdapterInfo - Pointer to the NIC data structure information\r
398 which the UNDI driver is layering on..\r
399\r
400Returns:\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
412VOID\r
413BlockIt (\r
414 IN NIC_DATA_INSTANCE *AdapterInfo,\r
415 UINT32 flag\r
416 )\r
417/*++\r
418\r
419Routine Description:\r
420\r
421Arguments:\r
422 AdapterInfo - Pointer to the NIC data structure information\r
423 which the UNDI driver is layering on..\r
424\r
425Returns:\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
437UINT8\r
438Load_Base_Regs (\r
439 NIC_DATA_INSTANCE *AdapterInfo\r
440 )\r
441/*++\r
442\r
443Routine Description:\r
444\r
445 TODO: Add function description\r
446\r
447Arguments:\r
448\r
449 AdapterInfo - TODO: add argument description\r
450\r
451Returns:\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
486UINT8\r
487IssueCB (\r
488 NIC_DATA_INSTANCE *AdapterInfo,\r
489 TxCB *cmd_ptr\r
490 )\r
491/*++\r
492\r
493Routine Description:\r
494\r
495 TODO: Add function description\r
496\r
497Arguments:\r
498\r
499 AdapterInfo - TODO: add argument description\r
500 cmd_ptr - TODO: add argument description\r
501\r
502Returns:\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
552UINT8\r
553Configure (\r
554 NIC_DATA_INSTANCE *AdapterInfo\r
555 )\r
556/*++\r
557\r
558Routine Description:\r
559\r
560 TODO: Add function description\r
561\r
562Arguments:\r
563\r
564 AdapterInfo - TODO: add argument description\r
565\r
566Returns:\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
628UINT8\r
629E100bSetupIAAddr (\r
630 NIC_DATA_INSTANCE *AdapterInfo\r
631 )\r
632/*++\r
633\r
634Routine Description:\r
635\r
636 TODO: Add function description\r
637\r
638Arguments:\r
639\r
640 AdapterInfo - TODO: add argument description\r
641\r
642Returns:\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
689VOID\r
690StopRU (\r
691 IN NIC_DATA_INSTANCE *AdapterInfo\r
692 )\r
693/*++\r
694\r
695Routine Description:\r
696 Instructs the NIC to stop receiving packets.\r
697\r
698Arguments:\r
699 AdapterInfo - Pointer to the NIC data structure information\r
700 which the UNDI driver is layering on..\r
701Returns:\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
724INT8\r
725StartRU (\r
726 NIC_DATA_INSTANCE *AdapterInfo\r
727 )\r
728/*++\r
729\r
730Routine Description:\r
731 Instructs the NIC to start receiving packets.\r
732\r
733Arguments:\r
734 AdapterInfo - Pointer to the NIC data structure information\r
735 which the UNDI driver is layering on..\r
736Returns:\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
763UINTN\r
764E100bInit (\r
765 IN NIC_DATA_INSTANCE *AdapterInfo\r
766 )\r
767/*++\r
768\r
769Routine Description:\r
770 Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.\r
771\r
772Arguments:\r
773 AdapterInfo - Pointer to the NIC data structure information\r
774 which the UNDI driver is layering on..\r
775\r
776Returns:\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
859UINT8\r
860E100bSetInterruptState (\r
861 IN NIC_DATA_INSTANCE *AdapterInfo\r
862 )\r
863/*++\r
864\r
865Routine Description:\r
866 Sets the interrupt state for the NIC.\r
867\r
868Arguments:\r
869 AdapterInfo - Pointer to the NIC data structure information\r
870 which the UNDI driver is layering on..\r
871Returns:\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
906UINTN\r
907E100bSetfilter (\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
915Routine Description:\r
916 Instructs the NIC to start receiving packets.\r
917\r
918Arguments:\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
925Returns:\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
1068UINTN\r
1069E100bTransmit (\r
1070 NIC_DATA_INSTANCE *AdapterInfo,\r
1071 UINT64 cpb,\r
1072 UINT16 opflags\r
1073 )\r
1074/*++\r
1075\r
1076Routine Description:\r
1077\r
1078 TODO: Add function description\r
1079\r
1080Arguments:\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
1086Returns:\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
1256UINTN\r
1257E100bReceive (\r
1258 NIC_DATA_INSTANCE *AdapterInfo,\r
1259 UINT64 cpb,\r
1260 UINT64 db\r
1261 )\r
1262/*++\r
1263\r
1264Routine Description:\r
1265\r
1266 TODO: Add function description\r
1267\r
1268Arguments:\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
1274Returns:\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
1414FreeRFD:\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
1443INT16\r
1444E100bReadEepromAndStationAddress (\r
1445 NIC_DATA_INSTANCE *AdapterInfo\r
1446 )\r
1447/*++\r
1448\r
1449Routine Description:\r
1450\r
1451 TODO: Add function description\r
1452\r
1453Arguments:\r
1454\r
1455 AdapterInfo - TODO: add argument description\r
1456\r
1457Returns:\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
1518UINT8\r
1519SetupCBlink (\r
1520 NIC_DATA_INSTANCE *AdapterInfo\r
1521 )\r
1522/*++\r
1523\r
1524Routine Description:\r
1525\r
1526 TODO: Add function description\r
1527\r
1528Arguments:\r
1529\r
1530 AdapterInfo - TODO: add argument description\r
1531\r
1532Returns:\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
1584TxCB *\r
1585GetFreeCB (\r
1586 NIC_DATA_INSTANCE *AdapterInfo\r
1587 )\r
1588/*++\r
1589\r
1590Routine Description:\r
1591\r
1592 TODO: Add function description\r
1593\r
1594Arguments:\r
1595\r
1596 AdapterInfo - TODO: add argument description\r
1597\r
1598Returns:\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
1631VOID\r
1632SetFreeCB (\r
1633 IN NIC_DATA_INSTANCE *AdapterInfo,\r
1634 IN TxCB *cb_ptr\r
1635 )\r
1636/*++\r
1637\r
1638Routine Description:\r
1639\r
1640 TODO: Add function description\r
1641\r
1642Arguments:\r
1643\r
1644 AdapterInfo - TODO: add argument description\r
1645 cb_ptr - TODO: add argument description\r
1646\r
1647Returns:\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
1665UINT16\r
1666next (\r
1667 IN UINT16 ind\r
1668 )\r
1669/*++\r
1670\r
1671Routine Description:\r
1672\r
1673 TODO: Add function description\r
1674\r
1675Arguments:\r
1676\r
1677 ind - TODO: add argument description\r
1678\r
1679Returns:\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
1695UINT16\r
1696CheckCBList (\r
1697 IN NIC_DATA_INSTANCE *AdapterInfo\r
1698 )\r
1699/*++\r
1700\r
1701Routine Description:\r
1702\r
1703 TODO: Add function description\r
1704\r
1705Arguments:\r
1706\r
1707 AdapterInfo - TODO: add argument description\r
1708\r
1709Returns:\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
1756UINT8\r
1757SetupReceiveQueues (\r
1758 IN NIC_DATA_INSTANCE *AdapterInfo\r
1759 )\r
1760/*++\r
1761\r
1762Routine Description:\r
1763\r
1764 TODO: Add function description\r
1765\r
1766Arguments:\r
1767\r
1768 AdapterInfo - TODO: add argument description\r
1769\r
1770Returns:\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
1819VOID\r
1820Recycle_RFD (\r
1821 IN NIC_DATA_INSTANCE *AdapterInfo,\r
1822 IN UINT16 rx_index\r
1823 )\r
1824/*++\r
1825\r
1826Routine Description:\r
1827\r
1828 TODO: Add function description\r
1829\r
1830Arguments:\r
1831\r
1832 AdapterInfo - TODO: add argument description\r
1833 rx_index - TODO: add argument description\r
1834\r
1835Returns:\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
1893VOID\r
1894shift_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
1901Routine Description:\r
1902\r
1903 TODO: Add function description\r
1904\r
1905Arguments:\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
1911Returns:\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
1951UINT16\r
1952shift_bits_in (\r
1953 IN NIC_DATA_INSTANCE *AdapterInfo\r
1954 )\r
1955/*++\r
1956\r
1957Routine Description:\r
1958\r
1959 TODO: Add function description\r
1960\r
1961Arguments:\r
1962\r
1963 AdapterInfo - TODO: add argument description\r
1964\r
1965Returns:\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
2002BOOLEAN\r
2003E100bSetEepromLockOut (\r
2004 IN NIC_DATA_INSTANCE *AdapterInfo\r
2005 )\r
2006/*++\r
2007\r
2008Routine 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
2013Arguments:\r
2014 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
2015\r
2016Returns:\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
2050VOID\r
2051E100bReSetEepromLockOut (\r
2052 IN NIC_DATA_INSTANCE *AdapterInfo\r
2053 )\r
2054/*++\r
2055\r
2056Routine 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
2061Arguments:\r
2062 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
2063\r
2064Returns:\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
2082UINT16\r
2083E100bReadEeprom (\r
2084 IN NIC_DATA_INSTANCE *AdapterInfo,\r
2085 IN INT32 Location,\r
2086 IN UINT8 AddrLen\r
2087 )\r
2088/*++\r
2089\r
2090Routine 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
2093Arguments:\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
2098Returns:\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
2166UINT8\r
2167E100bGetEepromAddrLen (\r
2168 IN NIC_DATA_INSTANCE *AdapterInfo\r
2169 )\r
2170/*++\r
2171\r
2172Routine 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
2176Arguments:\r
2177 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
2178\r
2179Returns:\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
2278UINTN\r
2279E100bStatistics (\r
2280 NIC_DATA_INSTANCE *AdapterInfo,\r
2281 UINT64 DBaddr,\r
2282 UINT16 DBsize\r
2283 )\r
2284/*++\r
2285\r
2286Routine Description:\r
2287\r
2288 TODO: Add function description\r
2289\r
2290Arguments:\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
2296Returns:\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
2418UINTN\r
2419E100bReset (\r
2420 IN NIC_DATA_INSTANCE *AdapterInfo,\r
2421 IN INT32 OpFlags\r
2422 )\r
2423/*++\r
2424\r
2425Routine Description:\r
2426\r
2427 TODO: Add function description\r
2428\r
2429Arguments:\r
2430\r
2431 AdapterInfo - TODO: add argument description\r
2432 OpFlags - TODO: add argument description\r
2433\r
2434Returns:\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
2489UINTN\r
2490E100bShutdown (\r
2491 IN NIC_DATA_INSTANCE *AdapterInfo\r
2492 )\r
2493/*++\r
2494\r
2495Routine Description:\r
2496\r
2497 TODO: Add function description\r
2498\r
2499Arguments:\r
2500\r
2501 AdapterInfo - TODO: add argument description\r
2502\r
2503Returns:\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
2538VOID\r
2539MdiWrite (\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
2547Routine 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
2552Arguments:\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
2558Returns:\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
2587VOID\r
2588MdiRead (\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
2596Routine 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
2601Arguments:\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
2607Returns:\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
2639VOID\r
2640PhyReset (\r
2641 NIC_DATA_INSTANCE *AdapterInfo\r
2642 )\r
2643/*++\r
2644\r
2645Routine Description:\r
2646 This routine will reset the PHY that the adapter is currently\r
2647 configured to use. \r
2648 \r
2649Arguments:\r
2650 AdapterInfo - pointer to the structure that contains the NIC's context.\r
2651\r
2652Returns:\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
2675BOOLEAN\r
2676PhyDetect (\r
2677 NIC_DATA_INSTANCE *AdapterInfo\r
2678 )\r
2679/*++\r
2680\r
2681Routine 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
2714Arguments:\r
2715 AdapterInfo - pointer to the structure that contains the NIC's context.\r
2716\r
2717Returns:\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
2997BOOLEAN\r
2998SetupPhy (\r
2999 IN NIC_DATA_INSTANCE *AdapterInfo\r
3000 )\r
3001/*++\r
3002\r
3003Routine 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
3017Arguments:\r
3018 AdapterInfo - pointer to the structure that contains the NIC's context.\r
3019\r
3020Returns:\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
3247VOID\r
3248FindPhySpeedAndDpx (\r
3249 IN NIC_DATA_INSTANCE *AdapterInfo,\r
3250 IN UINT32 PhyId\r
3251 )\r
3252/*++\r
3253\r
3254Routine Description:\r
3255 This routine will figure out what line speed and duplex mode\r
3256 the PHY is currently using.\r
3257\r
3258Arguments:\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
3262Returns:\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