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