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