ArmPlatformPkg/Bds: Added boot timeout setting
[mirror_edk2.git] / EmbeddedPkg / Drivers / Lan9118Dxe / Lan9118Dxe.c
CommitLineData
46f2c53b
OM
1/** @file\r
2*\r
3* Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "Lan9118Dxe.h"\r
16\r
17\r
18typedef struct {\r
19 MAC_ADDR_DEVICE_PATH Lan9118;\r
20 EFI_DEVICE_PATH_PROTOCOL End;\r
21} LAN9118_DEVICE_PATH;\r
22\r
23LAN9118_DEVICE_PATH Lan9118PathTemplate = {\r
24 {\r
25 {\r
26 MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,\r
27 { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) }\r
28 },\r
b0fdce95 29 { { 0 } },\r
46f2c53b
OM
30 0\r
31 },\r
32 {\r
33 END_DEVICE_PATH_TYPE,\r
34 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
b0fdce95 35 { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }\r
46f2c53b
OM
36 }\r
37};\r
38\r
39/*\r
40** Entry point for the LAN9118 driver\r
41**\r
42*/\r
43EFI_STATUS\r
44Lan9118DxeEntry (\r
45 IN EFI_HANDLE Handle,\r
46 IN EFI_SYSTEM_TABLE *SystemTable\r
47 )\r
48{\r
49 EFI_STATUS Status;\r
50 LAN9118_DRIVER *LanDriver;\r
51 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
52 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
53 LAN9118_DEVICE_PATH *Lan9118Path;\r
54 EFI_HANDLE ControllerHandle;\r
55\r
56 // The PcdLan9118DxeBaseAddress PCD must be defined\r
57 ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress) != 0);\r
58\r
59 // Allocate Resources\r
60 LanDriver = AllocateZeroPool (sizeof (LAN9118_DRIVER));\r
61 if (LanDriver == NULL) {\r
62 return EFI_OUT_OF_RESOURCES;\r
63 }\r
64 Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool (sizeof (LAN9118_DEVICE_PATH), &Lan9118PathTemplate);\r
65 if (Lan9118Path == NULL) {\r
66 return EFI_OUT_OF_RESOURCES;\r
67 }\r
68\r
69 // Initialize pointers\r
70 Snp = &(LanDriver->Snp);\r
71 SnpMode = &(LanDriver->SnpMode);\r
72 Snp->Mode = SnpMode;\r
73\r
74 // Set the signature of the LAN Driver structure\r
75 LanDriver->Signature = LAN9118_SIGNATURE;\r
76\r
77 // Assign fields and func pointers\r
78 Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
79 Snp->WaitForPacket = NULL;\r
80 Snp->Initialize = SnpInitialize;\r
81 Snp->Start = SnpStart;\r
82 Snp->Stop = SnpStop;\r
83 Snp->Reset = SnpReset;\r
84 Snp->Shutdown = SnpShutdown;\r
85 Snp->ReceiveFilters = SnpReceiveFilters;\r
86 Snp->StationAddress = SnpStationAddress;\r
87 Snp->Statistics = SnpStatistics;\r
88 Snp->MCastIpToMac = SnpMcastIptoMac;\r
89 Snp->NvData = SnpNvData;\r
90 Snp->GetStatus = SnpGetStatus;\r
91 Snp->Transmit = SnpTransmit;\r
92 Snp->Receive = SnpReceive;\r
93\r
94 // Start completing simple network mode structure\r
95 SnpMode->State = EfiSimpleNetworkStopped;\r
96 SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes\r
97 SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Not sure of this\r
98 SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes)\r
99 SnpMode->NvRamSize = 0; // No NVRAM with this device\r
100 SnpMode->NvRamAccessSize = 0; // No NVRAM with this device\r
101\r
102 // Update network mode information\r
103 SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |\r
104 EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |\r
105 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |\r
106 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;/* |\r
107 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;*/\r
108 // Current allowed settings\r
109 SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |\r
110 EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |\r
111 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
112\r
113 // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses\r
114 SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;\r
115 SnpMode->MCastFilterCount = 0;\r
116 ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));\r
117\r
118 // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)\r
119 SnpMode->IfType = NET_IFTYPE_ETHERNET;\r
120\r
121 // Mac address is changeable as it is loaded from erasable memory\r
122 SnpMode->MacAddressChangeable = TRUE;\r
123\r
124 // Can only transmit one packet at a time\r
125 SnpMode->MultipleTxSupported = FALSE;\r
126\r
127 // MediaPresent checks for cable connection and partner link\r
128 SnpMode->MediaPresentSupported = TRUE;\r
129 SnpMode->MediaPresent = FALSE;\r
130\r
131 // Set broadcast address\r
132 SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);\r
133\r
134 // Power up the device so we can find the MAC address\r
135 Status = Lan9118Initialize (Snp);\r
136 if (EFI_ERROR (Status)) {\r
137 DEBUG ((EFI_D_ERROR, "Lan9118: Error initialising hardware\n"));\r
138 return EFI_DEVICE_ERROR;\r
139 }\r
140\r
141 // Assign fields for device path\r
142 CopyMem (&Lan9118Path->Lan9118.MacAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);\r
143 Lan9118Path->Lan9118.IfType = Snp->Mode->IfType;\r
144\r
145 // Initialise the protocol\r
146 ControllerHandle = NULL;\r
147 Status = gBS->InstallMultipleProtocolInterfaces (\r
148 &ControllerHandle,\r
149 &gEfiSimpleNetworkProtocolGuid, Snp,\r
150 &gEfiDevicePathProtocolGuid, Lan9118Path,\r
151 NULL\r
152 );\r
153 // Say what the status of loading the protocol structure is\r
154 if (EFI_ERROR(Status)) {\r
155 FreePool (LanDriver);\r
156 } else {\r
157 LanDriver->ControllerHandle = ControllerHandle;\r
158 }\r
159\r
160 return Status;\r
161}\r
162\r
163/*\r
164 * UEFI Start() function\r
165 *\r
166 * Parameters:\r
167 *\r
168 * @param Snp: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.\r
169 *\r
170 * Description:\r
171 *\r
172 * This function starts a network interface. If the network interface successfully starts, then\r
173 * EFI_SUCCESS will be returned.\r
174 */\r
175EFI_STATUS\r
176EFIAPI\r
177SnpStart (\r
178 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
179 )\r
180{\r
181 // Check Snp instance\r
182 if (Snp == NULL) {\r
183 return EFI_INVALID_PARAMETER;\r
184 }\r
185\r
186 // Check state\r
187 if ((Snp->Mode->State == EfiSimpleNetworkStarted) || (Snp->Mode->State == EfiSimpleNetworkInitialized)) {\r
188 return EFI_ALREADY_STARTED;\r
189 } else if (Snp->Mode->State == EfiSimpleNetworkMaxState) {\r
190 return EFI_DEVICE_ERROR;\r
191 }\r
192\r
193 // Change state\r
194 Snp->Mode->State = EfiSimpleNetworkStarted;\r
195 return EFI_SUCCESS;\r
196}\r
197\r
198/*\r
199 * UEFI Stop() function\r
200 *\r
201 */\r
202EFI_STATUS\r
203EFIAPI\r
204SnpStop (\r
205 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
206 )\r
207{\r
208 // Check Snp Instance\r
209 if (Snp == NULL) {\r
210 return EFI_INVALID_PARAMETER;\r
211 }\r
212\r
213 // Check state of the driver\r
214 if ((Snp->Mode->State == EfiSimpleNetworkStopped) || (Snp->Mode->State == EfiSimpleNetworkMaxState)) {\r
215 return EFI_NOT_STARTED;\r
216 }\r
217\r
218 // Stop the Tx and Rx\r
219 StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp);\r
220 StopRx (0, Snp);\r
221\r
222 // Change the state\r
223 switch (Snp->Mode->State) {\r
224 case EfiSimpleNetworkStarted:\r
225 case EfiSimpleNetworkInitialized:\r
226 Snp->Mode->State = EfiSimpleNetworkStopped;\r
227 break;\r
228 default:\r
229 return EFI_DEVICE_ERROR;\r
230 }\r
231\r
232 // Put the device into a power saving mode ?\r
233 return EFI_SUCCESS;\r
234}\r
235\r
236\r
237// Allocated receive and transmit buffers\r
238STATIC UINT32 gTxBuffer = 0;\r
239\r
240/*\r
241 * UEFI Initialize() function\r
242 *\r
243 */\r
244EFI_STATUS\r
245EFIAPI\r
246SnpInitialize (\r
247 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
248 IN UINTN RxBufferSize OPTIONAL,\r
249 IN UINTN TxBufferSize OPTIONAL\r
250 )\r
251{\r
252 EFI_STATUS Status;\r
253 UINT32 PmConf;\r
254 INT32 AllocResult;\r
255 UINT32 RxStatusSize;\r
256 UINT32 TxStatusSize;\r
257\r
258 // Initialize variables\r
259 // Global variables to hold tx and rx FIFO allocation\r
260 gTxBuffer = 0;\r
261\r
262 // Check Snp Instance\r
263 if (Snp == NULL) {\r
264 return EFI_INVALID_PARAMETER;\r
265 }\r
266\r
267 // First check that driver has not already been initialized\r
268 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {\r
269 DEBUG ((EFI_D_WARN, "LAN9118 Driver already initialized\n"));\r
270 return EFI_SUCCESS;\r
271 } else\r
272 if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
273 DEBUG ((EFI_D_WARN, "LAN9118 Driver not started\n"));\r
274 return EFI_NOT_STARTED;\r
275 }\r
276\r
277 // Initiate a PHY reset\r
278 if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) {\r
279 Snp->Mode->State = EfiSimpleNetworkStopped;\r
280 DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n"));\r
281 return EFI_NOT_STARTED;\r
282 }\r
283\r
284 // Initiate a software reset\r
285 Status = SoftReset (0, Snp);\r
286 if (EFI_ERROR(Status)) {\r
287 DEBUG ((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n"));\r
288 return EFI_DEVICE_ERROR;\r
289 }\r
290\r
291 // Read the PM register\r
292 PmConf = MmioRead32 (LAN9118_PMT_CTRL);\r
293\r
294 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets\r
295 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode\r
296 // MPTCTRL_PME_EN: Allow Power Management Events\r
297 PmConf = 0;\r
298 PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);\r
299\r
300 // Write the current configuration to the register\r
301 MmioWrite32 (LAN9118_PMT_CTRL, PmConf);\r
302 gBS->Stall (LAN9118_STALL);\r
303 gBS->Stall (LAN9118_STALL);\r
304\r
305 // Configure GPIO and HW\r
306 Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);\r
307 if (EFI_ERROR(Status)) {\r
308 return Status;\r
309 }\r
310\r
311 // Assign the transmitter buffer size (default values)\r
312 TxStatusSize = LAN9118_TX_STATUS_SIZE;\r
313 RxStatusSize = LAN9118_RX_STATUS_SIZE;\r
314\r
315 // Check that a buff size was specified\r
316 if (TxBufferSize > 0) {\r
317 if (RxBufferSize == 0) {\r
318 RxBufferSize = LAN9118_RX_DATA_SIZE;\r
319 }\r
320\r
321 AllocResult = ChangeFifoAllocation (\r
322 ALLOC_USE_FIFOS,\r
323 &TxBufferSize,\r
324 &RxBufferSize,\r
325 &TxStatusSize,\r
326 &RxStatusSize,\r
327 Snp\r
328 );\r
329\r
330 if (AllocResult < 0) {\r
331 return EFI_OUT_OF_RESOURCES;\r
332 }\r
333 }\r
334\r
335 // Do auto-negotiation if supported\r
336 Status = AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp);\r
337 if (EFI_ERROR(Status)) {\r
338 DEBUG ((EFI_D_WARN, "Lan9118: Auto Negociation not supported.\n"));\r
339 }\r
340\r
341 // Configure flow control depending on speed capabilities\r
342 Status = ConfigureFlow (0, 0, 0, 0, Snp);\r
343 if (EFI_ERROR(Status)) {\r
344 return Status;\r
345 }\r
346\r
347 // Enable the receiver and transmitter\r
348 Status = StartRx (0, Snp);\r
349 if (EFI_ERROR(Status)) {\r
350 return Status;\r
351 }\r
352\r
353 Status = StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
354 if (EFI_ERROR(Status)) {\r
355 return Status;\r
356 }\r
357\r
358 // Now acknowledge all interrupts\r
359 MmioWrite32 (LAN9118_INT_STS, ~0);\r
360\r
361 // Declare the driver as initialized\r
362 Snp->Mode->State = EfiSimpleNetworkInitialized;\r
363\r
364 return Status;\r
365}\r
366\r
367/*\r
368 * UEFI Reset () function\r
369 *\r
370 */\r
371EFI_STATUS\r
372EFIAPI\r
373SnpReset (\r
374 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
375 IN BOOLEAN Verification\r
376 )\r
377{\r
378 UINT32 PmConf;\r
379 UINT32 HwConf;\r
380 UINT32 ResetFlags;\r
381\r
382 PmConf = 0;\r
383 HwConf = 0;\r
384 ResetFlags = 0;\r
385\r
386 // Check Snp Instance\r
387 if (Snp == NULL) {\r
388 return EFI_INVALID_PARAMETER;\r
389 }\r
390\r
391 // First check that driver has not already been initialized\r
392 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
393 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));\r
394 return EFI_DEVICE_ERROR;\r
395 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
396 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));\r
397 return EFI_NOT_STARTED;\r
398 }\r
399\r
400 // Initiate a PHY reset\r
401 if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) {\r
402 Snp->Mode->State = EfiSimpleNetworkStopped;\r
403 return EFI_NOT_STARTED;\r
404 }\r
405\r
406 // Initiate a software reset\r
407 ResetFlags |= SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT;\r
408\r
409 if (Verification) {\r
410 ResetFlags |= SOFT_RESET_SELF_TEST;\r
411 }\r
412\r
413 if (SoftReset (ResetFlags, Snp) < 0) {\r
414 DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));\r
415 return EFI_DEVICE_ERROR;\r
416 }\r
417\r
418 // Read the PM register\r
419 PmConf = MmioRead32 (LAN9118_PMT_CTRL);\r
420\r
421 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets\r
422 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode\r
423 // MPTCTRL_PME_EN: Allow Power Management Events\r
424 PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);\r
425\r
426 // Write the current configuration to the register\r
427 MmioWrite32 (LAN9118_PMT_CTRL, PmConf);\r
428 gBS->Stall (LAN9118_STALL);\r
429\r
430 // Check that a buffer size was specified in SnpInitialize\r
431 if (gTxBuffer != 0) {\r
432 HwConf = MmioRead32 (LAN9118_HW_CFG); // Read the HW register\r
433 HwConf &= ~HW_CFG_TX_FIFO_SIZE_MASK; // Clear buffer bits first\r
434 HwConf |= HW_CFG_TX_FIFO_SIZE(gTxBuffer); // assign size chosen in SnpInitialize\r
435\r
436 MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf\r
437 gBS->Stall (LAN9118_STALL);\r
438 }\r
439\r
440 // Enable the receiver and transmitter and clear their contents\r
441 StartRx (START_RX_CLEAR, Snp);\r
442 StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp);\r
443\r
444 // Now acknowledge all interrupts\r
445 MmioWrite32 (LAN9118_INT_STS, ~0);\r
446\r
447 return EFI_SUCCESS;\r
448}\r
449\r
450/*\r
451 * UEFI Shutdown () function\r
452 *\r
453 */\r
454EFI_STATUS\r
455EFIAPI\r
456SnpShutdown (\r
457 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp\r
458 )\r
459{\r
460 // Check Snp Instance\r
461 if (Snp == NULL) {\r
462 return EFI_INVALID_PARAMETER;\r
463 }\r
464\r
465 // First check that driver has not already been initialized\r
466 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
467 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));\r
468 return EFI_DEVICE_ERROR;\r
469 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
470 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
471 return EFI_NOT_STARTED;\r
472 }\r
473\r
474 // Initiate a PHY reset\r
475 PhySoftReset (PHY_RESET_PMT, Snp);\r
476\r
477 // Initiate a software reset\r
478 if (SoftReset (0, Snp) < 0) {\r
479 DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));\r
480 return EFI_DEVICE_ERROR;\r
481 }\r
482\r
483 return EFI_SUCCESS;\r
484}\r
485\r
486\r
487/*\r
488 * UEFI ReceiveFilters() function\r
489 *\r
490 */\r
491EFI_STATUS\r
492EFIAPI\r
493SnpReceiveFilters (\r
494 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
495 IN UINT32 Enable,\r
496 IN UINT32 Disable,\r
497 IN BOOLEAN Reset,\r
498 IN UINTN NumMfilter OPTIONAL,\r
499 IN EFI_MAC_ADDRESS *Mfilter OPTIONAL\r
500 )\r
501{\r
502 UINT32 MacCSRValue;\r
503 UINT32 MultHashTableHigh;\r
504 UINT32 MultHashTableLow;\r
505 UINT32 Crc;\r
506 UINT8 BitToSelect;\r
507 UINT32 Count;\r
508\r
509 MacCSRValue = 0;\r
510 MultHashTableHigh = 0;\r
511 MultHashTableLow = 0;\r
512 Crc = 0xFFFFFFFF;\r
513 BitToSelect = 0;\r
514 Count = 0;\r
515\r
516 // Check that driver was started and initialised\r
517 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
518 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
519 return EFI_DEVICE_ERROR;\r
520 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
521 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
522 return EFI_NOT_STARTED;\r
523 }\r
524\r
525 // If reset then clear the filter registers\r
526 if (Reset) {\r
527 Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
528 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, 0x00000000);\r
529 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, 0x00000000);\r
530 }\r
531\r
532 // Set the hash tables\r
533 if ((NumMfilter > 0) && (!Reset)) {\r
534\r
535 // Read the Multicast High Hash Table\r
536 MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH);\r
537\r
538 // Read the Multicast Low Hash Table\r
539 MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL);\r
540\r
541 // Go through each filter address and set appropriate bits on hash table\r
542 for (Count = 0; Count < NumMfilter; Count++) {\r
543\r
544 // Generate a 32-bit CRC for Ethernet\r
545 Crc = GenEtherCrc32 (&Mfilter[Count],6);\r
546 //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired\r
547\r
548 // Get the most significant 6 bits to index hash registers\r
549 BitToSelect = (Crc >> 26) & 0x3F;\r
550\r
551 // Select hashlow register if MSB is not set\r
552 if ((BitToSelect & 0x20) == 0) {\r
553 MultHashTableLow |= (1 << BitToSelect);\r
554 } else {\r
555 MultHashTableHigh |= (1 << (BitToSelect & 0x1F));\r
556 }\r
557 }\r
558\r
559 // Write the desired hash\r
560 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow);\r
561 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh);\r
562 }\r
563\r
564 // Read MAC controller\r
565 MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);\r
566\r
567 // Set the options for the MAC_CSR\r
568 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {\r
569 StartRx (0, Snp);\r
570 DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n"));\r
571 }\r
572\r
573 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {\r
574 StopRx (0, Snp);\r
575 DEBUG ((DEBUG_NET, "Disabling Unicast Frame Reception\n"));\r
576 }\r
577\r
578 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {\r
579 MacCSRValue |= MACCR_HPFILT;\r
580 DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n"));\r
581 }\r
582\r
583 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {\r
584 MacCSRValue &= ~MACCR_HPFILT;\r
585 DEBUG ((DEBUG_NET, "Disabling Multicast Frame Reception\n"));\r
586 }\r
587\r
588 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {\r
589 MacCSRValue &= ~(MACCR_BCAST);\r
590 DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n"));\r
591 }\r
592\r
593 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {\r
594 MacCSRValue |= MACCR_BCAST;\r
595 DEBUG ((DEBUG_NET, "Disabling Broadcast Frame Reception\n"));\r
596 }\r
597\r
598 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {\r
599 MacCSRValue |= MACCR_PRMS;\r
600 DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n"));\r
601 }\r
602\r
603 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {\r
604 MacCSRValue &= ~MACCR_PRMS;\r
605 DEBUG ((DEBUG_NET, "Disabling Promiscuous Mode\n"));\r
606 }\r
607\r
608 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
609 MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS);\r
610 DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n"));\r
611 }\r
612\r
613 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
614 MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS);\r
615 DEBUG ((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n"));\r
616 }\r
617\r
618 // Write the options to the MAC_CSR\r
619 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue);\r
620 gBS->Stall (LAN9118_STALL);\r
621\r
622 return EFI_SUCCESS;\r
623}\r
624\r
625/*\r
626 * UEFI StationAddress() function\r
627 *\r
628 */\r
629EFI_STATUS\r
630EFIAPI\r
631SnpStationAddress (\r
632 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
633 IN BOOLEAN Reset,\r
634 IN EFI_MAC_ADDRESS *NewMac\r
635)\r
636{\r
637 DEBUG ((DEBUG_NET, "SnpStationAddress()\n"));\r
638\r
639 UINT32 Count;\r
640 UINT8 PermAddr[6];\r
641 UINT64 DefaultMacAddress;\r
642\r
643 Count = 0;\r
644\r
645 // Check Snp instance\r
646 if (Snp == NULL) {\r
647 return EFI_INVALID_PARAMETER;\r
648 }\r
649\r
650 // Check that driver was started and initialised\r
651 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
652 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
653 return EFI_DEVICE_ERROR;\r
654 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
655 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
656 return EFI_NOT_STARTED;\r
657 }\r
658\r
659 // Get the Permanent MAC address if need reset\r
660 if (Reset) {\r
661 // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0\r
662 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) {\r
663 for (Count = 1; Count < 7; Count++) {\r
664 PermAddr[Count - 1] = IndirectEEPROMRead32 (Count);\r
665 }\r
666\r
667 // Write address\r
668 Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp);\r
669 } else {\r
670 DEBUG ((EFI_D_ERROR, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n"));\r
671 DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress);\r
672 Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp);\r
673 }\r
674 } else {\r
675 // Otherwise use the specified new MAC address\r
676 if (NewMac == NULL) {\r
677 return EFI_INVALID_PARAMETER;\r
678 }\r
679\r
680 // Write address\r
681 Lan9118SetMacAddress (NewMac, Snp);\r
682 }\r
683\r
684 return EFI_SUCCESS;\r
685}\r
686\r
687/*\r
688 * UEFI Statistics() function\r
689 *\r
690 */\r
691EFI_STATUS\r
692EFIAPI\r
693SnpStatistics (\r
694 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
695 IN BOOLEAN Reset,\r
696 IN OUT UINTN *StatSize,\r
697 OUT EFI_NETWORK_STATISTICS *Statistics\r
698 )\r
699{\r
700 LAN9118_DRIVER *LanDriver;\r
701\r
702 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
703\r
704 DEBUG ((DEBUG_NET, "SnpStatistics()\n"));\r
705\r
706 // Check Snp instance\r
707 if (Snp == NULL) {\r
708 return EFI_INVALID_PARAMETER;\r
709 }\r
710\r
711 // Check that driver was started and initialised\r
712 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
713 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
714 return EFI_DEVICE_ERROR;\r
715 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
716 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
717 return EFI_NOT_STARTED;\r
718 }\r
719\r
720 // Check pointless condition\r
721 if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) {\r
722 return EFI_SUCCESS;\r
723 }\r
724\r
725 // Check the parameters\r
726 if ((StatSize == NULL) && (Statistics != NULL)) {\r
727 return EFI_INVALID_PARAMETER;\r
728 }\r
729\r
730 // Do a reset if required\r
731 if (Reset) {\r
732 ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));\r
733 }\r
734\r
735 // Check buffer size\r
736 if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) {\r
737 *StatSize = sizeof(EFI_NETWORK_STATISTICS);\r
738 return EFI_BUFFER_TOO_SMALL;\r
739 }\r
740\r
741 // Fill in the statistics\r
742 CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));\r
743\r
744 return EFI_SUCCESS;\r
745}\r
746\r
747/*\r
748 * UEFI MCastIPtoMAC() function\r
749 *\r
750 */\r
751EFI_STATUS\r
752EFIAPI\r
753SnpMcastIptoMac (\r
754 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
755 IN BOOLEAN IsIpv6,\r
756 IN EFI_IP_ADDRESS *Ip,\r
757 OUT EFI_MAC_ADDRESS *McastMac\r
758 )\r
759{\r
760 DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n"));\r
761\r
762 // Check Snp instance\r
763 if (Snp == NULL) {\r
764 return EFI_INVALID_PARAMETER;\r
765 }\r
766\r
767 // Check that driver was started and initialised\r
768 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
769 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
770 return EFI_DEVICE_ERROR;\r
771 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
772 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
773 return EFI_NOT_STARTED;\r
774 }\r
775\r
776 // Check parameters\r
777 if ((McastMac == NULL) || (Ip == NULL)) {\r
778 return EFI_INVALID_PARAMETER;\r
779 }\r
780\r
781 // Make sure MAC address is empty\r
782 ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));\r
783\r
784 // If we need ipv4 address\r
785 if (!IsIpv6) {\r
786 // Most significant 25 bits of a multicast HW address are set.\r
787 // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)\r
788 McastMac->Addr[0] = 0x01;\r
789 McastMac->Addr[1] = 0x00;\r
790 McastMac->Addr[2] = 0x5E;\r
791\r
792 // Lower 23 bits from ipv4 address\r
793 McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)\r
794 McastMac->Addr[4] = Ip->v4.Addr[2];\r
795 McastMac->Addr[5] = Ip->v4.Addr[3];\r
796 } else {\r
797 // Most significant 16 bits of multicast v6 HW address are set\r
798 // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)\r
799 McastMac->Addr[0] = 0x33;\r
800 McastMac->Addr[1] = 0x33;\r
801\r
802 // lower four octets are taken from ipv6 address\r
803 McastMac->Addr[2] = Ip->v6.Addr[8];\r
804 McastMac->Addr[3] = Ip->v6.Addr[9];\r
805 McastMac->Addr[4] = Ip->v6.Addr[10];\r
806 McastMac->Addr[5] = Ip->v6.Addr[11];\r
807 }\r
808\r
809 return EFI_SUCCESS;\r
810}\r
811\r
812/*\r
813 * UEFI NvData() function\r
814 *\r
815 */\r
816EFI_STATUS\r
817EFIAPI\r
818SnpNvData (\r
819 IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,\r
820 IN BOOLEAN read_write,\r
821 IN UINTN offset,\r
822 IN UINTN buff_size,\r
823 IN OUT VOID *data\r
824 )\r
825{\r
826 DEBUG ((DEBUG_NET, "SnpNvData()\n"));\r
827\r
828 return EFI_UNSUPPORTED;\r
829}\r
830\r
831\r
832/*\r
833 * UEFI GetStatus () function\r
834 *\r
835 */\r
836EFI_STATUS\r
837EFIAPI\r
838SnpGetStatus (\r
839 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
840 OUT UINT32 *IrqStat OPTIONAL,\r
841 OUT VOID **TxBuff OPTIONAL\r
842 )\r
843{\r
844 UINT32 FifoInt;\r
845 EFI_STATUS Status;\r
846 UINTN NumTxStatusEntries;\r
847 UINT32 TxStatus;\r
848 UINT16 PacketTag;\r
849 UINT32 Interrupts;\r
850 LAN9118_DRIVER *LanDriver;\r
851\r
852 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
853\r
854 // Check preliminaries\r
855 if (Snp == NULL) {\r
856 return EFI_INVALID_PARAMETER;\r
857 }\r
858\r
859 if (Snp->Mode->State != EfiSimpleNetworkInitialized) {\r
860 return EFI_NOT_STARTED;\r
861 }\r
862\r
863 // Check and acknowledge TX Status interrupt (this will happen if the\r
864 // consumer of SNP does not call GetStatus.)\r
865 // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we\r
866 // should check for it and dump the TX Status FIFO.\r
867 FifoInt = MmioRead32 (LAN9118_FIFO_INT);\r
868\r
869 // Clear the TX Status FIFO Overflow\r
870 if ((FifoInt & INSTS_TXSO) == 0) {\r
871 FifoInt |= INSTS_TXSO;\r
872 MmioWrite32 (LAN9118_FIFO_INT, FifoInt);\r
873 }\r
874\r
875 // Read interrupt status if IrqStat is not NULL\r
876 if (IrqStat != NULL) {\r
877\r
878 // Check for receive interrupt\r
879 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO\r
880 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
881 MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);\r
882 } else {\r
883 *IrqStat &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
884 }\r
885\r
886 // Check for transmit interrupt\r
887 if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {\r
888 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
889 MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);\r
890 } else {\r
891 *IrqStat &= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
892 }\r
893\r
894 // Check for software interrupt\r
895 if (MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) {\r
896 *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;\r
897 MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT);\r
898 } else {\r
899 *IrqStat &= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;\r
900 }\r
901 }\r
902\r
903 // Check Status of transmitted packets\r
904 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)\r
905\r
906 NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;\r
907 if (NumTxStatusEntries > 0) {\r
908 TxStatus = MmioRead32 (LAN9118_TX_STATUS);\r
909 PacketTag = TxStatus >> 16;\r
910 TxStatus = TxStatus & 0xFFFF;\r
911 if ((TxStatus & TXSTATUS_ES) && TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA)) {\r
912 DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));\r
913 if (TxStatus & TXSTATUS_NO_CA) {\r
914 DEBUG ((EFI_D_ERROR, "- No carrier\n"));\r
915 }\r
916 if (TxStatus & TXSTATUS_DEF) {\r
917 DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));\r
918 }\r
919 if (TxStatus & TXSTATUS_EDEF) {\r
920 DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));\r
921 }\r
922 if (TxStatus & TXSTATUS_ECOLL) {\r
923 DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));\r
924 }\r
925 if (TxStatus & TXSTATUS_LCOLL) {\r
926 DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));\r
927 }\r
928 if (TxStatus & TXSTATUS_LOST_CA) {\r
929 DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));\r
930 }\r
931 return EFI_DEVICE_ERROR;\r
932 } else {\r
933 LanDriver->Stats.TxTotalFrames += 1;\r
934 *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];\r
935 }\r
936 }\r
937\r
938 // Check for a TX Error interrupt\r
939 Interrupts = MmioRead32 (LAN9118_INT_STS);\r
940 if (Interrupts & INSTS_TXE) {\r
941 DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));\r
942\r
943 // Initiate a software reset\r
944 if (SoftReset (0, Snp) < 0) {\r
945 DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));\r
946 return EFI_DEVICE_ERROR;\r
947 }\r
948\r
949 // Acknowledge the TXE\r
950 MmioWrite32 (LAN9118_INT_STS, INSTS_TXE);\r
951 gBS->Stall (LAN9118_STALL);\r
952\r
953 // Restart the transmitter\r
954 StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
955 }\r
956\r
957 // Update the media status\r
958 Status = CheckLinkStatus (0, Snp);\r
959 if (EFI_ERROR(Status)) {\r
960 Snp->Mode->MediaPresent = FALSE;\r
961 } else {\r
962 Snp->Mode->MediaPresent = TRUE;\r
963 }\r
964\r
965 return EFI_SUCCESS;\r
966}\r
967\r
968\r
969/*\r
970 * UEFI Transmit() function\r
971 *\r
972 */\r
973EFI_STATUS\r
974EFIAPI\r
975SnpTransmit (\r
976 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
977 IN UINTN HdrSize,\r
978 IN UINTN BuffSize,\r
979 IN VOID* Data,\r
980 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
981 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
982 IN UINT16 *Protocol OPTIONAL\r
983 )\r
984{\r
985 LAN9118_DRIVER *LanDriver;\r
986 UINT32 TxFreeSpace;\r
987 UINT32 TxStatusSpace;\r
988 INT32 Count;\r
989 UINT32 CommandA;\r
990 UINT32 CommandB;\r
991 UINT16 LocalProtocol;\r
992 UINT32 *LocalData;\r
993 UINT16 PacketTag;\r
994\r
995#if defined(EVAL_PERFORMANCE)\r
996 UINT64 Perf;\r
997 UINT64 StartClock;\r
998 UINT64 EndClock;\r
999\r
1000 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1001 StartClock = GetPerformanceCounter ();\r
1002#endif\r
1003\r
1004 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1005\r
1006 // Check preliminaries\r
1007 if ((Snp == NULL) || (Data == NULL)) {\r
1008 return EFI_INVALID_PARAMETER;\r
1009 }\r
1010 if (Snp->Mode->State != EfiSimpleNetworkInitialized) {\r
1011 return EFI_NOT_STARTED;\r
1012 }\r
1013\r
1014 // Ensure header is correct size if non-zero\r
1015 if (HdrSize) {\r
1016 if (HdrSize != Snp->Mode->MediaHeaderSize) {\r
1017 return EFI_INVALID_PARAMETER;\r
1018 }\r
1019\r
1020 if ((DstAddr == NULL) || (Protocol == NULL)) {\r
1021 return EFI_INVALID_PARAMETER;\r
1022 }\r
1023 }\r
1024\r
1025 // Before transmitting check the link status\r
1026 /*if (CheckLinkStatus (0, Snp) < 0) {\r
1027 return EFI_NOT_READY;\r
1028 }*/\r
1029\r
1030 // Get DATA FIFO free space in bytes\r
1031 TxFreeSpace = TxDataFreeSpace (0, Snp);\r
1032 if (TxFreeSpace < BuffSize) {\r
1033 return EFI_NOT_READY;\r
1034 }\r
1035\r
1036 // Get STATUS FIFO used space in bytes\r
1037 TxStatusSpace = TxStatusUsedSpace (0, Snp);\r
1038 if (TxStatusSpace > 500) {\r
1039 return EFI_NOT_READY;\r
1040 }\r
1041\r
1042 // If DstAddr is not provided, get it from Buffer (we trust that the caller\r
1043 // has provided a well-formed frame).\r
1044 if (DstAddr == NULL) {\r
1045 DstAddr = (EFI_MAC_ADDRESS *) Data;\r
1046 }\r
1047\r
1048 // Check for the nature of the frame\r
1049 if ((DstAddr->Addr[0] & 0x1) == 1) {\r
1050 LanDriver->Stats.TxMulticastFrames += 1;\r
1051 } else {\r
1052 LanDriver->Stats.TxUnicastFrames += 1;\r
1053 }\r
1054\r
1055 // Check if broadcast\r
1056 if (DstAddr->Addr[0] == 0xFF) {\r
1057 LanDriver->Stats.TxBroadcastFrames += 1;\r
1058 }\r
1059\r
1060 PacketTag = LanDriver->NextPacketTag;\r
1061 LanDriver->NextPacketTag++;\r
1062\r
1063 if (HdrSize) {\r
1064\r
1065 // Format pointer\r
1066 LocalData = (UINT32*) Data;\r
1067 LocalProtocol = *Protocol;\r
1068\r
1069 // Create first buffer to pass to controller (for the header)\r
1070 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);\r
1071 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1072\r
1073 // Write the commands first\r
1074 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1075 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1076\r
1077 // Write the destination address\r
1078 MmioWrite32 (LAN9118_TX_DATA,\r
1079 (DstAddr->Addr[0]) |\r
1080 (DstAddr->Addr[1] << 8) |\r
1081 (DstAddr->Addr[2] << 16) |\r
1082 (DstAddr->Addr[3] << 24)\r
1083 );\r
1084\r
1085 MmioWrite32 (LAN9118_TX_DATA,\r
1086 (DstAddr->Addr[4]) |\r
1087 (DstAddr->Addr[5] << 8) |\r
1088 (SrcAddr->Addr[0] << 16) | // Write the Source Address\r
1089 (SrcAddr->Addr[1] << 24)\r
1090 );\r
1091\r
1092 MmioWrite32 (LAN9118_TX_DATA,\r
1093 (SrcAddr->Addr[2]) |\r
1094 (SrcAddr->Addr[3] << 8) |\r
1095 (SrcAddr->Addr[4] << 16) |\r
1096 (SrcAddr->Addr[5] << 24)\r
1097 );\r
1098\r
1099 // Write the Protocol\r
1100 MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));\r
1101\r
1102 // Next buffer is the payload\r
1103 CommandA = TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize - HdrSize) | TX_CMD_A_COMPLETION_INT | TX_CMD_A_DATA_START_OFFSET (2); // 2 bytes beginning offset\r
1104\r
1105 // Write the commands\r
1106 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1107 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1108\r
1109 // Write the payload\r
1110 for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {\r
1111 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);\r
1112 }\r
1113 } else {\r
1114 // Format pointer\r
1115 LocalData = (UINT32*) Data;\r
1116\r
1117 // Create a buffer to pass to controller\r
1118 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;\r
1119 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1120\r
1121 // Write the commands first\r
1122 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1123 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1124\r
1125 // Write all the data\r
1126 for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {\r
1127 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);\r
1128 }\r
1129 }\r
1130\r
1131 // Save the address of the submitted packet so we can notify the consumer that\r
1132 // it has been sent in GetStatus. When the packet tag appears in the Tx Status\r
1133 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.\r
1134 LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;\r
1135\r
1136#if defined(EVAL_PERFORMANCE)\r
1137 EndClock = GetPerformanceCounter ();\r
1138 DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1139#endif\r
1140\r
1141 LanDriver->Stats.TxGoodFrames += 1;\r
1142\r
1143 return EFI_SUCCESS;\r
1144}\r
1145\r
1146\r
1147/*\r
1148 * UEFI Receive() function\r
1149 *\r
1150 */\r
1151EFI_STATUS\r
1152EFIAPI\r
1153SnpReceive (\r
1154 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1155 OUT UINTN *HdrSize OPTIONAL,\r
1156 IN OUT UINTN *BuffSize,\r
1157 OUT VOID *Data,\r
1158 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1159 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1160 OUT UINT16 *Protocol OPTIONAL\r
1161 )\r
1162{\r
1163 LAN9118_DRIVER *LanDriver;\r
1164 UINT32 RxFifoStatus;\r
1165 UINT32 NumPackets;\r
1166 UINT32 RxCfgValue;\r
1167 UINT32 PLength; // Packet length\r
1168 UINT32 ReadLimit;\r
1169 UINT32 Count;\r
1170 UINT32 Padding;\r
1171 UINT32 *RawData;\r
1172 EFI_MAC_ADDRESS Dst;\r
1173 EFI_MAC_ADDRESS Src;\r
1174 UINTN DroppedFrames;\r
1175\r
1176 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1177\r
1178#if defined(EVAL_PERFORMANCE)\r
1179 UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1180 UINT64 StartClock = GetPerformanceCounter ();\r
1181#endif\r
1182\r
1183 // Check preliminaries\r
1184 if ((Snp == NULL) || (Data == NULL)) {\r
1185 return EFI_INVALID_PARAMETER;\r
1186 }\r
1187\r
1188 if (Snp->Mode->State != EfiSimpleNetworkInitialized) {\r
1189 return EFI_NOT_STARTED;\r
1190 }\r
1191\r
1192 // Count dropped frames\r
1193 DroppedFrames = MmioRead32 (LAN9118_RX_DROP);\r
1194 LanDriver->Stats.RxDroppedFrames += DroppedFrames;\r
1195\r
1196 NumPackets = RxStatusUsedSpace (0, Snp) / 4;\r
1197 if (!NumPackets) {\r
1198 return EFI_NOT_READY;\r
1199 }\r
1200\r
1201 // Read Rx Status (only if not empty)\r
1202 RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS);\r
1203 LanDriver->Stats.RxTotalFrames += 1;\r
1204\r
1205 // First check for errors\r
1206 if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||\r
1207 (RxFifoStatus & RXSTATUS_RXW_TO) ||\r
1208 (RxFifoStatus & RXSTATUS_FTL) ||\r
1209 (RxFifoStatus & RXSTATUS_LCOLL) ||\r
1210 (RxFifoStatus & RXSTATUS_LE) ||\r
1211 (RxFifoStatus & RXSTATUS_DB))\r
1212 {\r
1213 DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));\r
1214 return EFI_DEVICE_ERROR;\r
1215 }\r
1216\r
1217 // Check if we got a CRC error\r
1218 if (RxFifoStatus & RXSTATUS_CRC_ERROR) {\r
1219 DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));\r
1220 LanDriver->Stats.RxCrcErrorFrames += 1;\r
1221 LanDriver->Stats.RxDroppedFrames += 1;\r
1222 return EFI_DEVICE_ERROR;\r
1223 }\r
1224\r
1225 // Check if we got a runt frame\r
1226 if (RxFifoStatus & RXSTATUS_RUNT) {\r
1227 DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));\r
1228 LanDriver->Stats.RxUndersizeFrames += 1;\r
1229 LanDriver->Stats.RxDroppedFrames += 1;\r
1230 return EFI_DEVICE_ERROR;\r
1231 }\r
1232\r
1233 // Check filtering status for this packet\r
1234 if (RxFifoStatus & RXSTATUS_FILT_FAIL) {\r
1235 DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));\r
1236 // fast forward?\r
1237 }\r
1238\r
1239 // Check if we got a broadcast frame\r
1240 if (RxFifoStatus & RXSTATUS_BCF) {\r
1241 LanDriver->Stats.RxBroadcastFrames += 1;\r
1242 }\r
1243\r
1244 // Check if we got a multicast frame\r
1245 if (RxFifoStatus & RXSTATUS_MCF) {\r
1246 LanDriver->Stats.RxMulticastFrames += 1;\r
1247 }\r
1248\r
1249 // Check if we got a unicast frame\r
1250 if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {\r
1251 LanDriver->Stats.RxUnicastFrames += 1;\r
1252 }\r
1253\r
1254 // Get the received packet length\r
1255 PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);\r
1256 LanDriver->Stats.RxTotalBytes += (PLength - 4);\r
1257\r
1258 // Check buffer size\r
1259 if (*BuffSize < PLength) {\r
1260 *BuffSize = PLength;\r
1261 return EFI_BUFFER_TOO_SMALL;\r
1262 }\r
1263\r
1264 // If padding is applied, read more DWORDs\r
1265 if (PLength % 4) {\r
1266 Padding = 4 - (PLength % 4);\r
1267 ReadLimit = (PLength + Padding)/4;\r
1268 } else {\r
1269 ReadLimit = PLength/4;\r
1270 Padding = 0;\r
1271 }\r
1272\r
1273 // Set the amount of data to be transfered out of FIFO for THIS packet\r
1274 // This can be used to trigger an interrupt, and status can be checked\r
1275 RxCfgValue = MmioRead32 (LAN9118_RX_CFG);\r
1276 RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);\r
1277 RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);\r
1278\r
1279 // Set end alignment to 4-bytes\r
1280 RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);\r
1281 MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);\r
1282\r
1283 // Update buffer size\r
1284 *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as\r
1285 // 4 bytes longer than packet actually is, unless\r
1286 // packet is < 64 bytes\r
1287\r
1288 if (HdrSize != NULL)\r
1289 *HdrSize = Snp->Mode->MediaHeaderSize;\r
1290\r
1291 // Format the pointer\r
1292 RawData = (UINT32*)Data;\r
1293\r
1294 // Read Rx Packet\r
1295 for (Count = 0; Count < ReadLimit; Count++) {\r
1296 RawData[Count] = MmioRead32 (LAN9118_RX_DATA);\r
1297 }\r
1298\r
1299 // Check for Rx errors (worst possible error)\r
1300 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {\r
1301 DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));\r
1302\r
1303 // Initiate a software reset\r
1304 if (SoftReset (0, Snp) < 0) {\r
1305 DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));\r
1306 return EFI_DEVICE_ERROR;\r
1307 }\r
1308\r
1309 // Acknowledge the RXE\r
1310 MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);\r
1311 gBS->Stall (LAN9118_STALL);\r
1312\r
1313 // Restart the rx (and do not clear FIFO)\r
1314 StartRx (0, Snp);\r
1315\r
1316 // Say that command could not be sent\r
1317 return EFI_DEVICE_ERROR;\r
1318 }\r
1319\r
1320 // Get the destination address\r
1321 if (DstAddr != NULL) {\r
1322 Dst.Addr[0] = (RawData[0] & 0xFF);\r
1323 Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;\r
1324 Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;\r
1325 Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;\r
1326 Dst.Addr[4] = (RawData[1] & 0xFF);\r
1327 Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;\r
1328 CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);\r
1329 }\r
1330\r
1331 // Get the source address\r
1332 if (SrcAddr != NULL) {\r
1333 Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;\r
1334 Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;\r
1335 Src.Addr[2] = (RawData[2] & 0xFF);\r
1336 Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;\r
1337 Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;\r
1338 Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;\r
1339 CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN);\r
1340 }\r
1341\r
1342 // Get the protocol\r
1343 if (Protocol != NULL) {\r
1344 *Protocol = NTOHS (RawData[3] & 0xFFFF);\r
1345 }\r
1346\r
1347#if defined(EVAL_PERFORMANCE)\r
1348 UINT64 EndClock = GetPerformanceCounter ();\r
1349 DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1350#endif\r
1351\r
1352 LanDriver->Stats.RxGoodFrames += 1;\r
1353\r
1354 return EFI_SUCCESS;\r
1355}\r