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