Home | History | Annotate | Download | only in Lan9118Dxe
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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