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