]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c
EmbeddedPkg/Lan9118Dxe: Add or fix input parameter checks
[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
492 return EFI_SUCCESS;\r
493}\r
494\r
0150e14d
RC
495/**\r
496 Enable and/or disable the receive filters of the LAN9118\r
497\r
498 Please refer to the UEFI specification for the precedence rules among the\r
499 Enable, Disable and ResetMCastFilter parameters.\r
500\r
501 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL\r
502 instance.\r
503 @param[in] Enable A bit mask of receive filters to enable.\r
504 @param[in] Disable A bit mask of receive filters to disable.\r
505 @param[in] ResetMCastFilter Set to TRUE to reset the contents of the multicast\r
506 receive filters on the network interface to\r
507 their default values.\r
508 @param[in] MCastFilterCnt Number of multicast HW MAC addresses in the new\r
509 MCastFilter list. This value must be less than or\r
510 equal to the MCastFilterCnt field of\r
511 EFI_SIMPLE_NETWORK_MODE. This field is optional if\r
512 ResetMCastFilter is TRUE.\r
513 @param[in] MCastFilter A pointer to a list of new multicast receive\r
514 filter HW MAC addresses. This list will replace\r
515 any existing multicast HW MAC address list. This\r
516 field is optional if ResetMCastFilter is TRUE.\r
517\r
518 @retval EFI_SUCCESS The receive filters of the LAN9118 were updated.\r
519 @retval EFI_NOT_STARTED The LAN9118 has not been started.\r
520 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :\r
521 . This is NULL\r
522 . Multicast is being enabled (the\r
523 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in\r
524 Enable, it is not set in Disable, and ResetMCastFilter\r
525 is FALSE) and MCastFilterCount is zero.\r
526 . Multicast is being enabled and MCastFilterCount is\r
527 greater than Snp->Mode->MaxMCastFilterCount.\r
528 . Multicast is being enabled and MCastFilter is NULL\r
529 . Multicast is being enabled and one or more of the\r
530 addresses in the MCastFilter list are not valid\r
531 multicast MAC addresses.\r
532 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.\r
46f2c53b 533\r
0150e14d 534**/\r
46f2c53b
OM
535EFI_STATUS\r
536EFIAPI\r
537SnpReceiveFilters (\r
0150e14d
RC
538 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
539 IN UINT32 Enable,\r
540 IN UINT32 Disable,\r
541 IN BOOLEAN ResetMCastFilter,\r
542 IN UINTN MCastFilterCnt OPTIONAL,\r
543 IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL\r
46f2c53b
OM
544 )\r
545{\r
0150e14d
RC
546 EFI_SIMPLE_NETWORK_MODE *Mode;\r
547 UINT32 MultHashTableHigh;\r
548 UINT32 MultHashTableLow;\r
549 UINT32 Count;\r
550 UINT32 Crc;\r
551 UINT8 HashValue;\r
552 UINT32 MacCSRValue;\r
553 EFI_MAC_ADDRESS *Mac;\r
46f2c53b 554\r
0150e14d
RC
555 // Check Snp Instance\r
556 if (Snp == NULL) {\r
557 return EFI_INVALID_PARAMETER;\r
558 }\r
559 Mode = Snp->Mode;\r
46f2c53b
OM
560\r
561 // Check that driver was started and initialised\r
0150e14d 562 if (Mode->State == EfiSimpleNetworkStarted) {\r
46f2c53b
OM
563 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
564 return EFI_DEVICE_ERROR;\r
0150e14d 565 } else if (Mode->State == EfiSimpleNetworkStopped) {\r
46f2c53b
OM
566 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
567 return EFI_NOT_STARTED;\r
568 }\r
569\r
0150e14d
RC
570 if ((Enable & (~Mode->ReceiveFilterMask)) ||\r
571 (Disable & (~Mode->ReceiveFilterMask)) ) {\r
572 return EFI_INVALID_PARAMETER;\r
46f2c53b
OM
573 }\r
574\r
0150e14d
RC
575 //\r
576 // Check the validity of the multicast setting and compute the\r
577 // hash values of the multicast mac addresses to listen to.\r
578 //\r
46f2c53b 579\r
0150e14d
RC
580 MultHashTableHigh = 0;\r
581 MultHashTableLow = 0;\r
582 if ((!ResetMCastFilter) &&\r
583 ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) == 0) &&\r
584 ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) ) {\r
585 if ((MCastFilterCnt == 0) ||\r
586 (MCastFilterCnt > Mode->MaxMCastFilterCount) ||\r
587 (MCastFilter == NULL) ) {\r
588 return EFI_INVALID_PARAMETER;\r
589 }\r
590 //\r
591 // Check the validity of all multicast addresses before to change\r
592 // anything.\r
593 //\r
594 for (Count = 0; Count < MCastFilterCnt; Count++) {\r
595 if ((MCastFilter[Count].Addr[0] & 1) == 0) {\r
596 return EFI_INVALID_PARAMETER;\r
597 }\r
598 }\r
46f2c53b 599\r
0150e14d 600 //\r
46f2c53b 601 // Go through each filter address and set appropriate bits on hash table\r
0150e14d
RC
602 //\r
603 for (Count = 0; Count < MCastFilterCnt; Count++) {\r
604 Mac = &(MCastFilter[Count]);\r
605 CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS));\r
46f2c53b 606\r
0150e14d 607 Crc = GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN);\r
46f2c53b
OM
608 //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired\r
609\r
0150e14d
RC
610 //\r
611 // The most significant 6 bits of the MAC address CRC constitute the hash\r
612 // value of the MAC address.\r
613 //\r
614 HashValue = (Crc >> 26) & 0x3F;\r
46f2c53b
OM
615\r
616 // Select hashlow register if MSB is not set\r
0150e14d
RC
617 if ((HashValue & 0x20) == 0) {\r
618 MultHashTableLow |= (1 << HashValue);\r
46f2c53b 619 } else {\r
0150e14d 620 MultHashTableHigh |= (1 << (HashValue & 0x1F));\r
46f2c53b
OM
621 }\r
622 }\r
0150e14d
RC
623 Mode->MCastFilterCount = MCastFilterCnt;\r
624 } else if (ResetMCastFilter) {\r
625 Mode->MCastFilterCount = 0;\r
626 } else {\r
627 MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL);\r
628 MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH);\r
46f2c53b
OM
629 }\r
630\r
0150e14d
RC
631 //\r
632 // Write the mask of the selected hash values for the multicast filtering.\r
633 // The two masks are set to zero if the multicast filtering is not enabled.\r
634 //\r
635 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow);\r
636 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh);\r
637\r
46f2c53b
OM
638 // Read MAC controller\r
639 MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);\r
640\r
641 // Set the options for the MAC_CSR\r
642 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {\r
643 StartRx (0, Snp);\r
644 DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n"));\r
645 }\r
646\r
647 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {\r
648 StopRx (0, Snp);\r
649 DEBUG ((DEBUG_NET, "Disabling Unicast Frame Reception\n"));\r
650 }\r
651\r
652 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {\r
653 MacCSRValue |= MACCR_HPFILT;\r
654 DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n"));\r
655 }\r
656\r
657 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {\r
658 MacCSRValue &= ~MACCR_HPFILT;\r
659 DEBUG ((DEBUG_NET, "Disabling Multicast Frame Reception\n"));\r
660 }\r
661\r
662 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {\r
663 MacCSRValue &= ~(MACCR_BCAST);\r
664 DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n"));\r
665 }\r
666\r
667 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {\r
668 MacCSRValue |= MACCR_BCAST;\r
669 DEBUG ((DEBUG_NET, "Disabling Broadcast Frame Reception\n"));\r
670 }\r
671\r
672 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {\r
673 MacCSRValue |= MACCR_PRMS;\r
674 DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n"));\r
675 }\r
676\r
677 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {\r
678 MacCSRValue &= ~MACCR_PRMS;\r
679 DEBUG ((DEBUG_NET, "Disabling Promiscuous Mode\n"));\r
680 }\r
681\r
682 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
683 MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS);\r
684 DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n"));\r
685 }\r
686\r
687 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
688 MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS);\r
689 DEBUG ((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n"));\r
690 }\r
691\r
692 // Write the options to the MAC_CSR\r
693 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue);\r
694 gBS->Stall (LAN9118_STALL);\r
695\r
696 return EFI_SUCCESS;\r
697}\r
698\r
0150e14d
RC
699/**\r
700 Modify of reset the current station address\r
701\r
702 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL\r
703 instance.\r
704 @param[in] Reset Flag used to reset the station address to the\r
705 LAN9118's permanent address.\r
706 @param[in] New New station address to be used for the network interface.\r
707\r
708 @retval EFI_SUCCESS The LAN9118's station address was updated.\r
709 @retval EFI_NOT_STARTED The LAN9118 has not been started.\r
710 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :\r
711 . The "New" station address is invalid.\r
712 . "Reset" is FALSE and "New" is NULL.\r
713 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.\r
714\r
715**/\r
46f2c53b
OM
716EFI_STATUS\r
717EFIAPI\r
718SnpStationAddress (\r
0150e14d
RC
719 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
720 IN BOOLEAN Reset,\r
721 IN EFI_MAC_ADDRESS *New\r
46f2c53b
OM
722)\r
723{\r
46f2c53b 724 UINT32 Count;\r
0150e14d 725 UINT8 PermAddr[NET_ETHER_ADDR_LEN];\r
46f2c53b 726\r
0150e14d 727 DEBUG ((DEBUG_NET, "SnpStationAddress()\n"));\r
46f2c53b
OM
728\r
729 // Check Snp instance\r
730 if (Snp == NULL) {\r
731 return EFI_INVALID_PARAMETER;\r
732 }\r
733\r
734 // Check that driver was started and initialised\r
735 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
736 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
737 return EFI_DEVICE_ERROR;\r
738 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
739 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
740 return EFI_NOT_STARTED;\r
741 }\r
742\r
743 // Get the Permanent MAC address if need reset\r
744 if (Reset) {\r
745 // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0\r
746 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) {\r
0150e14d
RC
747 for (Count = 0; Count < NET_ETHER_ADDR_LEN; Count++) {\r
748 PermAddr[Count] = IndirectEEPROMRead32 (Count + 1);\r
46f2c53b 749 }\r
0150e14d 750 New = (EFI_MAC_ADDRESS *) PermAddr;\r
46f2c53b
OM
751 Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp);\r
752 } else {\r
753 DEBUG ((EFI_D_ERROR, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n"));\r
0150e14d 754 New = (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress));\r
46f2c53b
OM
755 }\r
756 } else {\r
757 // Otherwise use the specified new MAC address\r
0150e14d
RC
758 if (New == NULL) {\r
759 return EFI_INVALID_PARAMETER;\r
760 }\r
761 //\r
762 // If it is a multicast address, it is not valid.\r
763 //\r
764 if (New->Addr[0] & 0x01) {\r
46f2c53b
OM
765 return EFI_INVALID_PARAMETER;\r
766 }\r
46f2c53b
OM
767 }\r
768\r
0150e14d
RC
769 // Write address\r
770 Lan9118SetMacAddress (New, Snp);\r
771\r
46f2c53b
OM
772 return EFI_SUCCESS;\r
773}\r
774\r
775/*\r
776 * UEFI Statistics() function\r
777 *\r
778 */\r
779EFI_STATUS\r
780EFIAPI\r
781SnpStatistics (\r
782 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
783 IN BOOLEAN Reset,\r
784 IN OUT UINTN *StatSize,\r
785 OUT EFI_NETWORK_STATISTICS *Statistics\r
786 )\r
787{\r
0150e14d
RC
788 LAN9118_DRIVER *LanDriver;\r
789 EFI_STATUS Status;\r
46f2c53b
OM
790\r
791 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
792\r
793 DEBUG ((DEBUG_NET, "SnpStatistics()\n"));\r
794\r
795 // Check Snp instance\r
796 if (Snp == NULL) {\r
797 return EFI_INVALID_PARAMETER;\r
798 }\r
799\r
800 // Check that driver was started and initialised\r
801 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
802 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
803 return EFI_DEVICE_ERROR;\r
804 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
805 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
806 return EFI_NOT_STARTED;\r
807 }\r
808\r
0150e14d
RC
809 //\r
810 // Do a reset if required. It is not clearly stated in the UEFI specification\r
811 // whether the reset has to be done before to copy the statistics in "Statictics"\r
812 // or after. It is a bit strange to do it before but that is what is expected by\r
813 // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89,\r
814 // 0x54,0x7e,0x4f,0xad,0x4f,0x24".\r
815 //\r
46f2c53b
OM
816 if (Reset) {\r
817 ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));\r
818 }\r
819\r
0150e14d
RC
820 Status = EFI_SUCCESS;\r
821 if (StatSize == NULL) {\r
822 if (Statistics != NULL) {\r
823 return EFI_INVALID_PARAMETER;\r
824 }\r
825 } else {\r
826 if (Statistics == NULL) {\r
827 Status = EFI_BUFFER_TOO_SMALL;\r
828 } else {\r
829 // Fill in the statistics\r
830 CopyMem (\r
831 Statistics, &LanDriver->Stats,\r
832 MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS))\r
833 );\r
834 if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) {\r
835 Status = EFI_BUFFER_TOO_SMALL;\r
836 }\r
837 }\r
838 *StatSize = sizeof (EFI_NETWORK_STATISTICS);\r
46f2c53b
OM
839 }\r
840\r
0150e14d 841 return Status;\r
46f2c53b
OM
842}\r
843\r
844/*\r
845 * UEFI MCastIPtoMAC() function\r
846 *\r
847 */\r
848EFI_STATUS\r
849EFIAPI\r
850SnpMcastIptoMac (\r
851 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
852 IN BOOLEAN IsIpv6,\r
853 IN EFI_IP_ADDRESS *Ip,\r
854 OUT EFI_MAC_ADDRESS *McastMac\r
855 )\r
856{\r
857 DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n"));\r
858\r
859 // Check Snp instance\r
860 if (Snp == NULL) {\r
861 return EFI_INVALID_PARAMETER;\r
862 }\r
863\r
864 // Check that driver was started and initialised\r
865 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
866 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
867 return EFI_DEVICE_ERROR;\r
868 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
869 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
870 return EFI_NOT_STARTED;\r
871 }\r
872\r
873 // Check parameters\r
874 if ((McastMac == NULL) || (Ip == NULL)) {\r
875 return EFI_INVALID_PARAMETER;\r
876 }\r
877\r
878 // Make sure MAC address is empty\r
879 ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));\r
880\r
881 // If we need ipv4 address\r
882 if (!IsIpv6) {\r
883 // Most significant 25 bits of a multicast HW address are set.\r
884 // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)\r
885 McastMac->Addr[0] = 0x01;\r
886 McastMac->Addr[1] = 0x00;\r
887 McastMac->Addr[2] = 0x5E;\r
888\r
889 // Lower 23 bits from ipv4 address\r
890 McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)\r
891 McastMac->Addr[4] = Ip->v4.Addr[2];\r
892 McastMac->Addr[5] = Ip->v4.Addr[3];\r
893 } else {\r
894 // Most significant 16 bits of multicast v6 HW address are set\r
895 // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)\r
896 McastMac->Addr[0] = 0x33;\r
897 McastMac->Addr[1] = 0x33;\r
898\r
899 // lower four octets are taken from ipv6 address\r
900 McastMac->Addr[2] = Ip->v6.Addr[8];\r
901 McastMac->Addr[3] = Ip->v6.Addr[9];\r
902 McastMac->Addr[4] = Ip->v6.Addr[10];\r
903 McastMac->Addr[5] = Ip->v6.Addr[11];\r
904 }\r
905\r
906 return EFI_SUCCESS;\r
907}\r
908\r
909/*\r
910 * UEFI NvData() function\r
911 *\r
912 */\r
913EFI_STATUS\r
914EFIAPI\r
915SnpNvData (\r
916 IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,\r
917 IN BOOLEAN read_write,\r
918 IN UINTN offset,\r
919 IN UINTN buff_size,\r
920 IN OUT VOID *data\r
921 )\r
922{\r
923 DEBUG ((DEBUG_NET, "SnpNvData()\n"));\r
924\r
925 return EFI_UNSUPPORTED;\r
926}\r
927\r
928\r
929/*\r
930 * UEFI GetStatus () function\r
931 *\r
932 */\r
933EFI_STATUS\r
934EFIAPI\r
935SnpGetStatus (\r
0150e14d
RC
936 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
937 OUT UINT32 *IrqStat OPTIONAL,\r
938 OUT VOID **TxBuff OPTIONAL\r
46f2c53b
OM
939 )\r
940{\r
941 UINT32 FifoInt;\r
942 EFI_STATUS Status;\r
943 UINTN NumTxStatusEntries;\r
944 UINT32 TxStatus;\r
945 UINT16 PacketTag;\r
946 UINT32 Interrupts;\r
947 LAN9118_DRIVER *LanDriver;\r
948\r
949 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
950\r
951 // Check preliminaries\r
952 if (Snp == NULL) {\r
953 return EFI_INVALID_PARAMETER;\r
954 }\r
955\r
0150e14d
RC
956 // Check that driver was started and initialised\r
957 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
958 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
959 return EFI_DEVICE_ERROR;\r
960 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
961 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
962 return EFI_NOT_STARTED;\r
963 }\r
964\r
965 // Check and acknowledge TX Status interrupt (this will happen if the\r
966 // consumer of SNP does not call GetStatus.)\r
967 // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we\r
968 // should check for it and dump the TX Status FIFO.\r
969 FifoInt = MmioRead32 (LAN9118_FIFO_INT);\r
970\r
971 // Clear the TX Status FIFO Overflow\r
972 if ((FifoInt & INSTS_TXSO) == 0) {\r
973 FifoInt |= INSTS_TXSO;\r
974 MmioWrite32 (LAN9118_FIFO_INT, FifoInt);\r
975 }\r
976\r
977 // Read interrupt status if IrqStat is not NULL\r
978 if (IrqStat != NULL) {\r
979\r
980 // Check for receive interrupt\r
981 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO\r
982 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
983 MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);\r
984 } else {\r
985 *IrqStat &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
986 }\r
987\r
988 // Check for transmit interrupt\r
989 if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {\r
990 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
991 MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);\r
992 } else {\r
993 *IrqStat &= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
994 }\r
995\r
996 // Check for software interrupt\r
997 if (MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) {\r
998 *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;\r
999 MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT);\r
1000 } else {\r
1001 *IrqStat &= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;\r
1002 }\r
1003 }\r
1004\r
1005 // Check Status of transmitted packets\r
1006 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)\r
1007\r
1008 NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;\r
1009 if (NumTxStatusEntries > 0) {\r
1010 TxStatus = MmioRead32 (LAN9118_TX_STATUS);\r
1011 PacketTag = TxStatus >> 16;\r
1012 TxStatus = TxStatus & 0xFFFF;\r
a537c717 1013 if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) {\r
46f2c53b
OM
1014 DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));\r
1015 if (TxStatus & TXSTATUS_NO_CA) {\r
1016 DEBUG ((EFI_D_ERROR, "- No carrier\n"));\r
1017 }\r
1018 if (TxStatus & TXSTATUS_DEF) {\r
1019 DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));\r
1020 }\r
1021 if (TxStatus & TXSTATUS_EDEF) {\r
1022 DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));\r
1023 }\r
1024 if (TxStatus & TXSTATUS_ECOLL) {\r
1025 DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));\r
1026 }\r
1027 if (TxStatus & TXSTATUS_LCOLL) {\r
1028 DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));\r
1029 }\r
1030 if (TxStatus & TXSTATUS_LOST_CA) {\r
1031 DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));\r
1032 }\r
1033 return EFI_DEVICE_ERROR;\r
a537c717 1034 } else if (TxBuff != NULL) {\r
46f2c53b
OM
1035 LanDriver->Stats.TxTotalFrames += 1;\r
1036 *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];\r
1037 }\r
1038 }\r
1039\r
1040 // Check for a TX Error interrupt\r
1041 Interrupts = MmioRead32 (LAN9118_INT_STS);\r
1042 if (Interrupts & INSTS_TXE) {\r
1043 DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));\r
1044\r
1045 // Initiate a software reset\r
42589b9a
OM
1046 Status = SoftReset (0, Snp);\r
1047 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
1048 DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));\r
1049 return EFI_DEVICE_ERROR;\r
1050 }\r
1051\r
1052 // Acknowledge the TXE\r
1053 MmioWrite32 (LAN9118_INT_STS, INSTS_TXE);\r
1054 gBS->Stall (LAN9118_STALL);\r
1055\r
1056 // Restart the transmitter\r
1057 StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
1058 }\r
1059\r
1060 // Update the media status\r
1061 Status = CheckLinkStatus (0, Snp);\r
1062 if (EFI_ERROR(Status)) {\r
1063 Snp->Mode->MediaPresent = FALSE;\r
1064 } else {\r
1065 Snp->Mode->MediaPresent = TRUE;\r
1066 }\r
1067\r
1068 return EFI_SUCCESS;\r
1069}\r
1070\r
1071\r
1072/*\r
1073 * UEFI Transmit() function\r
1074 *\r
1075 */\r
1076EFI_STATUS\r
1077EFIAPI\r
1078SnpTransmit (\r
1079 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1080 IN UINTN HdrSize,\r
1081 IN UINTN BuffSize,\r
1082 IN VOID* Data,\r
1083 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1084 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1085 IN UINT16 *Protocol OPTIONAL\r
1086 )\r
1087{\r
1088 LAN9118_DRIVER *LanDriver;\r
1089 UINT32 TxFreeSpace;\r
1090 UINT32 TxStatusSpace;\r
1091 INT32 Count;\r
1092 UINT32 CommandA;\r
1093 UINT32 CommandB;\r
1094 UINT16 LocalProtocol;\r
1095 UINT32 *LocalData;\r
1096 UINT16 PacketTag;\r
1097\r
1098#if defined(EVAL_PERFORMANCE)\r
1099 UINT64 Perf;\r
1100 UINT64 StartClock;\r
1101 UINT64 EndClock;\r
1102\r
1103 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1104 StartClock = GetPerformanceCounter ();\r
1105#endif\r
1106\r
1107 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1108\r
1109 // Check preliminaries\r
1110 if ((Snp == NULL) || (Data == NULL)) {\r
1111 return EFI_INVALID_PARAMETER;\r
1112 }\r
0150e14d
RC
1113\r
1114 // Check that driver was started and initialised\r
1115 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
1116 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
1117 return EFI_DEVICE_ERROR;\r
1118 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
1119 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
1120 return EFI_NOT_STARTED;\r
1121 }\r
1122\r
1123 // Ensure header is correct size if non-zero\r
1124 if (HdrSize) {\r
1125 if (HdrSize != Snp->Mode->MediaHeaderSize) {\r
1126 return EFI_INVALID_PARAMETER;\r
1127 }\r
1128\r
1129 if ((DstAddr == NULL) || (Protocol == NULL)) {\r
1130 return EFI_INVALID_PARAMETER;\r
1131 }\r
1132 }\r
1133\r
0150e14d
RC
1134 //\r
1135 // Check validity of BufferSize\r
1136 //\r
1137 if (BuffSize < Snp->Mode->MediaHeaderSize) {\r
1138 return EFI_BUFFER_TOO_SMALL;\r
1139 }\r
1140\r
46f2c53b
OM
1141 // Before transmitting check the link status\r
1142 /*if (CheckLinkStatus (0, Snp) < 0) {\r
1143 return EFI_NOT_READY;\r
1144 }*/\r
1145\r
1146 // Get DATA FIFO free space in bytes\r
1147 TxFreeSpace = TxDataFreeSpace (0, Snp);\r
1148 if (TxFreeSpace < BuffSize) {\r
1149 return EFI_NOT_READY;\r
1150 }\r
1151\r
1152 // Get STATUS FIFO used space in bytes\r
1153 TxStatusSpace = TxStatusUsedSpace (0, Snp);\r
1154 if (TxStatusSpace > 500) {\r
1155 return EFI_NOT_READY;\r
1156 }\r
1157\r
1158 // If DstAddr is not provided, get it from Buffer (we trust that the caller\r
1159 // has provided a well-formed frame).\r
1160 if (DstAddr == NULL) {\r
1161 DstAddr = (EFI_MAC_ADDRESS *) Data;\r
1162 }\r
1163\r
1164 // Check for the nature of the frame\r
1165 if ((DstAddr->Addr[0] & 0x1) == 1) {\r
1166 LanDriver->Stats.TxMulticastFrames += 1;\r
1167 } else {\r
1168 LanDriver->Stats.TxUnicastFrames += 1;\r
1169 }\r
1170\r
1171 // Check if broadcast\r
1172 if (DstAddr->Addr[0] == 0xFF) {\r
1173 LanDriver->Stats.TxBroadcastFrames += 1;\r
1174 }\r
1175\r
1176 PacketTag = LanDriver->NextPacketTag;\r
1177 LanDriver->NextPacketTag++;\r
1178\r
1179 if (HdrSize) {\r
1180\r
1181 // Format pointer\r
1182 LocalData = (UINT32*) Data;\r
1183 LocalProtocol = *Protocol;\r
1184\r
1185 // Create first buffer to pass to controller (for the header)\r
1186 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);\r
1187 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1188\r
1189 // Write the commands first\r
1190 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1191 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1192\r
1193 // Write the destination address\r
1194 MmioWrite32 (LAN9118_TX_DATA,\r
1195 (DstAddr->Addr[0]) |\r
1196 (DstAddr->Addr[1] << 8) |\r
1197 (DstAddr->Addr[2] << 16) |\r
1198 (DstAddr->Addr[3] << 24)\r
1199 );\r
1200\r
1201 MmioWrite32 (LAN9118_TX_DATA,\r
1202 (DstAddr->Addr[4]) |\r
1203 (DstAddr->Addr[5] << 8) |\r
1204 (SrcAddr->Addr[0] << 16) | // Write the Source Address\r
1205 (SrcAddr->Addr[1] << 24)\r
1206 );\r
1207\r
1208 MmioWrite32 (LAN9118_TX_DATA,\r
1209 (SrcAddr->Addr[2]) |\r
1210 (SrcAddr->Addr[3] << 8) |\r
1211 (SrcAddr->Addr[4] << 16) |\r
1212 (SrcAddr->Addr[5] << 24)\r
1213 );\r
1214\r
1215 // Write the Protocol\r
1216 MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));\r
1217\r
1218 // Next buffer is the payload\r
1219 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
1220\r
1221 // Write the commands\r
1222 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1223 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1224\r
1225 // Write the payload\r
1226 for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {\r
1227 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);\r
1228 }\r
1229 } else {\r
1230 // Format pointer\r
1231 LocalData = (UINT32*) Data;\r
1232\r
1233 // Create a buffer to pass to controller\r
1234 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;\r
1235 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1236\r
1237 // Write the commands first\r
1238 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1239 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1240\r
1241 // Write all the data\r
1242 for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {\r
1243 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);\r
1244 }\r
1245 }\r
1246\r
1247 // Save the address of the submitted packet so we can notify the consumer that\r
1248 // it has been sent in GetStatus. When the packet tag appears in the Tx Status\r
1249 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.\r
1250 LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;\r
1251\r
1252#if defined(EVAL_PERFORMANCE)\r
1253 EndClock = GetPerformanceCounter ();\r
1254 DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1255#endif\r
1256\r
1257 LanDriver->Stats.TxGoodFrames += 1;\r
1258\r
1259 return EFI_SUCCESS;\r
1260}\r
1261\r
1262\r
1263/*\r
1264 * UEFI Receive() function\r
1265 *\r
1266 */\r
1267EFI_STATUS\r
1268EFIAPI\r
1269SnpReceive (\r
1270 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1271 OUT UINTN *HdrSize OPTIONAL,\r
1272 IN OUT UINTN *BuffSize,\r
1273 OUT VOID *Data,\r
1274 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1275 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1276 OUT UINT16 *Protocol OPTIONAL\r
1277 )\r
1278{\r
42589b9a
OM
1279 LAN9118_DRIVER *LanDriver;\r
1280 UINT32 RxFifoStatus;\r
1281 UINT32 NumPackets;\r
1282 UINT32 RxCfgValue;\r
1283 UINT32 PLength; // Packet length\r
1284 UINT32 ReadLimit;\r
1285 UINT32 Count;\r
1286 UINT32 Padding;\r
1287 UINT32 *RawData;\r
46f2c53b
OM
1288 EFI_MAC_ADDRESS Dst;\r
1289 EFI_MAC_ADDRESS Src;\r
42589b9a
OM
1290 UINTN DroppedFrames;\r
1291 EFI_STATUS Status;\r
46f2c53b
OM
1292\r
1293 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1294\r
1295#if defined(EVAL_PERFORMANCE)\r
1296 UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1297 UINT64 StartClock = GetPerformanceCounter ();\r
1298#endif\r
1299\r
1300 // Check preliminaries\r
0150e14d 1301 if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) {\r
46f2c53b
OM
1302 return EFI_INVALID_PARAMETER;\r
1303 }\r
1304\r
0150e14d
RC
1305 // Check that driver was started and initialised\r
1306 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
1307 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
1308 return EFI_DEVICE_ERROR;\r
1309 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
1310 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
1311 return EFI_NOT_STARTED;\r
1312 }\r
1313\r
1314 // Count dropped frames\r
1315 DroppedFrames = MmioRead32 (LAN9118_RX_DROP);\r
1316 LanDriver->Stats.RxDroppedFrames += DroppedFrames;\r
1317\r
1318 NumPackets = RxStatusUsedSpace (0, Snp) / 4;\r
1319 if (!NumPackets) {\r
1320 return EFI_NOT_READY;\r
1321 }\r
1322\r
1323 // Read Rx Status (only if not empty)\r
1324 RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS);\r
1325 LanDriver->Stats.RxTotalFrames += 1;\r
1326\r
1327 // First check for errors\r
1328 if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||\r
1329 (RxFifoStatus & RXSTATUS_RXW_TO) ||\r
1330 (RxFifoStatus & RXSTATUS_FTL) ||\r
1331 (RxFifoStatus & RXSTATUS_LCOLL) ||\r
1332 (RxFifoStatus & RXSTATUS_LE) ||\r
1333 (RxFifoStatus & RXSTATUS_DB))\r
1334 {\r
1335 DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));\r
1336 return EFI_DEVICE_ERROR;\r
1337 }\r
1338\r
1339 // Check if we got a CRC error\r
1340 if (RxFifoStatus & RXSTATUS_CRC_ERROR) {\r
1341 DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));\r
1342 LanDriver->Stats.RxCrcErrorFrames += 1;\r
1343 LanDriver->Stats.RxDroppedFrames += 1;\r
1344 return EFI_DEVICE_ERROR;\r
1345 }\r
1346\r
1347 // Check if we got a runt frame\r
1348 if (RxFifoStatus & RXSTATUS_RUNT) {\r
1349 DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));\r
1350 LanDriver->Stats.RxUndersizeFrames += 1;\r
1351 LanDriver->Stats.RxDroppedFrames += 1;\r
1352 return EFI_DEVICE_ERROR;\r
1353 }\r
1354\r
1355 // Check filtering status for this packet\r
1356 if (RxFifoStatus & RXSTATUS_FILT_FAIL) {\r
1357 DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));\r
1358 // fast forward?\r
1359 }\r
1360\r
1361 // Check if we got a broadcast frame\r
1362 if (RxFifoStatus & RXSTATUS_BCF) {\r
1363 LanDriver->Stats.RxBroadcastFrames += 1;\r
1364 }\r
1365\r
1366 // Check if we got a multicast frame\r
1367 if (RxFifoStatus & RXSTATUS_MCF) {\r
1368 LanDriver->Stats.RxMulticastFrames += 1;\r
1369 }\r
1370\r
1371 // Check if we got a unicast frame\r
1372 if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {\r
1373 LanDriver->Stats.RxUnicastFrames += 1;\r
1374 }\r
1375\r
1376 // Get the received packet length\r
1377 PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);\r
1378 LanDriver->Stats.RxTotalBytes += (PLength - 4);\r
1379\r
1380 // Check buffer size\r
1381 if (*BuffSize < PLength) {\r
1382 *BuffSize = PLength;\r
1383 return EFI_BUFFER_TOO_SMALL;\r
1384 }\r
1385\r
1386 // If padding is applied, read more DWORDs\r
1387 if (PLength % 4) {\r
1388 Padding = 4 - (PLength % 4);\r
1389 ReadLimit = (PLength + Padding)/4;\r
1390 } else {\r
1391 ReadLimit = PLength/4;\r
1392 Padding = 0;\r
1393 }\r
1394\r
1395 // Set the amount of data to be transfered out of FIFO for THIS packet\r
1396 // This can be used to trigger an interrupt, and status can be checked\r
1397 RxCfgValue = MmioRead32 (LAN9118_RX_CFG);\r
1398 RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);\r
1399 RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);\r
1400\r
1401 // Set end alignment to 4-bytes\r
1402 RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);\r
1403 MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);\r
1404\r
1405 // Update buffer size\r
1406 *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as\r
1407 // 4 bytes longer than packet actually is, unless\r
1408 // packet is < 64 bytes\r
1409\r
1410 if (HdrSize != NULL)\r
1411 *HdrSize = Snp->Mode->MediaHeaderSize;\r
1412\r
1413 // Format the pointer\r
1414 RawData = (UINT32*)Data;\r
1415\r
1416 // Read Rx Packet\r
1417 for (Count = 0; Count < ReadLimit; Count++) {\r
1418 RawData[Count] = MmioRead32 (LAN9118_RX_DATA);\r
1419 }\r
1420\r
1421 // Check for Rx errors (worst possible error)\r
1422 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {\r
1423 DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));\r
1424\r
1425 // Initiate a software reset\r
42589b9a
OM
1426 Status = SoftReset (0, Snp);\r
1427 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
1428 DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));\r
1429 return EFI_DEVICE_ERROR;\r
1430 }\r
1431\r
1432 // Acknowledge the RXE\r
1433 MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);\r
1434 gBS->Stall (LAN9118_STALL);\r
1435\r
1436 // Restart the rx (and do not clear FIFO)\r
1437 StartRx (0, Snp);\r
1438\r
1439 // Say that command could not be sent\r
1440 return EFI_DEVICE_ERROR;\r
1441 }\r
1442\r
1443 // Get the destination address\r
1444 if (DstAddr != NULL) {\r
1445 Dst.Addr[0] = (RawData[0] & 0xFF);\r
1446 Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;\r
1447 Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;\r
1448 Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;\r
1449 Dst.Addr[4] = (RawData[1] & 0xFF);\r
1450 Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;\r
1451 CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);\r
1452 }\r
1453\r
1454 // Get the source address\r
1455 if (SrcAddr != NULL) {\r
1456 Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;\r
1457 Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;\r
1458 Src.Addr[2] = (RawData[2] & 0xFF);\r
1459 Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;\r
1460 Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;\r
1461 Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;\r
1462 CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN);\r
1463 }\r
1464\r
1465 // Get the protocol\r
1466 if (Protocol != NULL) {\r
1467 *Protocol = NTOHS (RawData[3] & 0xFFFF);\r
1468 }\r
1469\r
1470#if defined(EVAL_PERFORMANCE)\r
1471 UINT64 EndClock = GetPerformanceCounter ();\r
1472 DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1473#endif\r
1474\r
1475 LanDriver->Stats.RxGoodFrames += 1;\r
1476\r
1477 return EFI_SUCCESS;\r
1478}\r