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