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