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