EmbeddedPkg/Lan9118Dxe: Fix interrupt's mask returned by GetStatus
[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
e52aee5d 982 *IrqStat = 0;\r
46f2c53b
OM
983\r
984 // Check for receive interrupt\r
985 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO\r
986 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
987 MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);\r
46f2c53b
OM
988 }\r
989\r
990 // Check for transmit interrupt\r
991 if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {\r
992 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
993 MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);\r
46f2c53b
OM
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
46f2c53b
OM
1000 }\r
1001 }\r
1002\r
1003 // Check Status of transmitted packets\r
1004 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)\r
1005\r
1006 NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;\r
1007 if (NumTxStatusEntries > 0) {\r
1008 TxStatus = MmioRead32 (LAN9118_TX_STATUS);\r
1009 PacketTag = TxStatus >> 16;\r
1010 TxStatus = TxStatus & 0xFFFF;\r
a537c717 1011 if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) {\r
46f2c53b
OM
1012 DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));\r
1013 if (TxStatus & TXSTATUS_NO_CA) {\r
1014 DEBUG ((EFI_D_ERROR, "- No carrier\n"));\r
1015 }\r
1016 if (TxStatus & TXSTATUS_DEF) {\r
1017 DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));\r
1018 }\r
1019 if (TxStatus & TXSTATUS_EDEF) {\r
1020 DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));\r
1021 }\r
1022 if (TxStatus & TXSTATUS_ECOLL) {\r
1023 DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));\r
1024 }\r
1025 if (TxStatus & TXSTATUS_LCOLL) {\r
1026 DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));\r
1027 }\r
1028 if (TxStatus & TXSTATUS_LOST_CA) {\r
1029 DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));\r
1030 }\r
1031 return EFI_DEVICE_ERROR;\r
a537c717 1032 } else if (TxBuff != NULL) {\r
46f2c53b
OM
1033 LanDriver->Stats.TxTotalFrames += 1;\r
1034 *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];\r
1035 }\r
1036 }\r
1037\r
1038 // Check for a TX Error interrupt\r
1039 Interrupts = MmioRead32 (LAN9118_INT_STS);\r
1040 if (Interrupts & INSTS_TXE) {\r
1041 DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));\r
1042\r
1043 // Initiate a software reset\r
42589b9a
OM
1044 Status = SoftReset (0, Snp);\r
1045 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
1046 DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));\r
1047 return EFI_DEVICE_ERROR;\r
1048 }\r
1049\r
1050 // Acknowledge the TXE\r
1051 MmioWrite32 (LAN9118_INT_STS, INSTS_TXE);\r
1052 gBS->Stall (LAN9118_STALL);\r
1053\r
1054 // Restart the transmitter\r
1055 StartTx (START_TX_MAC | START_TX_CFG, Snp);\r
1056 }\r
1057\r
1058 // Update the media status\r
1059 Status = CheckLinkStatus (0, Snp);\r
1060 if (EFI_ERROR(Status)) {\r
1061 Snp->Mode->MediaPresent = FALSE;\r
1062 } else {\r
1063 Snp->Mode->MediaPresent = TRUE;\r
1064 }\r
1065\r
1066 return EFI_SUCCESS;\r
1067}\r
1068\r
1069\r
1070/*\r
1071 * UEFI Transmit() function\r
1072 *\r
1073 */\r
1074EFI_STATUS\r
1075EFIAPI\r
1076SnpTransmit (\r
1077 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,\r
1078 IN UINTN HdrSize,\r
1079 IN UINTN BuffSize,\r
1080 IN VOID* Data,\r
1081 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1082 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1083 IN UINT16 *Protocol OPTIONAL\r
1084 )\r
1085{\r
1086 LAN9118_DRIVER *LanDriver;\r
1087 UINT32 TxFreeSpace;\r
1088 UINT32 TxStatusSpace;\r
1089 INT32 Count;\r
1090 UINT32 CommandA;\r
1091 UINT32 CommandB;\r
1092 UINT16 LocalProtocol;\r
1093 UINT32 *LocalData;\r
1094 UINT16 PacketTag;\r
1095\r
1096#if defined(EVAL_PERFORMANCE)\r
1097 UINT64 Perf;\r
1098 UINT64 StartClock;\r
1099 UINT64 EndClock;\r
1100\r
1101 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1102 StartClock = GetPerformanceCounter ();\r
1103#endif\r
1104\r
1105 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1106\r
1107 // Check preliminaries\r
1108 if ((Snp == NULL) || (Data == NULL)) {\r
1109 return EFI_INVALID_PARAMETER;\r
1110 }\r
0150e14d
RC
1111\r
1112 // Check that driver was started and initialised\r
1113 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
1114 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
1115 return EFI_DEVICE_ERROR;\r
1116 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
1117 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
1118 return EFI_NOT_STARTED;\r
1119 }\r
1120\r
1121 // Ensure header is correct size if non-zero\r
1122 if (HdrSize) {\r
1123 if (HdrSize != Snp->Mode->MediaHeaderSize) {\r
1124 return EFI_INVALID_PARAMETER;\r
1125 }\r
1126\r
1127 if ((DstAddr == NULL) || (Protocol == NULL)) {\r
1128 return EFI_INVALID_PARAMETER;\r
1129 }\r
1130 }\r
1131\r
0150e14d
RC
1132 //\r
1133 // Check validity of BufferSize\r
1134 //\r
1135 if (BuffSize < Snp->Mode->MediaHeaderSize) {\r
1136 return EFI_BUFFER_TOO_SMALL;\r
1137 }\r
1138\r
46f2c53b
OM
1139 // Before transmitting check the link status\r
1140 /*if (CheckLinkStatus (0, Snp) < 0) {\r
1141 return EFI_NOT_READY;\r
1142 }*/\r
1143\r
1144 // Get DATA FIFO free space in bytes\r
1145 TxFreeSpace = TxDataFreeSpace (0, Snp);\r
1146 if (TxFreeSpace < BuffSize) {\r
1147 return EFI_NOT_READY;\r
1148 }\r
1149\r
1150 // Get STATUS FIFO used space in bytes\r
1151 TxStatusSpace = TxStatusUsedSpace (0, Snp);\r
1152 if (TxStatusSpace > 500) {\r
1153 return EFI_NOT_READY;\r
1154 }\r
1155\r
1156 // If DstAddr is not provided, get it from Buffer (we trust that the caller\r
1157 // has provided a well-formed frame).\r
1158 if (DstAddr == NULL) {\r
1159 DstAddr = (EFI_MAC_ADDRESS *) Data;\r
1160 }\r
1161\r
1162 // Check for the nature of the frame\r
1163 if ((DstAddr->Addr[0] & 0x1) == 1) {\r
1164 LanDriver->Stats.TxMulticastFrames += 1;\r
1165 } else {\r
1166 LanDriver->Stats.TxUnicastFrames += 1;\r
1167 }\r
1168\r
1169 // Check if broadcast\r
1170 if (DstAddr->Addr[0] == 0xFF) {\r
1171 LanDriver->Stats.TxBroadcastFrames += 1;\r
1172 }\r
1173\r
1174 PacketTag = LanDriver->NextPacketTag;\r
1175 LanDriver->NextPacketTag++;\r
1176\r
1177 if (HdrSize) {\r
1178\r
1179 // Format pointer\r
1180 LocalData = (UINT32*) Data;\r
1181 LocalProtocol = *Protocol;\r
1182\r
1183 // Create first buffer to pass to controller (for the header)\r
1184 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);\r
1185 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1186\r
1187 // Write the commands first\r
1188 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1189 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1190\r
1191 // Write the destination address\r
1192 MmioWrite32 (LAN9118_TX_DATA,\r
1193 (DstAddr->Addr[0]) |\r
1194 (DstAddr->Addr[1] << 8) |\r
1195 (DstAddr->Addr[2] << 16) |\r
1196 (DstAddr->Addr[3] << 24)\r
1197 );\r
1198\r
1199 MmioWrite32 (LAN9118_TX_DATA,\r
1200 (DstAddr->Addr[4]) |\r
1201 (DstAddr->Addr[5] << 8) |\r
1202 (SrcAddr->Addr[0] << 16) | // Write the Source Address\r
1203 (SrcAddr->Addr[1] << 24)\r
1204 );\r
1205\r
1206 MmioWrite32 (LAN9118_TX_DATA,\r
1207 (SrcAddr->Addr[2]) |\r
1208 (SrcAddr->Addr[3] << 8) |\r
1209 (SrcAddr->Addr[4] << 16) |\r
1210 (SrcAddr->Addr[5] << 24)\r
1211 );\r
1212\r
1213 // Write the Protocol\r
1214 MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));\r
1215\r
1216 // Next buffer is the payload\r
1217 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
1218\r
1219 // Write the commands\r
1220 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1221 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1222\r
1223 // Write the payload\r
1224 for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {\r
1225 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);\r
1226 }\r
1227 } else {\r
1228 // Format pointer\r
1229 LocalData = (UINT32*) Data;\r
1230\r
1231 // Create a buffer to pass to controller\r
1232 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;\r
1233 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);\r
1234\r
1235 // Write the commands first\r
1236 MmioWrite32 (LAN9118_TX_DATA, CommandA);\r
1237 MmioWrite32 (LAN9118_TX_DATA, CommandB);\r
1238\r
1239 // Write all the data\r
1240 for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {\r
1241 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);\r
1242 }\r
1243 }\r
1244\r
1245 // Save the address of the submitted packet so we can notify the consumer that\r
1246 // it has been sent in GetStatus. When the packet tag appears in the Tx Status\r
1247 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.\r
1248 LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;\r
1249\r
1250#if defined(EVAL_PERFORMANCE)\r
1251 EndClock = GetPerformanceCounter ();\r
1252 DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1253#endif\r
1254\r
1255 LanDriver->Stats.TxGoodFrames += 1;\r
1256\r
1257 return EFI_SUCCESS;\r
1258}\r
1259\r
1260\r
1261/*\r
1262 * UEFI Receive() function\r
1263 *\r
1264 */\r
1265EFI_STATUS\r
1266EFIAPI\r
1267SnpReceive (\r
1268 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,\r
1269 OUT UINTN *HdrSize OPTIONAL,\r
1270 IN OUT UINTN *BuffSize,\r
1271 OUT VOID *Data,\r
1272 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r
1273 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,\r
1274 OUT UINT16 *Protocol OPTIONAL\r
1275 )\r
1276{\r
42589b9a
OM
1277 LAN9118_DRIVER *LanDriver;\r
1278 UINT32 RxFifoStatus;\r
1279 UINT32 NumPackets;\r
1280 UINT32 RxCfgValue;\r
1281 UINT32 PLength; // Packet length\r
1282 UINT32 ReadLimit;\r
1283 UINT32 Count;\r
1284 UINT32 Padding;\r
1285 UINT32 *RawData;\r
46f2c53b
OM
1286 EFI_MAC_ADDRESS Dst;\r
1287 EFI_MAC_ADDRESS Src;\r
42589b9a
OM
1288 UINTN DroppedFrames;\r
1289 EFI_STATUS Status;\r
46f2c53b
OM
1290\r
1291 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);\r
1292\r
1293#if defined(EVAL_PERFORMANCE)\r
1294 UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);\r
1295 UINT64 StartClock = GetPerformanceCounter ();\r
1296#endif\r
1297\r
1298 // Check preliminaries\r
0150e14d 1299 if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) {\r
46f2c53b
OM
1300 return EFI_INVALID_PARAMETER;\r
1301 }\r
1302\r
0150e14d
RC
1303 // Check that driver was started and initialised\r
1304 if (Snp->Mode->State == EfiSimpleNetworkStarted) {\r
1305 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));\r
1306 return EFI_DEVICE_ERROR;\r
1307 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {\r
1308 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));\r
46f2c53b
OM
1309 return EFI_NOT_STARTED;\r
1310 }\r
1311\r
1312 // Count dropped frames\r
1313 DroppedFrames = MmioRead32 (LAN9118_RX_DROP);\r
1314 LanDriver->Stats.RxDroppedFrames += DroppedFrames;\r
1315\r
1316 NumPackets = RxStatusUsedSpace (0, Snp) / 4;\r
1317 if (!NumPackets) {\r
1318 return EFI_NOT_READY;\r
1319 }\r
1320\r
1321 // Read Rx Status (only if not empty)\r
1322 RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS);\r
1323 LanDriver->Stats.RxTotalFrames += 1;\r
1324\r
1325 // First check for errors\r
1326 if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||\r
1327 (RxFifoStatus & RXSTATUS_RXW_TO) ||\r
1328 (RxFifoStatus & RXSTATUS_FTL) ||\r
1329 (RxFifoStatus & RXSTATUS_LCOLL) ||\r
1330 (RxFifoStatus & RXSTATUS_LE) ||\r
1331 (RxFifoStatus & RXSTATUS_DB))\r
1332 {\r
1333 DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));\r
1334 return EFI_DEVICE_ERROR;\r
1335 }\r
1336\r
1337 // Check if we got a CRC error\r
1338 if (RxFifoStatus & RXSTATUS_CRC_ERROR) {\r
1339 DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));\r
1340 LanDriver->Stats.RxCrcErrorFrames += 1;\r
1341 LanDriver->Stats.RxDroppedFrames += 1;\r
1342 return EFI_DEVICE_ERROR;\r
1343 }\r
1344\r
1345 // Check if we got a runt frame\r
1346 if (RxFifoStatus & RXSTATUS_RUNT) {\r
1347 DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));\r
1348 LanDriver->Stats.RxUndersizeFrames += 1;\r
1349 LanDriver->Stats.RxDroppedFrames += 1;\r
1350 return EFI_DEVICE_ERROR;\r
1351 }\r
1352\r
1353 // Check filtering status for this packet\r
1354 if (RxFifoStatus & RXSTATUS_FILT_FAIL) {\r
1355 DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));\r
1356 // fast forward?\r
1357 }\r
1358\r
1359 // Check if we got a broadcast frame\r
1360 if (RxFifoStatus & RXSTATUS_BCF) {\r
1361 LanDriver->Stats.RxBroadcastFrames += 1;\r
1362 }\r
1363\r
1364 // Check if we got a multicast frame\r
1365 if (RxFifoStatus & RXSTATUS_MCF) {\r
1366 LanDriver->Stats.RxMulticastFrames += 1;\r
1367 }\r
1368\r
1369 // Check if we got a unicast frame\r
1370 if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {\r
1371 LanDriver->Stats.RxUnicastFrames += 1;\r
1372 }\r
1373\r
1374 // Get the received packet length\r
1375 PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);\r
1376 LanDriver->Stats.RxTotalBytes += (PLength - 4);\r
1377\r
1378 // Check buffer size\r
1379 if (*BuffSize < PLength) {\r
1380 *BuffSize = PLength;\r
1381 return EFI_BUFFER_TOO_SMALL;\r
1382 }\r
1383\r
1384 // If padding is applied, read more DWORDs\r
1385 if (PLength % 4) {\r
1386 Padding = 4 - (PLength % 4);\r
1387 ReadLimit = (PLength + Padding)/4;\r
1388 } else {\r
1389 ReadLimit = PLength/4;\r
1390 Padding = 0;\r
1391 }\r
1392\r
1393 // Set the amount of data to be transfered out of FIFO for THIS packet\r
1394 // This can be used to trigger an interrupt, and status can be checked\r
1395 RxCfgValue = MmioRead32 (LAN9118_RX_CFG);\r
1396 RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);\r
1397 RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);\r
1398\r
1399 // Set end alignment to 4-bytes\r
1400 RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);\r
1401 MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);\r
1402\r
1403 // Update buffer size\r
1404 *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as\r
1405 // 4 bytes longer than packet actually is, unless\r
1406 // packet is < 64 bytes\r
1407\r
1408 if (HdrSize != NULL)\r
1409 *HdrSize = Snp->Mode->MediaHeaderSize;\r
1410\r
1411 // Format the pointer\r
1412 RawData = (UINT32*)Data;\r
1413\r
1414 // Read Rx Packet\r
1415 for (Count = 0; Count < ReadLimit; Count++) {\r
1416 RawData[Count] = MmioRead32 (LAN9118_RX_DATA);\r
1417 }\r
1418\r
1419 // Check for Rx errors (worst possible error)\r
1420 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {\r
1421 DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));\r
1422\r
1423 // Initiate a software reset\r
42589b9a
OM
1424 Status = SoftReset (0, Snp);\r
1425 if (EFI_ERROR (Status)) {\r
46f2c53b
OM
1426 DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));\r
1427 return EFI_DEVICE_ERROR;\r
1428 }\r
1429\r
1430 // Acknowledge the RXE\r
1431 MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);\r
1432 gBS->Stall (LAN9118_STALL);\r
1433\r
1434 // Restart the rx (and do not clear FIFO)\r
1435 StartRx (0, Snp);\r
1436\r
1437 // Say that command could not be sent\r
1438 return EFI_DEVICE_ERROR;\r
1439 }\r
1440\r
1441 // Get the destination address\r
1442 if (DstAddr != NULL) {\r
1443 Dst.Addr[0] = (RawData[0] & 0xFF);\r
1444 Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;\r
1445 Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;\r
1446 Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;\r
1447 Dst.Addr[4] = (RawData[1] & 0xFF);\r
1448 Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;\r
1449 CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);\r
1450 }\r
1451\r
1452 // Get the source address\r
1453 if (SrcAddr != NULL) {\r
1454 Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;\r
1455 Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;\r
1456 Src.Addr[2] = (RawData[2] & 0xFF);\r
1457 Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;\r
1458 Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;\r
1459 Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;\r
1460 CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN);\r
1461 }\r
1462\r
1463 // Get the protocol\r
1464 if (Protocol != NULL) {\r
1465 *Protocol = NTOHS (RawData[3] & 0xFFFF);\r
1466 }\r
1467\r
1468#if defined(EVAL_PERFORMANCE)\r
1469 UINT64 EndClock = GetPerformanceCounter ();\r
1470 DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));\r
1471#endif\r
1472\r
1473 LanDriver->Stats.RxGoodFrames += 1;\r
1474\r
1475 return EFI_SUCCESS;\r
1476}\r