]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/Lan91xDxe/Lan91xDxe.c
EmbeddedPkg: import Lan91x Ethernet controller driver
[mirror_edk2.git] / EmbeddedPkg / Drivers / Lan91xDxe / Lan91xDxe.c
CommitLineData
4395f82e
LL
1/** @file\r
2* SMSC LAN91x series Network Controller Driver.\r
3*\r
4* Copyright (c) 2013-2017 Linaro.org\r
5*\r
6* Derived from the LAN9118 driver. Original sources\r
7* Copyright (c) 2012-2013, ARM Limited. All rights reserved.\r
8*\r
9* This program and the accompanying materials are licensed and\r
10* made available under the terms and conditions of the BSD License\r
11* which accompanies this distribution. The full text of the license\r
12* may be found at: http://opensource.org/licenses/bsd-license.php\r
13*\r
14* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16*\r
17**/\r
18\r
19#include <Uefi.h>\r
20#include <Uefi/UefiSpec.h>\r
21#include <Base.h>\r
22\r
23// Protocols used by this driver\r
24#include <Protocol/SimpleNetwork.h>\r
25#include <Protocol/ComponentName2.h>\r
26#include <Protocol/PxeBaseCode.h>\r
27#include <Protocol/DevicePath.h>\r
28\r
29// Libraries used by this driver\r
30#include <Library/UefiLib.h>\r
31#include <Library/DebugLib.h>\r
32#include <Library/UefiBootServicesTableLib.h>\r
33#include <Library/MemoryAllocationLib.h>\r
34#include <Library/IoLib.h>\r
35#include <Library/PcdLib.h>\r
36#include <Library/NetLib.h>\r
37#include <Library/DevicePathLib.h>\r
38\r
39// Hardware register definitions\r
40#include "Lan91xDxeHw.h"\r
41\r
42// Debugging output options\r
43//#define LAN91X_PRINT_REGISTERS 1\r
44//#define LAN91X_PRINT_PACKET_HEADERS 1\r
45//#define LAN91X_PRINT_RECEIVE_FILTERS 1\r
46\r
47// Chip power-down option -- UNTESTED\r
48//#define LAN91X_POWER_DOWN 1\r
49\r
50/*---------------------------------------------------------------------------------------------------------------------\r
51\r
52 LAN91x Information Structure\r
53\r
54---------------------------------------------------------------------------------------------------------------------*/\r
55typedef struct _LAN91X_DRIVER {\r
56 // Driver signature\r
57 UINT32 Signature;\r
58 EFI_HANDLE ControllerHandle;\r
59\r
60 // EFI SNP protocol instances\r
61 EFI_SIMPLE_NETWORK_PROTOCOL Snp;\r
62 EFI_SIMPLE_NETWORK_MODE SnpMode;\r
63\r
64 // EFI Snp statistics instance\r
65 EFI_NETWORK_STATISTICS Stats;\r
66\r
67 // Transmit Buffer recycle queue\r
68\r
69 LIST_ENTRY TransmitQueueHead;\r
70\r
71 // Register access variables\r
72 UINTN IoBase; // I/O Base Address\r
73 UINT8 Revision; // Chip Revision Number\r
74 INT8 PhyAd; // Phy Address\r
75 UINT8 BankSel; // Currently selected register bank\r
76\r
77} LAN91X_DRIVER;\r
78\r
79#define LAN91X_NO_PHY (-1) // PhyAd value if PHY not detected\r
80\r
81#define LAN91X_SIGNATURE SIGNATURE_32('S', 'M', '9', '1')\r
82#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN91X_DRIVER, Snp, LAN91X_SIGNATURE)\r
83\r
84#define LAN91X_STALL 2\r
85#define LAN91X_MEMORY_ALLOC_POLLS 100 // Max times to poll for memory allocation\r
86#define LAN91X_PKT_OVERHEAD 6 // Overhead bytes in packet buffer\r
87\r
88// Synchronization TPLs\r
89#define LAN91X_TPL TPL_CALLBACK\r
90\r
91// Most common CRC32 Polynomial for little endian machines\r
92#define CRC_POLYNOMIAL 0xEDB88320\r
93\r
94\r
95typedef struct {\r
96 MAC_ADDR_DEVICE_PATH Lan91x;\r
97 EFI_DEVICE_PATH_PROTOCOL End;\r
98} LAN91X_DEVICE_PATH;\r
99\r
100LAN91X_DEVICE_PATH Lan91xPathTemplate = {\r
101 {\r
102 {\r
103 MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,\r
104 { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) }\r
105 },\r
106 { { 0 } },\r
107 0\r
108 },\r
109 {\r
110 END_DEVICE_PATH_TYPE,\r
111 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
112 { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }\r
113 }\r
114};\r
115\r
116// Chip ID numbers and name strings\r
117#define CHIP_9192 3\r
118#define CHIP_9194 4\r
119#define CHIP_9195 5\r
120#define CHIP_9196 6\r
121#define CHIP_91100 7\r
122#define CHIP_91100FD 8\r
123#define CHIP_91111FD 9\r
124\r
125STATIC CHAR16 CONST * CONST ChipIds[ 16 ] = {\r
126 NULL, NULL, NULL,\r
127 /* 3 */ L"SMC91C90/91C92",\r
128 /* 4 */ L"SMC91C94",\r
129 /* 5 */ L"SMC91C95",\r
130 /* 6 */ L"SMC91C96",\r
131 /* 7 */ L"SMC91C100",\r
132 /* 8 */ L"SMC91C100FD",\r
133 /* 9 */ L"SMC91C11xFD",\r
134 NULL, NULL, NULL,\r
135 NULL, NULL, NULL\r
136};\r
137\r
138/* ------------------ TxBuffer Queue structures ------------------- */\r
139\r
140typedef struct {\r
141 VOID *Buf;\r
142 UINTN Length;\r
143} MSK_SYSTEM_BUF;\r
144\r
145typedef struct {\r
146 UINTN Signature;\r
147 LIST_ENTRY Link;\r
148 MSK_SYSTEM_BUF SystemBuf;\r
149} MSK_LINKED_SYSTEM_BUF;\r
150\r
151#define TX_MBUF_SIGNATURE SIGNATURE_32 ('t','x','m','b')\r
152\r
153/* ------------------ MAC Address Hash Calculations ------------------- */\r
154\r
155/*\r
156** Generate a hash value from a multicast address\r
157**\r
158** This uses the Ethernet standard CRC32 algorithm\r
159**\r
160** INFO USED:\r
161** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check\r
162**\r
163** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html\r
164**\r
165** 3: http://en.wikipedia.org/wiki/Computation_of_CRC\r
166*/\r
167STATIC\r
168UINT32\r
169MulticastHash (\r
170 IN EFI_MAC_ADDRESS *Mac,\r
171 IN UINT32 AddrLen\r
172 )\r
173{\r
174 UINT32 Iter;\r
175 UINT32 Remainder;\r
176 UINT32 Crc32;\r
177 UINT8 *Addr;\r
178\r
179 // 0xFFFFFFFF is standard seed for Ethernet\r
180 Remainder = 0xFFFFFFFF;\r
181\r
182 // Generate the remainder byte-by-byte (LSB first)\r
183 Addr = &Mac->Addr[0];\r
184 while (AddrLen-- > 0) {\r
185 Remainder ^= *Addr++;\r
186 for (Iter = 0; Iter < 8; ++Iter) {\r
187 // Check if exponent is set\r
188 if ((Remainder & 1) != 0) {\r
189 Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL;\r
190 } else {\r
191 Remainder = (Remainder >> 1) ^ 0;\r
192 }\r
193 }\r
194 }\r
195\r
196 // Reverse the bits of the remainder\r
197 Crc32 = 0;\r
198 for (Iter = 0; Iter < 32; ++Iter) {\r
199 Crc32 <<= 1;\r
200 Crc32 |= Remainder & 1;\r
201 Remainder >>= 1;\r
202 }\r
203 return Crc32;\r
204}\r
205\r
206\r
207/* ---------------- Banked Register Operations ------------------ */\r
208\r
209// Select the proper I/O bank\r
210STATIC\r
211VOID\r
212SelectIoBank (\r
213 LAN91X_DRIVER *LanDriver,\r
214 UINTN Register\r
215 )\r
216{\r
217 UINT8 Bank;\r
218\r
219 Bank = RegisterToBank (Register);\r
220\r
221 // Select the proper I/O bank\r
222 if (LanDriver->BankSel != Bank) {\r
223 MmioWrite16 (LanDriver->IoBase + LAN91X_BANK_OFFSET, Bank);\r
224 LanDriver->BankSel = Bank;\r
225 }\r
226}\r
227\r
228// Read a 16-bit I/O-space register\r
229STATIC\r
230UINT16\r
231ReadIoReg16 (\r
232 LAN91X_DRIVER *LanDriver,\r
233 UINTN Register\r
234 )\r
235{\r
236 UINT8 Offset;\r
237\r
238 // Select the proper I/O bank\r
239 SelectIoBank (LanDriver, Register);\r
240\r
241 // Read the requested register\r
242 Offset = RegisterToOffset (Register);\r
243 return MmioRead16 (LanDriver->IoBase + Offset);\r
244}\r
245\r
246// Write a 16-bit I/O-space register\r
247STATIC\r
248UINT16\r
249WriteIoReg16 (\r
250 LAN91X_DRIVER *LanDriver,\r
251 UINTN Register,\r
252 UINT16 Value\r
253 )\r
254{\r
255 UINT8 Offset;\r
256\r
257 // Select the proper I/O bank\r
258 SelectIoBank (LanDriver, Register);\r
259\r
260 // Write the requested register\r
261 Offset = RegisterToOffset (Register);\r
262 return MmioWrite16 (LanDriver->IoBase + Offset, Value);\r
263}\r
264\r
265// Read an 8-bit I/O-space register\r
266STATIC\r
267UINT8\r
268ReadIoReg8 (\r
269 LAN91X_DRIVER *LanDriver,\r
270 UINTN Register\r
271 )\r
272{\r
273 UINT8 Offset;\r
274\r
275 // Select the proper I/O bank\r
276 SelectIoBank (LanDriver, Register);\r
277\r
278 // Read the requested register\r
279 Offset = RegisterToOffset (Register);\r
280 return MmioRead8 (LanDriver->IoBase + Offset);\r
281}\r
282\r
283// Write an 8-bit I/O-space register\r
284STATIC\r
285UINT8\r
286WriteIoReg8 (\r
287 LAN91X_DRIVER *LanDriver,\r
288 UINTN Register,\r
289 UINT8 Value\r
290 )\r
291{\r
292 UINT8 Offset;\r
293\r
294 // Select the proper I/O bank\r
295 SelectIoBank (LanDriver, Register);\r
296\r
297 // Write the requested register\r
298 Offset = RegisterToOffset (Register);\r
299 return MmioWrite8 (LanDriver->IoBase + Offset, Value);\r
300}\r
301\r
302\r
303/* ---------------- MII/PHY Access Operations ------------------ */\r
304\r
305#define LAN91X_MDIO_STALL 1\r
306\r
307STATIC\r
308VOID\r
309MdioOutput (\r
310 LAN91X_DRIVER *LanDriver,\r
311 UINTN Bits,\r
312 UINT32 Value\r
313 )\r
314{\r
315 UINT16 MgmtReg;\r
316 UINT32 Mask;\r
317\r
318 MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);\r
319 MgmtReg &= ~MGMT_MCLK;\r
320 MgmtReg |= MGMT_MDOE;\r
321\r
322 for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) {\r
323 if ((Value & Mask) != 0) {\r
324 MgmtReg |= MGMT_MDO;\r
325 } else {\r
326 MgmtReg &= ~MGMT_MDO;\r
327 }\r
328\r
329 WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);\r
330 gBS->Stall (LAN91X_MDIO_STALL);\r
331 WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK);\r
332 gBS->Stall (LAN91X_MDIO_STALL);\r
333 }\r
334}\r
335#define PHY_OUTPUT_TIME (2 * LAN91X_MDIO_STALL)\r
336\r
337STATIC\r
338UINT32\r
339MdioInput (\r
340 LAN91X_DRIVER *LanDriver,\r
341 UINTN Bits\r
342 )\r
343{\r
344 UINT16 MgmtReg;\r
345 UINT32 Mask;\r
346 UINT32 Value;\r
347\r
348 MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);\r
349 MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO);\r
350 WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);\r
351\r
352 Value = 0;\r
353 for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) {\r
354 if ((ReadIoReg16 (LanDriver, LAN91X_MGMT) & MGMT_MDI) != 0) {\r
355 Value |= Mask;\r
356 }\r
357\r
358 WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);\r
359 gBS->Stall (LAN91X_MDIO_STALL);\r
360 WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK);\r
361 gBS->Stall (LAN91X_MDIO_STALL);\r
362 }\r
363\r
364 return Value;\r
365}\r
366#define PHY_INPUT_TIME (2 * LAN91X_MDIO_STALL)\r
367\r
368STATIC\r
369VOID\r
370MdioIdle (\r
371 LAN91X_DRIVER *LanDriver\r
372 )\r
373{\r
374 UINT16 MgmtReg;\r
375\r
376 MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);\r
377 MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO);\r
378 WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);\r
379}\r
380\r
381// Write to a PHY register\r
382STATIC\r
383VOID\r
384WritePhyReg16 (\r
385 LAN91X_DRIVER *LanDriver,\r
386 UINTN RegAd,\r
387 UINT16 Value\r
388 )\r
389{\r
390 // Bit-bang the MII Serial Frame write operation\r
391 MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble\r
392 MdioOutput (LanDriver, 2, 0x01); // Send Start (01)\r
393 MdioOutput (LanDriver, 2, 0x01); // Send Write (01)\r
394 MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0]\r
395 MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0]\r
396 MdioOutput (LanDriver, 2, 0x02); // Send TurnAround (10)\r
397 MdioOutput (LanDriver, 16, Value); // Write 16 data bits\r
398\r
399 // Idle the MDIO bus\r
400 MdioIdle (LanDriver);\r
401}\r
402// Calculate approximate time to write a PHY register in microseconds\r
403#define PHY_WRITE_TIME ((32 + 2 + 2 + 5 + 5 + 2 + 16) * PHY_OUTPUT_TIME)\r
404\r
405// Read from a PHY register\r
406STATIC\r
407UINT16\r
408ReadPhyReg16 (\r
409 LAN91X_DRIVER *LanDriver,\r
410 UINTN RegAd\r
411 )\r
412{\r
413 UINT32 Value;\r
414\r
415 // Bit-bang the MII Serial Frame read operation\r
416 MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble\r
417 MdioOutput (LanDriver, 2, 0x01); // Send Start (01)\r
418 MdioOutput (LanDriver, 2, 0x02); // Send Read (10)\r
419 MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0]\r
420 MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0]\r
421\r
422 (VOID) MdioInput (LanDriver, 2); // Discard TurnAround bits\r
423 Value = MdioInput (LanDriver, 16); // Read 16 data bits\r
424\r
425 // Idle the MDIO bus\r
426 MdioIdle (LanDriver);\r
427\r
428 return (Value & 0xffff);\r
429}\r
430// Calculate approximate time to read a PHY register in microseconds\r
431#define PHY_READ_TIME (((32 + 2 + 2 + 5 + 5) * PHY_OUTPUT_TIME) + \\r
432 ((2 + 16) * PHY_INPUT_TIME))\r
433\r
434\r
435/* ---------------- Debug Functions ------------------ */\r
436\r
437#ifdef LAN91X_PRINT_REGISTERS\r
438STATIC\r
439VOID\r
440PrintIoRegisters (\r
441 IN LAN91X_DRIVER *LanDriver\r
442 )\r
443{\r
444 UINTN Bank;\r
445 UINTN Offset;\r
446 UINT16 Value;\r
447\r
448 DEBUG ((DEBUG_ERROR, "\nLAN91x I/O Register Dump:\n"));\r
449\r
450 // Print currrent bank select register\r
451 Value = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);\r
452 DEBUG ((DEBUG_ERROR, " BankSel: %d Bank Register %04x (%d)\n",\r
453 LanDriver->BankSel, Value, Value & 0x0007));\r
454\r
455 // Print all I/O registers\r
456 for (Offset = 0; Offset < 0x0e; Offset += 2) {\r
457 DEBUG ((DEBUG_ERROR, " %02x:", Offset));\r
458 for (Bank = 0; Bank <= 3; ++Bank) {\r
459 DEBUG ((DEBUG_ERROR, " %04x", ReadIoReg16 (LanDriver, MakeRegister (Bank, Offset))));\r
460 }\r
461 DEBUG ((DEBUG_ERROR, "\n"));\r
462 }\r
463}\r
464\r
465STATIC\r
466VOID\r
467PrintPhyRegisters (\r
468 IN LAN91X_DRIVER *LanDriver\r
469 )\r
470{\r
471 UINTN RegNum;\r
472\r
473 DEBUG ((DEBUG_ERROR, "\nLAN91x Phy %d Register Dump:\n", LanDriver->PhyAd));\r
474\r
475 // Print all Phy registers\r
476 for (RegNum = 0; RegNum <= 5; ++RegNum) {\r
477 DEBUG ((DEBUG_ERROR, " %2d: %04x\n",\r
478 RegNum,\r
479 ReadPhyReg16 (LanDriver, RegNum)\r
480 ));\r
481 }\r
482 for (RegNum = 16; RegNum <= 20; ++RegNum) {\r
483 DEBUG ((DEBUG_ERROR, " %2d: %04x\n",\r
484 RegNum,\r
485 ReadPhyReg16 (LanDriver, RegNum)\r
486 ));\r
487 }\r
488}\r
489#endif\r
490\r
491#if LAN91X_PRINT_PACKET_HEADERS\r
492STATIC\r
493VOID\r
494PrintIpDgram (\r
495 IN CONST VOID *DstMac,\r
496 IN CONST VOID *SrcMac,\r
497 IN CONST VOID *Proto,\r
498 IN CONST VOID *IpDgram\r
499 )\r
500{\r
501 CONST UINT8 *Ptr;\r
502 UINT16 SrcPort;\r
503 UINT16 DstPort;\r
504\r
505 Ptr = DstMac;\r
506 DEBUG ((DEBUG_ERROR, " Dst: %02x-%02x-%02x",\r
507 Ptr[0], Ptr[1], Ptr[2]));\r
508 DEBUG ((DEBUG_ERROR, "-%02x-%02x-%02x",\r
509 Ptr[3], Ptr[4], Ptr[5]));\r
510\r
511 Ptr = SrcMac;\r
512 DEBUG ((DEBUG_ERROR, " Src: %02x-%02x-%02x",\r
513 Ptr[0], Ptr[1], Ptr[2]));\r
514 DEBUG ((DEBUG_ERROR, "-%02x-%02x-%02x",\r
515 Ptr[3], Ptr[4], Ptr[5]));\r
516\r
517 Ptr = Proto;\r
518 DEBUG ((DEBUG_ERROR, " Proto: %02x%02x\n",\r
519 Ptr[0], Ptr[1]));\r
520\r
521 Ptr = IpDgram;\r
522 switch (Ptr[9]) {\r
523 case EFI_IP_PROTO_ICMP:\r
524 DEBUG ((DEBUG_ERROR, " ICMP"));\r
525 break;\r
526 case EFI_IP_PROTO_TCP:\r
527 DEBUG ((DEBUG_ERROR, " TCP"));\r
528 break;\r
529 case EFI_IP_PROTO_UDP:\r
530 DEBUG ((DEBUG_ERROR, " UDP"));\r
531 break;\r
532 default:\r
533 DEBUG ((DEBUG_ERROR, " IpProto %d\n", Ptr[9]));\r
534 return;\r
535 }\r
536\r
537 DEBUG ((DEBUG_ERROR, " SrcIp: %d.%d.%d.%d",\r
538 Ptr[12], Ptr[13], Ptr[14], Ptr[15]));\r
539 DEBUG ((DEBUG_ERROR, " DstIp: %d.%d.%d.%d",\r
540 Ptr[16], Ptr[17], Ptr[18], Ptr[19]));\r
541\r
542 SrcPort = (Ptr[20] << 8) | Ptr[21];\r
543 DstPort = (Ptr[22] << 8) | Ptr[23];\r
544 DEBUG ((DEBUG_ERROR, " SrcPort: %d DstPort: %d\n", SrcPort, DstPort));\r
545}\r
546#endif\r
547\r
548\r
549/* ---------------- PHY Management Operations ----------------- */\r
550\r
551STATIC\r
552EFI_STATUS\r
553PhyDetect (\r
554 IN LAN91X_DRIVER *LanDriver\r
555 )\r
556{\r
557 UINT16 PhyId1;\r
558 UINT16 PhyId2;\r
559\r
560 for (LanDriver->PhyAd = 0x1f; LanDriver->PhyAd >= 0 ; --LanDriver->PhyAd) {\r
561 PhyId1 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID1);\r
562 PhyId2 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID2);\r
563\r
564 if ((PhyId1 != 0x0000) && (PhyId1 != 0xffff) &&\r
565 (PhyId2 != 0x0000) && (PhyId2 != 0xffff)) {\r
566 if ((PhyId1 == 0x0016) && ((PhyId2 & 0xfff0) == 0xf840)) {\r
567 DEBUG ((DEBUG_ERROR, "LAN91x: PHY type LAN83C183 (LAN91C111 Internal)\n"));\r
568 } else if ((PhyId1 == 0x0282) && ((PhyId2 & 0xfff0) == 0x1c50)) {\r
569 DEBUG ((DEBUG_ERROR, "LAN91x: PHY type LAN83C180\n"));\r
570 } else {\r
571 DEBUG ((DEBUG_ERROR, "LAN91x: PHY id %04x:%04x\n", PhyId1, PhyId2));\r
572 }\r
573 return EFI_SUCCESS;\r
574 }\r
575 }\r
576\r
577 DEBUG ((DEBUG_ERROR, "LAN91x: PHY detection failed\n"));\r
578 return EFI_NO_MEDIA;\r
579}\r
580\r
581\r
582// Check the Link Status and take appropriate action\r
583STATIC\r
584BOOLEAN\r
585CheckLinkStatus (\r
586 IN LAN91X_DRIVER *LanDriver\r
587 )\r
588{\r
589 UINT16 PhyStatus;\r
590\r
591 // Get the PHY Status\r
592 PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS);\r
593\r
594 return (PhyStatus & PHYSTS_LINK_STS) != 0;\r
595}\r
596\r
597\r
598// Do auto-negotiation\r
599STATIC\r
600EFI_STATUS\r
601PhyAutoNegotiate (\r
602 IN LAN91X_DRIVER *LanDriver\r
603 )\r
604{\r
605 UINTN Retries;\r
606 UINT16 PhyControl;\r
607 UINT16 PhyStatus;\r
608 UINT16 PhyAdvert;\r
609\r
610 // If there isn't a PHY, don't try to reset it\r
611 if (LanDriver->PhyAd == LAN91X_NO_PHY) {\r
612 return EFI_SUCCESS;\r
613 }\r
614\r
615 // Next check that auto-negotiation is supported\r
616 PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS);\r
617 if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) {\r
618 return EFI_SUCCESS;\r
619 }\r
620\r
621 // Translate capabilities to advertise\r
622 PhyAdvert = PHYANA_CSMA;\r
623\r
624 if ((PhyStatus & PHYSTS_10BASET_HDPLX) != 0) {\r
625 PhyAdvert |= PHYANA_10BASET;\r
626 }\r
627 if ((PhyStatus & PHYSTS_10BASET_FDPLX) != 0) {\r
628 PhyAdvert |= PHYANA_10BASETFD;\r
629 }\r
630 if ((PhyStatus & PHYSTS_100BASETX_HDPLX) != 0) {\r
631 PhyAdvert |= PHYANA_100BASETX;\r
632 }\r
633 if ((PhyStatus & PHYSTS_100BASETX_FDPLX) != 0) {\r
634 PhyAdvert |= PHYANA_100BASETXFD;\r
635 }\r
636 if ((PhyStatus & PHYSTS_100BASE_T4) != 0) {\r
637 PhyAdvert |= PHYANA_100BASET4;\r
638 }\r
639\r
640 // Set the capabilities to advertise\r
641 WritePhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert);\r
642 (VOID) ReadPhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT);\r
643\r
644 // Restart Auto-Negotiation\r
645 PhyControl = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL);\r
646 PhyControl &= ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE);\r
647 PhyControl |= PHYCR_AUTO_EN | PHYCR_RST_AUTO;\r
648 WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PhyControl);\r
649\r
650 // Wait up to 2 seconds for the process to complete\r
651 Retries = 2000000 / (PHY_READ_TIME + 100);\r
652 while ((ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0) {\r
653 if (--Retries == 0) {\r
654 DEBUG ((DEBUG_ERROR, "LAN91x: PHY auto-negotiation timed-out\n"));\r
655 return EFI_TIMEOUT;\r
656 }\r
657 gBS->Stall (100);\r
658 }\r
659\r
660 return EFI_SUCCESS;\r
661}\r
662\r
663\r
664// Perform PHY software reset\r
665STATIC\r
666EFI_STATUS\r
667PhySoftReset (\r
668 IN LAN91X_DRIVER *LanDriver\r
669 )\r
670{\r
671 UINTN Retries;\r
672\r
673 // If there isn't a PHY, don't try to reset it\r
674 if (LanDriver->PhyAd == LAN91X_NO_PHY) {\r
675 return EFI_SUCCESS;\r
676 }\r
677\r
678 // Request a PHY reset\r
679 WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PHYCR_RESET);\r
680\r
681 // The internal PHY will reset within 50ms. Allow 100ms.\r
682 Retries = 100000 / (PHY_READ_TIME + 100);\r
683 while (ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) {\r
684 if (--Retries == 0) {\r
685 DEBUG ((DEBUG_ERROR, "LAN91x: PHY reset timed-out\n"));\r
686 return EFI_TIMEOUT;\r
687 }\r
688 gBS->Stall (100);\r
689 }\r
690\r
691 return EFI_SUCCESS;\r
692}\r
693\r
694\r
695/* ---------------- General Operations ----------------- */\r
696\r
697STATIC\r
698EFI_MAC_ADDRESS\r
699GetCurrentMacAddress (\r
700 IN LAN91X_DRIVER *LanDriver\r
701 )\r
702{\r
703 UINTN RegNum;\r
704 UINT8 *Addr;\r
705 EFI_MAC_ADDRESS MacAddress;\r
706\r
707 SetMem (&MacAddress, sizeof(MacAddress), 0);\r
708\r
709 Addr = &MacAddress.Addr[0];\r
710 for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) {\r
711 *Addr = ReadIoReg8 (LanDriver, RegNum);\r
712 ++Addr;\r
713 }\r
714\r
715 return MacAddress;\r
716}\r
717\r
718STATIC\r
719EFI_STATUS\r
720SetCurrentMacAddress (\r
721 IN LAN91X_DRIVER *LanDriver,\r
722 IN EFI_MAC_ADDRESS *MacAddress\r
723 )\r
724{\r
725 UINTN RegNum;\r
726 UINT8 *Addr;\r
727\r
728 Addr = &MacAddress->Addr[0];\r
729 for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) {\r
730 WriteIoReg8 (LanDriver, RegNum, *Addr);\r
731 ++Addr;\r
732 }\r
733\r
734 return EFI_SUCCESS;\r
735}\r
736\r
737STATIC\r
738EFI_STATUS\r
739MmuOperation (\r
740 IN LAN91X_DRIVER *LanDriver,\r
741 IN UINTN MmuOp\r
742 )\r
743{\r
744 UINTN Polls;\r
745\r
746 WriteIoReg16 (LanDriver, LAN91X_MMUCR, MmuOp);\r
747 Polls = 100;\r
748 while ((ReadIoReg16 (LanDriver, LAN91X_MMUCR) & MMUCR_BUSY) != 0) {\r
749 if (--Polls == 0) {\r
750 DEBUG ((DEBUG_ERROR, "LAN91x: MMU operation %04x timed-out\n", MmuOp));\r
751 return EFI_TIMEOUT;\r
752 }\r
753 gBS->Stall (LAN91X_STALL);\r
754 }\r
755\r
756 return EFI_SUCCESS;\r
757}\r
758\r
759// Read bytes from the DATA register\r
760STATIC\r
761EFI_STATUS\r
762ReadIoData (\r
763 IN LAN91X_DRIVER *LanDriver,\r
764 IN VOID *Buffer,\r
765 IN UINTN BufLen\r
766 )\r
767{\r
768 UINT8 *Ptr;\r
769\r
770 Ptr = Buffer;\r
771 for (; BufLen > 0; --BufLen) {\r
772 *Ptr = ReadIoReg8 (LanDriver, LAN91X_DATA0);\r
773 ++Ptr;\r
774 }\r
775\r
776 return EFI_SUCCESS;\r
777}\r
778\r
779// Write bytes to the DATA register\r
780STATIC\r
781EFI_STATUS\r
782WriteIoData (\r
783 IN LAN91X_DRIVER *LanDriver,\r
784 IN VOID *Buffer,\r
785 IN UINTN BufLen\r
786 )\r
787{\r
788 UINT8 *Ptr;\r
789\r
790 Ptr = Buffer;\r
791 for (; BufLen > 0; --BufLen) {\r
792 WriteIoReg8 (LanDriver, LAN91X_DATA0, *Ptr);\r
793 ++Ptr;\r
794 }\r
795\r
796 return EFI_SUCCESS;\r
797}\r
798\r
799// Disable the interface\r
800STATIC\r
801EFI_STATUS\r
802ChipDisable (\r
803 IN LAN91X_DRIVER *LanDriver\r
804 )\r
805{\r
806#ifdef LAN91X_POWER_DOWN\r
807 UINT16 Val16;\r
808#endif\r
809\r
810 // Stop Rx and Tx operations\r
811 WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);\r
812 WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR);\r
813\r
814#ifdef LAN91X_POWER_DOWN\r
815 // Power-down the chip\r
816 Val16 = ReadIoReg16 (LanDriver, LAN91X_CR);\r
817 Val16 &= ~CR_EPH_POWER_EN;\r
818 WriteIoReg16 (LanDriver, LAN91X_CR, Val16);\r
819#endif\r
820\r
821 return EFI_SUCCESS;\r
822}\r
823\r
824// Enable the interface\r
825STATIC\r
826EFI_STATUS\r
827ChipEnable (\r
828 IN LAN91X_DRIVER *LanDriver\r
829 )\r
830{\r
831#ifdef LAN91X_POWER_DOWN\r
832 UINT16 Val16;\r
833\r
834 // Power-up the chip\r
835 Val16 = ReadIoReg16 (LanDriver, LAN91X_CR);\r
836 Val16 |= CR_EPH_POWER_EN;\r
837 WriteIoReg16 (LanDriver, LAN91X_CR, Val16);\r
838 gBS->Stall (LAN91X_STALL);\r
839#endif\r
840\r
841 // Start Rx and Tx operations\r
842 WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_DEFAULT);\r
843 WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_DEFAULT);\r
844\r
845 return EFI_SUCCESS;\r
846}\r
847\r
848\r
849// Perform software reset on the LAN91x\r
850STATIC\r
851EFI_STATUS\r
852SoftReset (\r
853 IN LAN91X_DRIVER *LanDriver\r
854 )\r
855{\r
856 UINT16 Val16;\r
857\r
858 // Issue the reset\r
859 WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_SOFT_RST);\r
860 gBS->Stall (LAN91X_STALL);\r
861 WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);\r
862\r
863 // Set the configuration register\r
864 WriteIoReg16 (LanDriver, LAN91X_CR, CR_DEFAULT);\r
865 gBS->Stall (LAN91X_STALL);\r
866\r
867 // Stop Rx and Tx\r
868 WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);\r
869 WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR);\r
870\r
871 // Initialize the Control Register\r
872 Val16 = ReadIoReg16 (LanDriver, LAN91X_CTR);\r
873 Val16 |= CTR_AUTO_REL;\r
874 WriteIoReg16 (LanDriver, LAN91X_CTR, Val16);\r
875\r
876 // Reset the MMU\r
877 MmuOperation (LanDriver, MMUCR_OP_RESET_MMU);\r
878\r
879 return EFI_SUCCESS;\r
880}\r
881\r
882/*\r
883** Probe()\r
884**\r
885** Validate that there is a LAN91x device.\r
886**\r
887*/\r
888STATIC\r
889EFI_STATUS\r
890Probe (\r
891 IN LAN91X_DRIVER *LanDriver\r
892 )\r
893{\r
894 UINT16 Bank;\r
895 UINT16 Val16;\r
896 CHAR16 CONST *ChipId;\r
897 UINTN ResetTime;\r
898\r
899 // First check that the Bank Select register is valid\r
900 Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);\r
901 if ((Bank & 0xff00) != 0x3300) {\r
902 DEBUG ((DEBUG_ERROR, "LAN91x: signature error: expecting 33xx, read %04x\n", Bank));\r
903 return EFI_DEVICE_ERROR;\r
904 }\r
905\r
906 // Try reading the revision register next\r
907 LanDriver->BankSel = 0xff;\r
908 Val16 = ReadIoReg16 (LanDriver, LAN91X_REV);\r
909\r
910 Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);\r
911 if ((Bank & 0xff03) != 0x3303) {\r
912 DEBUG ((DEBUG_ERROR, "LAN91x: signature error: expecting 33x3, read %04x\n", Bank));\r
913 return EFI_DEVICE_ERROR;\r
914 }\r
915\r
916 // Validate the revision register\r
917 if ((Val16 & 0xff00) != 0x3300) {\r
918 DEBUG ((DEBUG_ERROR, "LAN91x: revision error: expecting 33xx, read %04x\n", Val16));\r
919 return EFI_DEVICE_ERROR;\r
920 }\r
921\r
922 ChipId = ChipIds[(Val16 >> 4) & 0x0f];\r
923 if (ChipId == NULL) {\r
924 DEBUG ((DEBUG_ERROR, "LAN91x: unrecognized revision: %04x\n", Val16));\r
925 return EFI_DEVICE_ERROR;\r
926 }\r
927 DEBUG ((DEBUG_ERROR, "LAN91x: detected chip %s rev %d\n", ChipId, Val16 & 0xf));\r
928 LanDriver->Revision = Val16 & 0xff;\r
929\r
930 // Reload from EEPROM to get the hardware MAC address\r
931 WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED | CTR_RELOAD);\r
932 ResetTime = 1000;\r
933 while ((ReadIoReg16 (LanDriver, LAN91X_CTR) & CTR_RELOAD) != 0) {\r
934 if (--ResetTime == 0) {\r
935 DEBUG ((DEBUG_ERROR, "LAN91x: reload from EEPROM timed-out\n"));\r
936 WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED);\r
937 return EFI_DEVICE_ERROR;\r
938 }\r
939 gBS->Stall (LAN91X_STALL);\r
940 }\r
941\r
942 // Read and save the Permanent MAC Address\r
943 LanDriver->SnpMode.PermanentAddress = GetCurrentMacAddress (LanDriver);\r
944 LanDriver->SnpMode.CurrentAddress = LanDriver->SnpMode.PermanentAddress;\r
945 DEBUG ((DEBUG_ERROR, //DEBUG_NET | DEBUG_INFO,\r
946 "LAN91x: HW MAC Address: %02x-%02x-%02x-%02x-%02x-%02x\n",\r
947 LanDriver->SnpMode.PermanentAddress.Addr[0],\r
948 LanDriver->SnpMode.PermanentAddress.Addr[1],\r
949 LanDriver->SnpMode.PermanentAddress.Addr[2],\r
950 LanDriver->SnpMode.PermanentAddress.Addr[3],\r
951 LanDriver->SnpMode.PermanentAddress.Addr[4],\r
952 LanDriver->SnpMode.PermanentAddress.Addr[5]\r
953 ));\r
954\r
955 // Reset the device\r
956 SoftReset (LanDriver);\r
957\r
958 // Try to detect a PHY\r
959 if (LanDriver->Revision > (CHIP_91100 << 4)) {\r
960 PhyDetect (LanDriver);\r
961 } else {\r
962 LanDriver->PhyAd = LAN91X_NO_PHY;\r
963 }\r
964\r
965 return EFI_SUCCESS;\r
966}\r
967\r
968\r
969\r
970\r
971/*------------------ Simple Network Driver entry point functions ------------------*/\r
972\r
973// Refer to the Simple Network Protocol section (21.1)\r
974// in the UEFI 2.3.1 Specification for documentation.\r
975\r
976#define ReturnUnlock(s) do { Status = (s); goto exit_unlock; } while(0)\r
977\r
978\r
979/*\r
980** UEFI Start() function\r
981**\r
982*/\r
983EFI_STATUS\r
984EFIAPI\r
985SnpStart (\r
986 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
987 )\r
988{\r
989 EFI_SIMPLE_NETWORK_MODE *Mode;\r
990 EFI_TPL SavedTpl;\r
991 EFI_STATUS Status;\r
992\r
993 // Check Snp instance\r
994 if (Snp == NULL) {\r
995 return EFI_INVALID_PARAMETER;\r
996 }\r
997\r
998 // Serialize access to data and registers\r
999 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1000 Mode = Snp->Mode;\r
1001\r
1002 // Check state of the driver\r
1003 switch (Mode->State) {\r
1004 case EfiSimpleNetworkStopped:\r
1005 break;\r
1006 case EfiSimpleNetworkStarted:\r
1007 case EfiSimpleNetworkInitialized:\r
1008 DEBUG ((DEBUG_WARN, "LAN91x: Driver already started\n"));\r
1009 ReturnUnlock (EFI_ALREADY_STARTED);\r
1010 default:\r
1011 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1012 (UINTN)Snp->Mode->State));\r
1013 ReturnUnlock (EFI_DEVICE_ERROR);\r
1014 }\r
1015\r
1016\r
1017 // Change state\r
1018 Mode->State = EfiSimpleNetworkStarted;\r
1019 Status = EFI_SUCCESS;\r
1020\r
1021 // Restore TPL and return\r
1022exit_unlock:\r
1023 gBS->RestoreTPL (SavedTpl);\r
1024 return Status;\r
1025}\r
1026\r
1027/*\r
1028** UEFI Stop() function\r
1029**\r
1030*/\r
1031EFI_STATUS\r
1032EFIAPI\r
1033SnpStop (\r
1034 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
1035 )\r
1036{\r
1037 LAN91X_DRIVER *LanDriver;\r
1038 EFI_TPL SavedTpl;\r
1039 EFI_STATUS Status;\r
1040\r
1041 // Check Snp Instance\r
1042 if (Snp == NULL) {\r
1043 return EFI_INVALID_PARAMETER;\r
1044 }\r
1045\r
1046 // Serialize access to data and registers\r
1047 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1048\r
1049 // Check state of the driver\r
1050 switch (Snp->Mode->State) {\r
1051 case EfiSimpleNetworkStarted:\r
1052 case EfiSimpleNetworkInitialized:\r
1053 break;\r
1054 case EfiSimpleNetworkStopped:\r
1055 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1056 ReturnUnlock (EFI_NOT_STARTED);\r
1057 default:\r
1058 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1059 (UINTN)Snp->Mode->State));\r
1060 ReturnUnlock (EFI_DEVICE_ERROR);\r
1061 }\r
1062\r
1063 // Find the LanDriver structure\r
1064 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1065\r
1066 // Stop the Tx and Rx\r
1067 ChipDisable (LanDriver);\r
1068\r
1069 // Change the state\r
1070 Snp->Mode->State = EfiSimpleNetworkStopped;\r
1071 Status = EFI_SUCCESS;\r
1072\r
1073 // Restore TPL and return\r
1074exit_unlock:\r
1075 gBS->RestoreTPL (SavedTpl);\r
1076 return Status;\r
1077}\r
1078\r
1079/*\r
1080** UEFI Initialize() function\r
1081**\r
1082*/\r
1083EFI_STATUS\r
1084EFIAPI\r
1085SnpInitialize (\r
1086 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1087 IN UINTN RxBufferSize OPTIONAL,\r
1088 IN UINTN TxBufferSize OPTIONAL\r
1089 )\r
1090{\r
1091 LAN91X_DRIVER *LanDriver;\r
1092 EFI_TPL SavedTpl;\r
1093 EFI_STATUS Status;\r
1094\r
1095 // Check Snp Instance\r
1096 if (Snp == NULL) {\r
1097 return EFI_INVALID_PARAMETER;\r
1098 }\r
1099\r
1100 // Serialize access to data and registers\r
1101 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1102\r
1103 // Check that driver was started but not initialised\r
1104 switch (Snp->Mode->State) {\r
1105 case EfiSimpleNetworkStarted:\r
1106 break;\r
1107 case EfiSimpleNetworkInitialized:\r
1108 DEBUG ((DEBUG_WARN, "LAN91x: Driver already initialized\n"));\r
1109 ReturnUnlock (EFI_SUCCESS);\r
1110 case EfiSimpleNetworkStopped:\r
1111 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1112 ReturnUnlock (EFI_NOT_STARTED);\r
1113 default:\r
1114 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1115 (UINTN)Snp->Mode->State));\r
1116 ReturnUnlock (EFI_DEVICE_ERROR);\r
1117 }\r
1118\r
1119 // Find the LanDriver structure\r
1120 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1121\r
1122 // Initiate a software reset\r
1123 Status = SoftReset (LanDriver);\r
1124 if (EFI_ERROR(Status)) {\r
1125 DEBUG ((DEBUG_WARN, "LAN91x: Soft reset failed\n"));\r
1126 ReturnUnlock (EFI_DEVICE_ERROR);\r
1127 }\r
1128\r
1129 // Initiate a PHY reset\r
1130 if (PhySoftReset (LanDriver) < 0) {\r
1131 Snp->Mode->State = EfiSimpleNetworkStopped;\r
1132 DEBUG ((DEBUG_WARN, "LAN91x: PHY soft reset timeout\n"));\r
1133 ReturnUnlock (EFI_NOT_STARTED);\r
1134 }\r
1135\r
1136 // Do auto-negotiation\r
1137 Status = PhyAutoNegotiate (LanDriver);\r
1138 if (EFI_ERROR(Status)) {\r
1139 DEBUG ((DEBUG_WARN, "LAN91x: PHY auto-negotiation failed\n"));\r
1140 }\r
1141\r
1142 // Enable the receiver and transmitter\r
1143 ChipEnable (LanDriver);\r
1144\r
1145 // Now acknowledge all interrupts\r
1146 WriteIoReg8 (LanDriver, LAN91X_IST, 0xFF);\r
1147\r
1148 // Declare the driver as initialized\r
1149 Snp->Mode->State = EfiSimpleNetworkInitialized;\r
1150 Status = EFI_SUCCESS;\r
1151\r
1152 // Restore TPL and return\r
1153exit_unlock:\r
1154 gBS->RestoreTPL (SavedTpl);\r
1155 return Status;\r
1156}\r
1157\r
1158/*\r
1159** UEFI Reset () function\r
1160**\r
1161*/\r
1162EFI_STATUS\r
1163EFIAPI\r
1164SnpReset (\r
1165 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1166 IN BOOLEAN Verification\r
1167 )\r
1168{\r
1169 LAN91X_DRIVER *LanDriver;\r
1170 EFI_TPL SavedTpl;\r
1171 EFI_STATUS Status;\r
1172\r
1173 // Check Snp Instance\r
1174 if (Snp == NULL) {\r
1175 return EFI_INVALID_PARAMETER;\r
1176 }\r
1177\r
1178 // Serialize access to data and registers\r
1179 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1180\r
1181 // Check that driver was started and initialised\r
1182 switch (Snp->Mode->State) {\r
1183 case EfiSimpleNetworkInitialized:\r
1184 break;\r
1185 case EfiSimpleNetworkStarted:\r
1186 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1187 ReturnUnlock (EFI_DEVICE_ERROR);\r
1188 case EfiSimpleNetworkStopped:\r
1189 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1190 ReturnUnlock (EFI_NOT_STARTED);\r
1191 default:\r
1192 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1193 (UINTN)Snp->Mode->State));\r
1194 ReturnUnlock (EFI_DEVICE_ERROR);\r
1195 }\r
1196\r
1197 // Find the LanDriver structure\r
1198 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1199\r
1200 // Initiate a software reset\r
1201 if (EFI_ERROR (SoftReset (LanDriver))) {\r
1202 DEBUG ((DEBUG_WARN, "LAN91x: Soft reset failed\n"));\r
1203 ReturnUnlock (EFI_DEVICE_ERROR);\r
1204 }\r
1205\r
1206 // Initiate a PHY reset\r
1207 if (EFI_ERROR (PhySoftReset (LanDriver))) {\r
1208 DEBUG ((DEBUG_WARN, "LAN91x: PHY soft reset failed\n"));\r
1209 ReturnUnlock (EFI_DEVICE_ERROR);\r
1210 }\r
1211\r
1212 // Enable the receiver and transmitter\r
1213 Status = ChipEnable (LanDriver);\r
1214\r
1215 // Restore TPL and return\r
1216exit_unlock:\r
1217 gBS->RestoreTPL (SavedTpl);\r
1218 return Status;\r
1219}\r
1220\r
1221/*\r
1222** UEFI Shutdown () function\r
1223**\r
1224*/\r
1225EFI_STATUS\r
1226EFIAPI\r
1227SnpShutdown (\r
1228 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
1229 )\r
1230{\r
1231 LAN91X_DRIVER *LanDriver;\r
1232 EFI_TPL SavedTpl;\r
1233 EFI_STATUS Status;\r
1234\r
1235 // Check Snp Instance\r
1236 if (Snp == NULL) {\r
1237 return EFI_INVALID_PARAMETER;\r
1238 }\r
1239\r
1240 // Serialize access to data and registers\r
1241 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1242\r
1243 // First check that driver has already been initialized\r
1244 switch (Snp->Mode->State) {\r
1245 case EfiSimpleNetworkInitialized:\r
1246 break;\r
1247 case EfiSimpleNetworkStarted:\r
1248 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1249 ReturnUnlock (EFI_DEVICE_ERROR);\r
1250 case EfiSimpleNetworkStopped:\r
1251 DEBUG ((DEBUG_WARN, "LAN91x: Driver in stopped state\n"));\r
1252 ReturnUnlock (EFI_NOT_STARTED);\r
1253 default:\r
1254 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1255 (UINTN)Snp->Mode->State));\r
1256 ReturnUnlock (EFI_DEVICE_ERROR);\r
1257 }\r
1258\r
1259 // Find the LanDriver structure\r
1260 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1261\r
1262 // Disable the interface\r
1263 Status = ChipDisable (LanDriver);\r
1264\r
1265 // Restore TPL and return\r
1266exit_unlock:\r
1267 gBS->RestoreTPL (SavedTpl);\r
1268 return Status;\r
1269}\r
1270\r
1271\r
1272/*\r
1273** UEFI ReceiveFilters() function\r
1274**\r
1275*/\r
1276EFI_STATUS\r
1277EFIAPI\r
1278SnpReceiveFilters (\r
1279 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1280 IN UINT32 Enable,\r
1281 IN UINT32 Disable,\r
1282 IN BOOLEAN Reset,\r
1283 IN UINTN NumMfilter OPTIONAL,\r
1284 IN EFI_MAC_ADDRESS *Mfilter OPTIONAL\r
1285 )\r
1286{\r
1287#define MCAST_HASH_BYTES 8\r
1288\r
1289 LAN91X_DRIVER *LanDriver;\r
1290 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1291 EFI_TPL SavedTpl;\r
1292 EFI_STATUS Status;\r
1293 UINTN i;\r
1294 UINT32 Crc;\r
1295 UINT16 RcvCtrl;\r
1296 UINT8 McastHash[MCAST_HASH_BYTES];\r
1297\r
1298 // Check Snp Instance\r
1299 if (Snp == NULL) {\r
1300 return EFI_INVALID_PARAMETER;\r
1301 }\r
1302\r
1303 // Serialize access to data and registers\r
1304 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1305\r
1306 // First check that driver has already been initialized\r
1307 switch (Snp->Mode->State) {\r
1308 case EfiSimpleNetworkInitialized:\r
1309 break;\r
1310 case EfiSimpleNetworkStarted:\r
1311 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1312 ReturnUnlock (EFI_DEVICE_ERROR);\r
1313 case EfiSimpleNetworkStopped:\r
1314 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1315 ReturnUnlock (EFI_NOT_STARTED);\r
1316 default:\r
1317 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1318 (UINTN)Snp->Mode->State));\r
1319 ReturnUnlock (EFI_DEVICE_ERROR);\r
1320 }\r
1321\r
1322 // Find the LanDriver structure\r
1323 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1324 SnpMode = Snp->Mode;\r
1325\r
1326#ifdef LAN91X_PRINT_RECEIVE_FILTERS\r
1327 DEBUG ((DEBUG_ERROR, "LAN91x:SnpReceiveFilters()\n"));\r
1328 DEBUG ((DEBUG_ERROR, " Enable = %08x\n", Enable));\r
1329 DEBUG ((DEBUG_ERROR, " Disable = %08x\n", Disable));\r
1330 DEBUG ((DEBUG_ERROR, " Reset = %d\n", Reset));\r
1331 DEBUG ((DEBUG_ERROR, " NumMfilter = %d\n", NumMfilter));\r
1332 for (i = 0; i < NumMfilter; ++i) {\r
1333 DEBUG ((DEBUG_ERROR,\r
1334 " [%2d] = %02x-%02x-%02x-%02x-%02x-%02x\n",\r
1335 i,\r
1336 Mfilter[i].Addr[0],\r
1337 Mfilter[i].Addr[1],\r
1338 Mfilter[i].Addr[2],\r
1339 Mfilter[i].Addr[3],\r
1340 Mfilter[i].Addr[4],\r
1341 Mfilter[i].Addr[5]));\r
1342 }\r
1343#endif\r
1344\r
1345 // Update the Multicast Hash registers\r
1346 if (Reset) {\r
1347 // Clear the hash table\r
1348 SetMem (McastHash, MCAST_HASH_BYTES, 0);\r
1349 SnpMode->MCastFilterCount = 0;\r
1350 } else {\r
1351 // Read the current hash table\r
1352 for (i = 0; i < MCAST_HASH_BYTES; ++i) {\r
1353 McastHash[i] = ReadIoReg8 (LanDriver, LAN91X_MT0 + i);\r
1354 }\r
1355 // Set the new additions\r
1356 for (i = 0; i < NumMfilter; ++i) {\r
1357 Crc = MulticastHash (&Mfilter[i], NET_ETHER_ADDR_LEN);\r
1358 McastHash[(Crc >> 29) & 0x3] |= 1 << ((Crc >> 26) & 0x3);\r
1359 }\r
1360 SnpMode->MCastFilterCount = NumMfilter;\r
1361 }\r
1362 // If the hash registers need updating, write them\r
1363 if (Reset || NumMfilter > 0) {\r
1364 for (i = 0; i < MCAST_HASH_BYTES; ++i) {\r
1365 WriteIoReg8 (LanDriver, LAN91X_MT0 + i, McastHash[i]);\r
1366 }\r
1367 }\r
1368\r
1369 RcvCtrl = ReadIoReg16 (LanDriver, LAN91X_RCR);\r
1370 if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
1371 RcvCtrl |= RCR_PRMS;\r
1372 SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
1373 }\r
1374 if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
1375 RcvCtrl &= ~RCR_PRMS;\r
1376 SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
1377 }\r
1378\r
1379 if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
1380 RcvCtrl |= RCR_ALMUL;\r
1381 SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
1382 }\r
1383 if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
1384 RcvCtrl &= ~RCR_ALMUL;\r
1385 SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
1386 }\r
1387 WriteIoReg16 (LanDriver, LAN91X_RCR, RcvCtrl);\r
1388\r
1389 Status = SetCurrentMacAddress (LanDriver, &SnpMode->CurrentAddress);\r
1390\r
1391 // Restore TPL and return\r
1392exit_unlock:\r
1393 gBS->RestoreTPL (SavedTpl);\r
1394 return Status;\r
1395}\r
1396\r
1397/*\r
1398** UEFI StationAddress() function\r
1399**\r
1400*/\r
1401EFI_STATUS\r
1402EFIAPI\r
1403SnpStationAddress (\r
1404 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1405 IN BOOLEAN Reset,\r
1406 IN EFI_MAC_ADDRESS *NewMac\r
1407)\r
1408{\r
1409 LAN91X_DRIVER *LanDriver;\r
1410 EFI_TPL SavedTpl;\r
1411 EFI_STATUS Status;\r
1412\r
1413 // Check Snp instance\r
1414 if (Snp == NULL) {\r
1415 return EFI_INVALID_PARAMETER;\r
1416 }\r
1417\r
1418 // Serialize access to data and registers\r
1419 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1420\r
1421 // Check that driver was started and initialised\r
1422 switch (Snp->Mode->State) {\r
1423 case EfiSimpleNetworkInitialized:\r
1424 break;\r
1425 case EfiSimpleNetworkStarted:\r
1426 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1427 ReturnUnlock (EFI_DEVICE_ERROR);\r
1428 case EfiSimpleNetworkStopped:\r
1429 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1430 ReturnUnlock (EFI_NOT_STARTED);\r
1431 default:\r
1432 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1433 (UINTN)Snp->Mode->State));\r
1434 ReturnUnlock (EFI_DEVICE_ERROR);\r
1435 }\r
1436\r
1437 // Find the LanDriver structure\r
1438 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1439\r
1440 if (Reset) {\r
1441 Snp->Mode->CurrentAddress = Snp->Mode->PermanentAddress;\r
1442 } else {\r
1443 if (NewMac == NULL) {\r
1444 ReturnUnlock (EFI_INVALID_PARAMETER);\r
1445 }\r
1446 Snp->Mode->CurrentAddress = *NewMac;\r
1447 }\r
1448\r
1449 Status = SetCurrentMacAddress (LanDriver, &Snp->Mode->CurrentAddress);\r
1450\r
1451 // Restore TPL and return\r
1452exit_unlock:\r
1453 gBS->RestoreTPL (SavedTpl);\r
1454 return Status;\r
1455}\r
1456\r
1457/*\r
1458** UEFI Statistics() function\r
1459**\r
1460*/\r
1461EFI_STATUS\r
1462EFIAPI\r
1463SnpStatistics (\r
1464 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1465 IN BOOLEAN Reset,\r
1466 IN OUT UINTN *StatSize,\r
1467 OUT EFI_NETWORK_STATISTICS *Statistics\r
1468 )\r
1469{\r
1470 LAN91X_DRIVER *LanDriver;\r
1471 EFI_TPL SavedTpl;\r
1472 EFI_STATUS Status;\r
1473\r
1474 // Check Snp instance\r
1475 if (Snp == NULL) {\r
1476 return EFI_INVALID_PARAMETER;\r
1477 }\r
1478\r
1479 // Check pointless condition\r
1480 if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) {\r
1481 return EFI_SUCCESS;\r
1482 }\r
1483\r
1484 // Check the parameters\r
1485 if ((StatSize == NULL) && (Statistics != NULL)) {\r
1486 return EFI_INVALID_PARAMETER;\r
1487 }\r
1488\r
1489 // Serialize access to data and registers\r
1490 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1491\r
1492 // Check that driver was started and initialised\r
1493 switch (Snp->Mode->State) {\r
1494 case EfiSimpleNetworkInitialized:\r
1495 break;\r
1496 case EfiSimpleNetworkStarted:\r
1497 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1498 ReturnUnlock (EFI_DEVICE_ERROR);\r
1499 case EfiSimpleNetworkStopped:\r
1500 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1501 ReturnUnlock (EFI_NOT_STARTED);\r
1502 default:\r
1503 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1504 (UINTN)Snp->Mode->State));\r
1505 ReturnUnlock (EFI_DEVICE_ERROR);\r
1506 }\r
1507\r
1508 // Find the LanDriver structure\r
1509 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1510\r
1511 // Do a reset if required\r
1512 if (Reset) {\r
1513 ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));\r
1514 }\r
1515\r
1516 // Check buffer size\r
1517 if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) {\r
1518 *StatSize = sizeof(EFI_NETWORK_STATISTICS);\r
1519 ReturnUnlock (EFI_BUFFER_TOO_SMALL);\r
1520 goto exit_unlock;\r
1521 }\r
1522\r
1523 // Fill in the statistics\r
1524 CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));\r
1525 Status = EFI_SUCCESS;\r
1526\r
1527 // Restore TPL and return\r
1528exit_unlock:\r
1529 gBS->RestoreTPL (SavedTpl);\r
1530 return Status;\r
1531}\r
1532\r
1533/*\r
1534** UEFI MCastIPtoMAC() function\r
1535**\r
1536*/\r
1537EFI_STATUS\r
1538EFIAPI\r
1539SnpMcastIptoMac (\r
1540 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1541 IN BOOLEAN IsIpv6,\r
1542 IN EFI_IP_ADDRESS *Ip,\r
1543 OUT EFI_MAC_ADDRESS *McastMac\r
1544 )\r
1545{\r
1546 // Check Snp instance\r
1547 if (Snp == NULL) {\r
1548 return EFI_INVALID_PARAMETER;\r
1549 }\r
1550\r
1551 // Check parameters\r
1552 if ((McastMac == NULL) || (Ip == NULL)) {\r
1553 return EFI_INVALID_PARAMETER;\r
1554 }\r
1555\r
1556 // Make sure MAC address is empty\r
1557 ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));\r
1558\r
1559 // If we need ipv4 address\r
1560 if (!IsIpv6) {\r
1561 // Most significant 25 bits of a multicast HW address are set\r
1562 McastMac->Addr[0] = 0x01;\r
1563 McastMac->Addr[1] = 0x00;\r
1564 McastMac->Addr[2] = 0x5E;\r
1565\r
1566 // Lower 23 bits from ipv4 address\r
1567 McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the ms bit (25th bit of MAC must be 0)\r
1568 McastMac->Addr[4] = Ip->v4.Addr[2];\r
1569 McastMac->Addr[5] = Ip->v4.Addr[3];\r
1570 } else {\r
1571 // Most significant 16 bits of multicast v6 HW address are set\r
1572 McastMac->Addr[0] = 0x33;\r
1573 McastMac->Addr[1] = 0x33;\r
1574\r
1575 // lower four octets are taken from ipv6 address\r
1576 McastMac->Addr[2] = Ip->v6.Addr[8];\r
1577 McastMac->Addr[3] = Ip->v6.Addr[9];\r
1578 McastMac->Addr[4] = Ip->v6.Addr[10];\r
1579 McastMac->Addr[5] = Ip->v6.Addr[11];\r
1580 }\r
1581\r
1582 return EFI_SUCCESS;\r
1583}\r
1584\r
1585/*\r
1586** UEFI NvData() function\r
1587**\r
1588*/\r
1589EFI_STATUS\r
1590EFIAPI\r
1591SnpNvData (\r
1592 IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,\r
1593 IN BOOLEAN read_write,\r
1594 IN UINTN offset,\r
1595 IN UINTN buff_size,\r
1596 IN OUT VOID *data\r
1597 )\r
1598{\r
1599 DEBUG ((DEBUG_ERROR, "LAN91x: Non-volatile storage not supported\n"));\r
1600\r
1601 return EFI_UNSUPPORTED;\r
1602}\r
1603\r
1604\r
1605/*\r
1606** UEFI GetStatus () function\r
1607**\r
1608*/\r
1609EFI_STATUS\r
1610EFIAPI\r
1611SnpGetStatus (\r
1612 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1613 OUT UINT32 *IrqStat OPTIONAL,\r
1614 OUT VOID **TxBuff OPTIONAL\r
1615 )\r
1616{\r
1617 LAN91X_DRIVER *LanDriver;\r
1618 EFI_TPL SavedTpl;\r
1619 EFI_STATUS Status;\r
1620 BOOLEAN MediaPresent;\r
1621 UINT8 IstReg;\r
1622 MSK_LINKED_SYSTEM_BUF *LinkedTXRecycleBuff;\r
1623\r
1624 // Check preliminaries\r
1625 if (Snp == NULL) {\r
1626 return EFI_INVALID_PARAMETER;\r
1627 }\r
1628\r
1629 // Serialize access to data and registers\r
1630 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1631\r
1632 // Check that driver was started and initialised\r
1633 switch (Snp->Mode->State) {\r
1634 case EfiSimpleNetworkInitialized:\r
1635 break;\r
1636 case EfiSimpleNetworkStarted:\r
1637 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1638 ReturnUnlock (EFI_DEVICE_ERROR);\r
1639 case EfiSimpleNetworkStopped:\r
1640 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1641 ReturnUnlock (EFI_NOT_STARTED);\r
1642 default:\r
1643 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1644 (UINTN)Snp->Mode->State));\r
1645 ReturnUnlock (EFI_DEVICE_ERROR);\r
1646 }\r
1647\r
1648 // Find the LanDriver structure\r
1649 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1650\r
1651 // Arbitrarily set the interrupt status to 0\r
1652 if (IrqStat != NULL) {\r
1653 *IrqStat = 0;\r
1654 IstReg = ReadIoReg8 (LanDriver, LAN91X_IST);\r
1655 if ((IstReg & IST_RCV) != 0) {\r
1656 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
1657 }\r
1658 if ((IstReg & IST_TX) != 0) {\r
1659 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
1660 }\r
1661 }\r
1662\r
1663 // Pass back the completed buffer address\r
1664 // The transmit buffer status is not read when TxBuf is NULL\r
1665 if (TxBuff != NULL) {\r
1666 *((UINT8 **) TxBuff) = (UINT8 *) 0;\r
1667 if( !IsListEmpty (&LanDriver->TransmitQueueHead))\r
1668 {\r
1669 LinkedTXRecycleBuff = CR (GetFirstNode (&LanDriver->TransmitQueueHead), MSK_LINKED_SYSTEM_BUF, Link, TX_MBUF_SIGNATURE);\r
1670 if(LinkedTXRecycleBuff != NULL) {\r
1671 *TxBuff = LinkedTXRecycleBuff->SystemBuf.Buf;\r
1672 RemoveEntryList (&LinkedTXRecycleBuff->Link);\r
1673 FreePool (LinkedTXRecycleBuff);\r
1674 }\r
1675 }\r
1676 }\r
1677\r
1678 // Update the media status\r
1679 MediaPresent = CheckLinkStatus (LanDriver);\r
1680 if (MediaPresent != Snp->Mode->MediaPresent) {\r
1681 DEBUG ((DEBUG_WARN, "LAN91x: Link %s\n", MediaPresent ? L"up" : L"down"));\r
1682 }\r
1683 Snp->Mode->MediaPresent = MediaPresent;\r
1684 Status = EFI_SUCCESS;\r
1685\r
1686 // Restore TPL and return\r
1687exit_unlock:\r
1688 gBS->RestoreTPL (SavedTpl);\r
1689 return Status;\r
1690}\r
1691\r
1692\r
1693/*\r
1694** UEFI Transmit() function\r
1695**\r
1696*/\r
1697EFI_STATUS\r
1698EFIAPI\r
1699SnpTransmit (\r
1700 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1701 IN UINTN HdrSize,\r
1702 IN UINTN BufSize,\r
1703 IN VOID *BufAddr,\r
1704 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1705 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1706 IN UINT16 *Protocol OPTIONAL\r
1707 )\r
1708{\r
1709 LAN91X_DRIVER *LanDriver;\r
1710 EFI_TPL SavedTpl;\r
1711 EFI_STATUS Status;\r
1712 UINT8 *Ptr;\r
1713 UINTN Len;\r
1714 UINTN MmuPages;\r
1715 UINTN Retries;\r
1716 UINT16 Proto;\r
1717 UINT8 PktNum;\r
1718 MSK_LINKED_SYSTEM_BUF *LinkedTXRecycleBuff;\r
1719\r
1720\r
1721 // Check preliminaries\r
1722 if ((Snp == NULL) || (BufAddr == NULL)) {\r
1723 DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): NULL Snp (%p) or BufAddr (%p)\n",\r
1724 Snp, BufAddr));\r
1725 return EFI_INVALID_PARAMETER;\r
1726 }\r
1727\r
1728 // Serialize access to data and registers\r
1729 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1730\r
1731 // Check that driver was started and initialised\r
1732 switch (Snp->Mode->State) {\r
1733 case EfiSimpleNetworkInitialized:\r
1734 break;\r
1735 case EfiSimpleNetworkStarted:\r
1736 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1737 ReturnUnlock (EFI_DEVICE_ERROR);\r
1738 case EfiSimpleNetworkStopped:\r
1739 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1740 ReturnUnlock (EFI_NOT_STARTED);\r
1741 default:\r
1742 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1743 (UINTN)Snp->Mode->State));\r
1744 ReturnUnlock (EFI_DEVICE_ERROR);\r
1745 }\r
1746\r
1747 // Find the LanDriver structure\r
1748 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1749\r
1750 // Ensure header is correct size if non-zero\r
1751 if (HdrSize != 0) {\r
1752 if (HdrSize != Snp->Mode->MediaHeaderSize) {\r
1753 DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): Invalid HdrSize %d\n", HdrSize));\r
1754 ReturnUnlock (EFI_INVALID_PARAMETER);\r
1755 }\r
1756\r
1757 if ((DstAddr == NULL) || (Protocol == NULL)) {\r
1758 DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): NULL DstAddr %p or Protocol %p\n",\r
1759 DstAddr, Protocol));\r
1760 ReturnUnlock (EFI_INVALID_PARAMETER);\r
1761 }\r
1762 }\r
1763\r
1764 // Before transmitting check the link status\r
1765 if (!Snp->Mode->MediaPresent) {\r
1766 DEBUG ((DEBUG_WARN, "LAN91x: SnpTransmit(): Link not ready\n"));\r
1767 ReturnUnlock (EFI_NOT_READY);\r
1768 }\r
1769\r
1770 // Calculate the request size in 256-byte "pages" minus 1\r
1771 // The 91C111 ignores this, but some older devices need it.\r
1772 MmuPages = ((BufSize & ~1) + LAN91X_PKT_OVERHEAD - 1) >> 8;\r
1773 if (MmuPages > 7) {\r
1774 DEBUG ((DEBUG_WARN, "LAN91x: Tx buffer too large (%d bytes)\n", BufSize));\r
1775 LanDriver->Stats.TxOversizeFrames += 1;\r
1776 LanDriver->Stats.TxDroppedFrames += 1;\r
1777 ReturnUnlock (EFI_BAD_BUFFER_SIZE);\r
1778 }\r
1779\r
1780 // Request allocation of a transmit buffer\r
1781 Status = MmuOperation (LanDriver, MMUCR_OP_TX_ALLOC | MmuPages);\r
1782 if (EFI_ERROR (Status)) {\r
1783 DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer request failure: %d\n", Status));\r
1784 ReturnUnlock (EFI_DEVICE_ERROR);\r
1785 }\r
1786\r
1787 // Wait for allocation request completion\r
1788 Retries = LAN91X_MEMORY_ALLOC_POLLS;\r
1789 while ((ReadIoReg8 (LanDriver, LAN91X_IST) & IST_ALLOC) == 0) {\r
1790 if (--Retries == 0) {\r
1791 DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer allocation timeout\n"));\r
1792 ReturnUnlock (EFI_TIMEOUT);\r
1793 }\r
1794 }\r
1795\r
1796 // Check for successful allocation\r
1797 PktNum = ReadIoReg8 (LanDriver, LAN91X_ARR);\r
1798 if ((PktNum & ARR_FAILED) != 0) {\r
1799 DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer allocation failure: %02x\n", PktNum));\r
1800 ReturnUnlock (EFI_NOT_READY);\r
1801 }\r
1802 PktNum &= ARR_PACKET;\r
1803\r
1804 // Check for the nature of the frame\r
1805 // If no destination address, it's ARP broadcast\r
1806 if(DstAddr != NULL)\r
1807 {\r
1808 if (DstAddr->Addr[0] == 0xFF) {\r
1809 LanDriver->Stats.TxBroadcastFrames += 1;\r
1810 } else if ((DstAddr->Addr[0] & 0x1) == 1) {\r
1811 LanDriver->Stats.TxMulticastFrames += 1;\r
1812 } else {\r
1813 LanDriver->Stats.TxUnicastFrames += 1;\r
1814 }\r
1815 } else {\r
1816 LanDriver->Stats.TxBroadcastFrames += 1;\r
1817 }\r
1818\r
1819 // Set the Packet Number and Pointer registers\r
1820 WriteIoReg8 (LanDriver, LAN91X_PNR, PktNum);\r
1821 WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_AUTO_INCR);\r
1822\r
1823 // Set up mutable buffer information variables\r
1824 Ptr = BufAddr;\r
1825 Len = BufSize;\r
1826\r
1827 // Write Status and Byte Count first\r
1828 WriteIoReg16 (LanDriver, LAN91X_DATA0, 0);\r
1829 WriteIoReg16 (LanDriver, LAN91X_DATA0, (Len + LAN91X_PKT_OVERHEAD) & BCW_COUNT);\r
1830\r
1831 // This packet may come with a preconfigured Ethernet header.\r
1832 // If not, we need to construct one from optional parameters.\r
1833 if (HdrSize) {\r
1834\r
1835 // Write the destination address\r
1836 WriteIoData (LanDriver, DstAddr, NET_ETHER_ADDR_LEN);\r
1837\r
1838 // Write the Source Address\r
1839 if (SrcAddr != NULL) {\r
1840 WriteIoData (LanDriver, SrcAddr, NET_ETHER_ADDR_LEN);\r
1841 } else {\r
1842 WriteIoData (LanDriver, &LanDriver->SnpMode.CurrentAddress, NET_ETHER_ADDR_LEN);\r
1843 }\r
1844\r
1845 // Write the Protocol word\r
1846 Proto = HTONS (*Protocol);\r
1847 WriteIoReg16 (LanDriver, LAN91X_DATA0, Proto);\r
1848\r
1849 // Adjust the data start and length\r
1850 Ptr += sizeof(ETHER_HEAD);\r
1851 Len -= sizeof(ETHER_HEAD);\r
1852 }\r
1853\r
1854 // Copy the remainder data buffer, except the odd byte\r
1855 WriteIoData (LanDriver, Ptr, Len & ~1);\r
1856 Ptr += Len & ~1;\r
1857 Len &= 1;\r
1858\r
1859 // Write the Packet Control Word and odd byte\r
1860 WriteIoReg16 (LanDriver, LAN91X_DATA0,\r
1861 (Len != 0) ? (PCW_ODD | PCW_CRC | *Ptr) : PCW_CRC);\r
1862\r
1863 // Release the packet for transmission\r
1864 Status = MmuOperation (LanDriver, MMUCR_OP_TX_PUSH);\r
1865 if (EFI_ERROR (Status)) {\r
1866 DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer release failure: %d\n", Status));\r
1867 ReturnUnlock (EFI_DEVICE_ERROR);\r
1868 }\r
1869\r
1870 // Update the Tx statistics\r
1871 LanDriver->Stats.TxTotalBytes += BufSize;\r
1872 LanDriver->Stats.TxGoodFrames += 1;\r
1873\r
1874 // Update the Tx Buffer cache\r
1875 LinkedTXRecycleBuff = AllocateZeroPool (sizeof (MSK_LINKED_SYSTEM_BUF));\r
1876 if (LinkedTXRecycleBuff == NULL) {\r
1877 return EFI_OUT_OF_RESOURCES;\r
1878 }\r
1879 LinkedTXRecycleBuff->Signature = TX_MBUF_SIGNATURE;\r
1880 //\r
1881 // Add the passed Buffer to the transmit queue. Don't copy.\r
1882 //\r
1883 LinkedTXRecycleBuff->SystemBuf.Buf = BufAddr;\r
1884 LinkedTXRecycleBuff->SystemBuf.Length = BufSize;\r
1885 InsertTailList (&LanDriver->TransmitQueueHead, &LinkedTXRecycleBuff->Link);\r
1886\r
1887 Status = EFI_SUCCESS;\r
1888\r
1889 // Dump the packet header\r
1890#if LAN91X_PRINT_PACKET_HEADERS\r
1891 Ptr = BufAddr;\r
1892 DEBUG ((DEBUG_ERROR, "LAN91X:SnpTransmit()\n"));\r
1893 DEBUG ((DEBUG_ERROR, " HdrSize: %d, SrcAddr: %p, Length: %d, Last byte: %02x\n",\r
1894 HdrSize, SrcAddr, BufSize, Ptr[BufSize - 1]));\r
1895 PrintIpDgram (\r
1896 (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[0] : DstAddr,\r
1897 (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[6] : (SrcAddr != NULL) ? SrcAddr : &LanDriver->SnpMode.CurrentAddress,\r
1898 (HdrSize == 0) ? (UINT16 *)&Ptr[12] : &Proto,\r
1899 &Ptr[14]\r
1900 );\r
1901#endif\r
1902\r
1903 // Restore TPL and return\r
1904exit_unlock:\r
1905 gBS->RestoreTPL (SavedTpl);\r
1906 return Status;\r
1907}\r
1908\r
1909\r
1910/*\r
1911** UEFI Receive() function\r
1912**\r
1913*/\r
1914EFI_STATUS\r
1915EFIAPI\r
1916SnpReceive (\r
1917 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1918 OUT UINTN *HdrSize OPTIONAL,\r
1919 IN OUT UINTN *BuffSize,\r
1920 OUT VOID *Data,\r
1921 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1922 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1923 OUT UINT16 *Protocol OPTIONAL\r
1924 )\r
1925{\r
1926 EFI_TPL SavedTpl;\r
1927 EFI_STATUS Status;\r
1928 LAN91X_DRIVER *LanDriver;\r
1929 UINT8 *DataPtr;\r
1930 UINT16 PktStatus;\r
1931 UINT16 PktLength;\r
1932 UINT16 PktControl;\r
1933 UINT8 IstReg;\r
1934\r
1935 // Check preliminaries\r
1936 if ((Snp == NULL) || (Data == NULL)) {\r
1937 return EFI_INVALID_PARAMETER;\r
1938 }\r
1939\r
1940 // Serialize access to data and registers\r
1941 SavedTpl = gBS->RaiseTPL (LAN91X_TPL);\r
1942\r
1943 // Check that driver was started and initialised\r
1944 switch (Snp->Mode->State) {\r
1945 case EfiSimpleNetworkInitialized:\r
1946 break;\r
1947 case EfiSimpleNetworkStarted:\r
1948 DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));\r
1949 ReturnUnlock (EFI_DEVICE_ERROR);\r
1950 case EfiSimpleNetworkStopped:\r
1951 DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));\r
1952 ReturnUnlock (EFI_NOT_STARTED);\r
1953 default:\r
1954 DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",\r
1955 (UINTN)Snp->Mode->State));\r
1956 ReturnUnlock (EFI_DEVICE_ERROR);\r
1957 }\r
1958\r
1959 // Find the LanDriver structure\r
1960 LanDriver = INSTANCE_FROM_SNP_THIS(Snp);\r
1961\r
1962 // Check for Rx Overrun\r
1963 IstReg = ReadIoReg8 (LanDriver, LAN91X_IST);\r
1964 if ((IstReg & IST_RX_OVRN) != 0) {\r
1965 LanDriver->Stats.RxTotalFrames += 1;\r
1966 LanDriver->Stats.RxDroppedFrames += 1;\r
1967 WriteIoReg8 (LanDriver, LAN91X_IST, IST_RX_OVRN);\r
1968 DEBUG ((DEBUG_WARN, "LAN91x: Receiver overrun\n"));\r
1969 }\r
1970\r
1971 // Check for Rx data available\r
1972 if ((IstReg & IST_RCV) == 0) {\r
1973 ReturnUnlock (EFI_NOT_READY);\r
1974 }\r
1975\r
1976 // Configure the PTR register for reading\r
1977 WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_RCV | PTR_AUTO_INCR | PTR_READ);\r
1978\r
1979 // Read the Packet Status and Packet Length words\r
1980 PktStatus = ReadIoReg16 (LanDriver, LAN91X_DATA0);\r
1981 PktLength = ReadIoReg16 (LanDriver, LAN91X_DATA0) & BCW_COUNT;\r
1982\r
1983 // Check for valid received packet\r
1984 if ((PktStatus == 0) && (PktLength == 0)) {\r
1985 DEBUG ((DEBUG_WARN, "LAN91x: Received zero-length packet. IST=%04x\n", IstReg));\r
1986 ReturnUnlock (EFI_NOT_READY);\r
1987 }\r
1988 LanDriver->Stats.RxTotalFrames += 1;\r
1989\r
1990 // Check if we got a CRC error\r
1991 if ((PktStatus & RX_BAD_CRC) != 0) {\r
1992 DEBUG ((DEBUG_WARN, "LAN91x: Received frame CRC error\n"));\r
1993 LanDriver->Stats.RxCrcErrorFrames += 1;\r
1994 LanDriver->Stats.RxDroppedFrames += 1;\r
1995 Status = EFI_DEVICE_ERROR;\r
1996 goto exit_release;\r
1997 }\r
1998\r
1999 // Check if we got a too-short frame\r
2000 if ((PktStatus & RX_TOO_SHORT) != 0) {\r
2001 DEBUG ((DEBUG_WARN, "LAN91x: Received frame too short (%d bytes)\n", PktLength));\r
2002 LanDriver->Stats.RxUndersizeFrames += 1;\r
2003 LanDriver->Stats.RxDroppedFrames += 1;\r
2004 Status = EFI_DEVICE_ERROR;\r
2005 goto exit_release;\r
2006 }\r
2007\r
2008 // Check if we got a too-long frame\r
2009 if ((PktStatus & RX_TOO_LONG) != 0) {\r
2010 DEBUG ((DEBUG_WARN, "LAN91x: Received frame too long (%d bytes)\n", PktLength));\r
2011 LanDriver->Stats.RxOversizeFrames += 1;\r
2012 LanDriver->Stats.RxDroppedFrames += 1;\r
2013 Status = EFI_DEVICE_ERROR;\r
2014 goto exit_release;\r
2015 }\r
2016\r
2017 // Check if we got an alignment error\r
2018 if ((PktStatus & RX_ALGN_ERR) != 0) {\r
2019 DEBUG ((DEBUG_WARN, "LAN91x: Received frame alignment error\n"));\r
2020 // Don't seem to keep track of these specifically\r
2021 LanDriver->Stats.RxDroppedFrames += 1;\r
2022 Status = EFI_DEVICE_ERROR;\r
2023 goto exit_release;\r
2024 }\r
2025\r
2026 // Classify the received fram\r
2027 if ((PktStatus & RX_MULTICAST) != 0) {\r
2028 LanDriver->Stats.RxMulticastFrames += 1;\r
2029 } else if ((PktStatus & RX_BROADCAST) != 0) {\r
2030 LanDriver->Stats.RxBroadcastFrames += 1;\r
2031 } else {\r
2032 LanDriver->Stats.RxUnicastFrames += 1;\r
2033 }\r
2034\r
2035 // Calculate the received packet data length\r
2036 PktLength -= LAN91X_PKT_OVERHEAD;\r
2037 if ((PktStatus & RX_ODD_FRAME) != 0) {\r
2038 PktLength += 1;\r
2039 }\r
2040\r
2041 // Check buffer size\r
2042 if (*BuffSize < PktLength) {\r
2043 DEBUG ((DEBUG_WARN, "LAN91x: Receive buffer too small for packet (%d < %d)\n",\r
2044 *BuffSize, PktLength));\r
2045 *BuffSize = PktLength;\r
2046 Status = EFI_BUFFER_TOO_SMALL;\r
2047 goto exit_release;\r
2048 }\r
2049\r
2050 // Transfer the data bytes\r
2051 DataPtr = Data;\r
2052 ReadIoData (LanDriver, DataPtr, PktLength & ~0x0001);\r
2053\r
2054 // Read the PktControl and Odd Byte from the FIFO\r
2055 PktControl = ReadIoReg16 (LanDriver, LAN91X_DATA0);\r
2056 if ((PktControl & PCW_ODD) != 0) {\r
2057 DataPtr[PktLength - 1] = PktControl & PCW_ODD_BYTE;\r
2058 }\r
2059\r
2060 // Update buffer size\r
2061 *BuffSize = PktLength;\r
2062\r
2063 if (HdrSize != NULL) {\r
2064 *HdrSize = LanDriver->SnpMode.MediaHeaderSize;\r
2065 }\r
2066\r
2067 // Extract the destination address\r
2068 if (DstAddr != NULL) {\r
2069 CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN);\r
2070 }\r
2071\r
2072 // Get the source address\r
2073 if (SrcAddr != NULL) {\r
2074 CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN);\r
2075 }\r
2076\r
2077 // Get the protocol\r
2078 if (Protocol != NULL) {\r
2079 *Protocol = NTOHS (*(UINT16*)(&DataPtr[12]));\r
2080 }\r
2081\r
2082 // Update the Rx statistics\r
2083 LanDriver->Stats.RxTotalBytes += PktLength;\r
2084 LanDriver->Stats.RxGoodFrames += 1;\r
2085 Status = EFI_SUCCESS;\r
2086\r
2087#if LAN91X_PRINT_PACKET_HEADERS\r
2088 // Dump the packet header\r
2089 DEBUG ((DEBUG_ERROR, "LAN91X:SnpReceive()\n"));\r
2090 DEBUG ((DEBUG_ERROR, " HdrSize: %p, SrcAddr: %p, DstAddr: %p, Protocol: %p\n",\r
2091 HdrSize, SrcAddr, DstAddr, Protocol));\r
2092 DEBUG ((DEBUG_ERROR, " Length: %d, Last byte: %02x\n", PktLength, DataPtr[PktLength - 1]));\r
2093 PrintIpDgram (&DataPtr[0], &DataPtr[6], &DataPtr[12], &DataPtr[14]);\r
2094#endif\r
2095\r
2096 // Release the FIFO buffer\r
2097exit_release:\r
2098 MmuOperation (LanDriver, MMUCR_OP_RX_POP_REL);\r
2099\r
2100 // Restore TPL and return\r
2101exit_unlock:\r
2102 gBS->RestoreTPL (SavedTpl);\r
2103 return Status;\r
2104}\r
2105\r
2106\r
2107/*------------------ Driver Execution Environment main entry point ------------------*/\r
2108\r
2109/*\r
2110** Entry point for the LAN91x driver\r
2111**\r
2112*/\r
2113EFI_STATUS\r
2114Lan91xDxeEntry (\r
2115 IN EFI_HANDLE Handle,\r
2116 IN EFI_SYSTEM_TABLE *SystemTable\r
2117 )\r
2118{\r
2119 EFI_STATUS Status;\r
2120 LAN91X_DRIVER *LanDriver;\r
2121 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
2122 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
2123 LAN91X_DEVICE_PATH *Lan91xPath;\r
2124\r
2125 // The PcdLan91xDxeBaseAddress PCD must be defined\r
2126 ASSERT(PcdGet32 (PcdLan91xDxeBaseAddress) != 0);\r
2127\r
2128 // Allocate Resources\r
2129 LanDriver = AllocateZeroPool (sizeof(LAN91X_DRIVER));\r
2130 Lan91xPath = AllocateCopyPool (sizeof(LAN91X_DEVICE_PATH), &Lan91xPathTemplate);\r
2131\r
2132 // Initialize I/O Space access info\r
2133 LanDriver->IoBase = PcdGet32 (PcdLan91xDxeBaseAddress);\r
2134 LanDriver->PhyAd = LAN91X_NO_PHY;\r
2135 LanDriver->BankSel = 0xff;\r
2136\r
2137 // Initialize pointers\r
2138 Snp = &(LanDriver->Snp);\r
2139 SnpMode = &(LanDriver->SnpMode);\r
2140 Snp->Mode = SnpMode;\r
2141\r
2142 // Set the signature of the LAN Driver structure\r
2143 LanDriver->Signature = LAN91X_SIGNATURE;\r
2144\r
2145 // Probe the device\r
2146 Status = Probe (LanDriver);\r
2147 if (EFI_ERROR(Status)) {\r
2148 DEBUG ((DEBUG_ERROR, "LAN91x:Lan91xDxeEntry(): Probe failed with status %d\n", Status));\r
2149 return Status;\r
2150 }\r
2151\r
2152#ifdef LAN91X_PRINT_REGISTERS\r
2153 PrintIoRegisters (LanDriver);\r
2154 PrintPhyRegisters (LanDriver);\r
2155#endif\r
2156\r
2157 // Initialize transmit queue\r
2158 InitializeListHead (&LanDriver->TransmitQueueHead);\r
2159\r
2160 // Assign fields and func pointers\r
2161 Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
2162 Snp->WaitForPacket = NULL;\r
2163 Snp->Initialize = SnpInitialize;\r
2164 Snp->Start = SnpStart;\r
2165 Snp->Stop = SnpStop;\r
2166 Snp->Reset = SnpReset;\r
2167 Snp->Shutdown = SnpShutdown;\r
2168 Snp->ReceiveFilters = SnpReceiveFilters;\r
2169 Snp->StationAddress = SnpStationAddress;\r
2170 Snp->Statistics = SnpStatistics;\r
2171 Snp->MCastIpToMac = SnpMcastIptoMac;\r
2172 Snp->NvData = SnpNvData;\r
2173 Snp->GetStatus = SnpGetStatus;\r
2174 Snp->Transmit = SnpTransmit;\r
2175 Snp->Receive = SnpReceive;\r
2176\r
2177 // Fill in simple network mode structure\r
2178 SnpMode->State = EfiSimpleNetworkStopped;\r
2179 SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes\r
2180 SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Size of an Ethernet header\r
2181 SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Ethernet Frame (with VLAN tag +4 bytes)\r
2182\r
2183 // Supported receive filters\r
2184 SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |\r
2185 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |\r
2186 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |\r
2187 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |\r
2188 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
2189\r
2190 // Initially-enabled receive filters\r
2191 SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |\r
2192 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |\r
2193 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
2194\r
2195 // LAN91x has 64bit hash table. We can filter an infinite MACs, but\r
2196 // higher-level software must filter out any hash collisions.\r
2197 SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;\r
2198 SnpMode->MCastFilterCount = 0;\r
2199 ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));\r
2200\r
2201 // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)\r
2202 SnpMode->IfType = NET_IFTYPE_ETHERNET;\r
2203\r
2204 // Mac address is changeable\r
2205 SnpMode->MacAddressChangeable = TRUE;\r
2206\r
2207 // We can only transmit one packet at a time\r
2208 SnpMode->MultipleTxSupported = FALSE;\r
2209\r
2210 // MediaPresent checks for cable connection and partner link\r
2211 SnpMode->MediaPresentSupported = TRUE;\r
2212 SnpMode->MediaPresent = FALSE;\r
2213\r
2214 // Set broadcast address\r
2215 SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);\r
2216\r
2217 // Assign fields for device path\r
2218 Lan91xPath->Lan91x.MacAddress = SnpMode->PermanentAddress;\r
2219 Lan91xPath->Lan91x.IfType = SnpMode->IfType;\r
2220\r
2221 // Initialise the protocol\r
2222 Status = gBS->InstallMultipleProtocolInterfaces (\r
2223 &LanDriver->ControllerHandle,\r
2224 &gEfiSimpleNetworkProtocolGuid, Snp,\r
2225 &gEfiDevicePathProtocolGuid, Lan91xPath,\r
2226 NULL\r
2227 );\r
2228\r
2229 // Say what the status of loading the protocol structure is\r
2230 if (EFI_ERROR(Status)) {\r
2231 FreePool (LanDriver);\r
2232 }\r
2233\r
2234 return Status;\r
2235}\r