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