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