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