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