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