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