Bladeren bron

Platform/ARM/VExpressPkg: incorporate Lan9118 driver

Incorporate the Lan91x driver from EmbeddedPkg, which is only used
on obsolete ARM development platforms and does not follow the UEFI
driver model. This will allow us to drop if from the core EDK2
repository.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
Ard Biesheuvel 4 jaren geleden
bovenliggende
commit
67ad191c58

+ 4 - 4
Platform/ARM/JunoPkg/ArmJuno.dsc

@@ -150,9 +150,9 @@
 !endif
 
   # LAN9118 Ethernet Driver
-  gEmbeddedTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x18000000
-  gEmbeddedTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x1215161822242628
-  gEmbeddedTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|40000
+  gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x18000000
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x1215161822242628
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|40000
 
   #
   # ARM Generic Interrupt Controller
@@ -324,7 +324,7 @@
   #
   # Networking stack
   #
-  EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
+  Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
 !if 0
   OptionRomPkg/MarvellYukonDxe/MarvellYukonDxe.inf
 !endif

+ 1 - 1
Platform/ARM/JunoPkg/ArmJuno.fdf

@@ -196,7 +196,7 @@ FvNameGuid         = B73FE497-B92E-416e-8326-45AD0D270092
   #
 !include Platform/ARM/VExpressPkg/ArmVExpress-networking.fdf.inc
 
-  INF EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
+  INF Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
 !if 0
   INF OptionRomPkg/MarvellYukonDxe/MarvellYukonDxe.inf
 !endif

+ 3 - 3
Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc

@@ -160,8 +160,8 @@
   gEmbeddedTokenSpaceGuid.PcdIsp1761BaseAddress|0x1B000000
 
   # Ethernet (SMSC LAN9118)
-  gEmbeddedTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000
-  gEmbeddedTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|400000
+  gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|400000
 
   #
   # Define the device path to the FDT for the platform
@@ -252,7 +252,7 @@
   Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
 
   # SMSC LAN 9118
-  EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
+  Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
 
   #
   # FAT filesystem + GPT/MBR partitioning

+ 1 - 1
Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf

@@ -143,7 +143,7 @@ FvNameGuid         = 73dcb643-3862-4904-9076-a94af1890243
   #
 !include Platform/ARM/VExpressPkg/ArmVExpress-networking.fdf.inc
 
-  INF EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
+  INF Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
 
   #
   # UEFI application

+ 8 - 0
Platform/ARM/VExpressPkg/ArmVExpressPkg.dec

@@ -59,3 +59,11 @@
 
   # LAN91x Ethernet Driver PCDs
   gArmVExpressTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x0|UINT32|0x0000000B
+
+  # LAN9118 Ethernet Driver PCDs
+  gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x00000025
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x0|UINT64|0x00000026
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|4000|UINT32|0x00000027
+  # The default feature mask below disables full duplex negotiation, since full
+  # duplex operation is suspected to be broken in the driver.
+  gArmVExpressTokenSpaceGuid.PcdLan9118NegotiationFeatureMask|0xFFFFFEBF|UINT32|0x00000028

+ 1539 - 0
Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c

@@ -0,0 +1,1539 @@
+/** @file
+*
+*  WARNING:
+*  This driver fails to follow the UEFI driver model without a good
+*  reason, and only remains in the tree because it is still used by
+*  a small number of platforms. It will be removed when no longer used.
+*  New platforms should not use it, and no one should use this as
+*  reference code for developing new drivers.
+*
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include "Lan9118Dxe.h"
+
+typedef struct {
+  MAC_ADDR_DEVICE_PATH      Lan9118;
+  EFI_DEVICE_PATH_PROTOCOL  End;
+} LAN9118_DEVICE_PATH;
+
+LAN9118_DEVICE_PATH Lan9118PathTemplate =  {
+  {
+    {
+      MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,
+      { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) }
+    },
+    { { 0 } },
+    0
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }
+  }
+};
+
+/*
+**  Entry point for the LAN9118 driver
+**
+*/
+EFI_STATUS
+EFIAPI
+Lan9118DxeEntry (
+  IN EFI_HANDLE Handle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS                   Status;
+  LAN9118_DRIVER              *LanDriver;
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+  EFI_SIMPLE_NETWORK_MODE     *SnpMode;
+  LAN9118_DEVICE_PATH         *Lan9118Path;
+  EFI_HANDLE                   ControllerHandle;
+
+  // The PcdLan9118DxeBaseAddress PCD must be defined
+  ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress) != 0);
+
+  // Allocate Resources
+  LanDriver = AllocateZeroPool (sizeof (LAN9118_DRIVER));
+  if (LanDriver == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool (sizeof (LAN9118_DEVICE_PATH), &Lan9118PathTemplate);
+  if (Lan9118Path == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Initialize pointers
+  Snp = &(LanDriver->Snp);
+  SnpMode = &(LanDriver->SnpMode);
+  Snp->Mode = SnpMode;
+
+  // Set the signature of the LAN Driver structure
+  LanDriver->Signature = LAN9118_SIGNATURE;
+
+  // Assign fields and func pointers
+  Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+  Snp->WaitForPacket = NULL;
+  Snp->Initialize = SnpInitialize;
+  Snp->Start = SnpStart;
+  Snp->Stop = SnpStop;
+  Snp->Reset = SnpReset;
+  Snp->Shutdown = SnpShutdown;
+  Snp->ReceiveFilters = SnpReceiveFilters;
+  Snp->StationAddress = SnpStationAddress;
+  Snp->Statistics = SnpStatistics;
+  Snp->MCastIpToMac = SnpMcastIptoMac;
+  Snp->NvData = SnpNvData;
+  Snp->GetStatus = SnpGetStatus;
+  Snp->Transmit = SnpTransmit;
+  Snp->Receive = SnpReceive;
+
+  // Start completing simple network mode structure
+  SnpMode->State = EfiSimpleNetworkStopped;
+  SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes
+  SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Not sure of this
+  SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes)
+  SnpMode->NvRamSize = 0;           // No NVRAM with this device
+  SnpMode->NvRamAccessSize = 0; // No NVRAM with this device
+
+  //
+  // Claim that all receive filter settings are supported, though the MULTICAST mode
+  // is not completely supported. The LAN9118 Ethernet controller is only able to
+  // do a "hash filtering" and not a perfect filtering on multicast addresses. The
+  // controller does not filter the multicast addresses directly but a hash value
+  // of them. The hash value of a multicast address is derived from its CRC and
+  // ranges from 0 to 63 included.
+  // We claim that the perfect MULTICAST filtering mode is supported because
+  // we do not want the user to switch directly to the PROMISCOUS_MULTICAST mode
+  // and thus not being able to take advantage of the hash filtering.
+  //
+  SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST              |
+                               EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST            |
+                               EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST            |
+                               EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS          |
+                               EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+  // We do not intend to receive anything for the time being.
+  SnpMode->ReceiveFilterSetting = 0;
+
+  // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses
+  SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
+  SnpMode->MCastFilterCount = 0;
+  ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));
+
+  // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)
+  SnpMode->IfType = NET_IFTYPE_ETHERNET;
+
+  // Mac address is changeable as it is loaded from erasable memory
+  SnpMode->MacAddressChangeable = TRUE;
+
+  // Can only transmit one packet at a time
+  SnpMode->MultipleTxSupported = FALSE;
+
+  // MediaPresent checks for cable connection and partner link
+  SnpMode->MediaPresentSupported = TRUE;
+  SnpMode->MediaPresent = FALSE;
+
+  // Set broadcast address
+  SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
+
+  // Power up the device so we can find the MAC address
+  Status = Lan9118Initialize (Snp);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "LAN9118: Error initialising hardware\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Assign fields for device path
+  CopyMem (&Lan9118Path->Lan9118.MacAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
+  Lan9118Path->Lan9118.IfType = Snp->Mode->IfType;
+
+  // Initialise the protocol
+  ControllerHandle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ControllerHandle,
+                  &gEfiSimpleNetworkProtocolGuid, Snp,
+                  &gEfiDevicePathProtocolGuid, Lan9118Path,
+                  NULL
+                  );
+  // Say what the status of loading the protocol structure is
+  if (EFI_ERROR(Status)) {
+    FreePool (LanDriver);
+  } else {
+    LanDriver->ControllerHandle = ControllerHandle;
+  }
+
+  return Status;
+}
+
+/*
+ *  UEFI Start() function
+ *
+ *  Parameters:
+ *
+ *  @param Snp:  A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ *
+ *  Description:
+ *
+ *    This function starts a network interface. If the network interface successfully starts, then
+ *    EFI_SUCCESS will be returned.
+ */
+EFI_STATUS
+EFIAPI
+SnpStart (
+  IN  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp
+ )
+{
+  // Check Snp instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check state
+  if ((Snp->Mode->State == EfiSimpleNetworkStarted)    ||
+      (Snp->Mode->State == EfiSimpleNetworkInitialized)  ) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  // Change state
+  Snp->Mode->State = EfiSimpleNetworkStarted;
+  return EFI_SUCCESS;
+}
+
+/*
+ *  UEFI Stop() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpStop (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+  )
+{
+  // Check Snp Instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check state of the driver
+  if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    return EFI_NOT_STARTED;
+  }
+
+  // Stop the Tx and Rx
+  StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp);
+  StopRx (0, Snp);
+
+  // Change the state
+  switch (Snp->Mode->State) {
+    case EfiSimpleNetworkStarted:
+    case EfiSimpleNetworkInitialized:
+      Snp->Mode->State = EfiSimpleNetworkStopped;
+      break;
+    default:
+      return EFI_DEVICE_ERROR;
+  }
+
+  // Put the device into a power saving mode ?
+  return EFI_SUCCESS;
+}
+
+
+// Allocated receive and transmit buffers
+STATIC UINT32 gTxBuffer = 0;
+
+/*
+ *  UEFI Initialize() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpInitialize (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        UINTN                        RxBufferSize    OPTIONAL,
+  IN        UINTN                        TxBufferSize    OPTIONAL
+  )
+{
+  EFI_STATUS Status;
+  UINT32     PmConf;
+  INT32      AllocResult;
+  UINT32     RxStatusSize;
+  UINT32     TxStatusSize;
+
+  // Initialize variables
+  // Global variables to hold tx and rx FIFO allocation
+  gTxBuffer = 0;
+
+  // Check Snp Instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // First check that driver has not already been initialized
+  if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
+    DEBUG ((EFI_D_WARN, "LAN9118 Driver already initialized\n"));
+    return EFI_SUCCESS;
+  } else
+  if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "LAN9118 Driver not started\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Initiate a PHY reset
+  Status = PhySoftReset (PHY_RESET_PMT, Snp);
+  if (EFI_ERROR (Status)) {
+    Snp->Mode->State = EfiSimpleNetworkStopped;
+    DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Initiate a software reset
+  Status = SoftReset (0, Snp);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Read the PM register
+  PmConf = Lan9118MmioRead32 (LAN9118_PMT_CTRL);
+
+  // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets
+  // MPTCTRL_ED_EN:  Allow energy detection to allow lowest power consumption mode
+  // MPTCTRL_PME_EN: Allow Power Management Events
+  PmConf = 0;
+  PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);
+
+  // Write the current configuration to the register
+  Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf);
+
+  // Configure GPIO and HW
+  Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  // Assign the transmitter buffer size (default values)
+  TxStatusSize = LAN9118_TX_STATUS_SIZE;
+  RxStatusSize = LAN9118_RX_STATUS_SIZE;
+
+  // Check that a buff size was specified
+  if (TxBufferSize > 0) {
+    if (RxBufferSize == 0) {
+      RxBufferSize = LAN9118_RX_DATA_SIZE;
+    }
+
+    AllocResult = ChangeFifoAllocation (
+                          ALLOC_USE_FIFOS,
+                          &TxBufferSize,
+                          &RxBufferSize,
+                          &TxStatusSize,
+                          &RxStatusSize,
+                          Snp
+                          );
+
+    if (AllocResult < 0) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  // Do auto-negotiation if supported
+  Status = AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_WARN, "LAN9118: Auto Negotiation failed.\n"));
+  }
+
+  // Configure flow control depending on speed capabilities
+  Status = ConfigureFlow (0, 0, 0, 0, Snp);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  // Enable the transmitter
+  Status = StartTx (START_TX_MAC | START_TX_CFG, Snp);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  // Now acknowledge all interrupts
+  Lan9118MmioWrite32 (LAN9118_INT_STS, ~0);
+
+  // Declare the driver as initialized
+  Snp->Mode->State = EfiSimpleNetworkInitialized;
+
+  return Status;
+}
+
+/*
+ *  UEFI Reset () function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpReset (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN Verification
+  )
+{
+  UINT32     PmConf;
+  UINT32     HwConf;
+  UINT32     ResetFlags;
+  EFI_STATUS Status;
+
+  PmConf = 0;
+  HwConf = 0;
+  ResetFlags = 0;
+
+  // Check Snp Instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // First check that driver has not already been initialized
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Initiate a PHY reset
+  Status = PhySoftReset (PHY_RESET_PMT, Snp);
+  if (EFI_ERROR (Status)) {
+    Snp->Mode->State = EfiSimpleNetworkStopped;
+    return EFI_NOT_STARTED;
+  }
+
+  // Initiate a software reset
+  ResetFlags |= SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT;
+
+  if (Verification) {
+    ResetFlags |= SOFT_RESET_SELF_TEST;
+  }
+
+  Status = SoftReset (ResetFlags, Snp);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Read the PM register
+  PmConf = Lan9118MmioRead32 (LAN9118_PMT_CTRL);
+
+  // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets
+  // MPTCTRL_ED_EN:  Allow energy detection to allow lowest power consumption mode
+  // MPTCTRL_PME_EN: Allow Power Management Events
+  PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);
+
+  // Write the current configuration to the register
+  Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf);
+
+  // Reactivate the LEDs
+  Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Check that a buffer size was specified in SnpInitialize
+  if (gTxBuffer != 0) {
+    HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG);        // Read the HW register
+    HwConf &= ~HW_CFG_TX_FIFO_SIZE_MASK;         // Clear buffer bits first
+    HwConf |= HW_CFG_TX_FIFO_SIZE(gTxBuffer);    // assign size chosen in SnpInitialize
+
+    Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf);        // Write the conf
+  }
+
+  // Enable the receiver and transmitter and clear their contents
+  StartRx (START_RX_CLEAR, Snp);
+  StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp);
+
+  // Now acknowledge all interrupts
+  Lan9118MmioWrite32 (LAN9118_INT_STS, ~0);
+
+  return EFI_SUCCESS;
+}
+
+/*
+ *  UEFI Shutdown () function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpShutdown (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+  )
+{
+  EFI_STATUS Status;
+
+  // Check Snp Instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // First check that driver has not already been initialized
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Initiate a PHY reset
+  Status = PhySoftReset (PHY_RESET_PMT, Snp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Initiate a software reset
+  Status = SoftReset (0, Snp);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));
+    return Status;
+  }
+
+  // Back to the started and thus not initialized state
+  Snp->Mode->State = EfiSimpleNetworkStarted;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable and/or disable the receive filters of the LAN9118
+
+  Please refer to the UEFI specification for the precedence rules among the
+  Enable, Disable and ResetMCastFilter parameters.
+
+  @param[in]  Snp               A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
+                                instance.
+  @param[in]  Enable            A bit mask of receive filters to enable.
+  @param[in]  Disable           A bit mask of receive filters to disable.
+  @param[in]  ResetMCastFilter  Set to TRUE to reset the contents of the multicast
+                                receive filters on the network interface to
+                                their default values.
+  @param[in]  MCastFilterCnt    Number of multicast HW MAC addresses in the new
+                                MCastFilter list. This value must be less than or
+                                equal to the MCastFilterCnt field of
+                                EFI_SIMPLE_NETWORK_MODE. This field is optional if
+                                ResetMCastFilter is TRUE.
+  @param[in]  MCastFilter       A pointer to a list of new multicast receive
+                                filter HW MAC addresses. This list will replace
+                                any existing multicast HW MAC address list. This
+                                field is optional if ResetMCastFilter is TRUE.
+
+  @retval  EFI_SUCCESS            The receive filters of the LAN9118 were updated.
+  @retval  EFI_NOT_STARTED        The LAN9118 has not been started.
+  @retval  EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE :
+                                  . This is NULL
+                                  . Multicast is being enabled (the
+                                    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in
+                                    Enable, it is not set in Disable, and ResetMCastFilter
+                                    is FALSE) and MCastFilterCount is zero.
+                                  . Multicast is being enabled and MCastFilterCount is
+                                    greater than Snp->Mode->MaxMCastFilterCount.
+                                  . Multicast is being enabled and MCastFilter is NULL
+                                  . Multicast is being enabled and one or more of the
+                                    addresses in the MCastFilter list are not valid
+                                    multicast MAC addresses.
+  @retval  EFI_DEVICE_ERROR       The LAN9118 has been started but not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpReceiveFilters (
+  IN  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp,
+  IN  UINT32                       Enable,
+  IN  UINT32                       Disable,
+  IN  BOOLEAN                      ResetMCastFilter,
+  IN  UINTN                        MCastFilterCnt  OPTIONAL,
+  IN  EFI_MAC_ADDRESS              *MCastFilter  OPTIONAL
+  )
+{
+  EFI_SIMPLE_NETWORK_MODE  *Mode;
+  UINT32                   MultHashTableHigh;
+  UINT32                   MultHashTableLow;
+  UINT32                   Count;
+  UINT32                   Crc;
+  UINT8                    HashValue;
+  UINT32                   MacCSRValue;
+  UINT32                   ReceiveFilterSetting;
+  EFI_MAC_ADDRESS          *Mac;
+  EFI_MAC_ADDRESS          ZeroMac;
+
+  // Check Snp Instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Mode = Snp->Mode;
+
+  // Check that driver was started and initialised
+  if (Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  if ((Enable  & (~Mode->ReceiveFilterMask)) ||
+      (Disable & (~Mode->ReceiveFilterMask))    ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check the validity of the multicast setting and compute the
+  // hash values of the multicast mac addresses to listen to.
+  //
+
+  MultHashTableHigh = 0;
+  MultHashTableLow  = 0;
+  if ((!ResetMCastFilter)                                     &&
+      ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) == 0) &&
+      ((Enable  & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0)    ) {
+    if ((MCastFilterCnt == 0)                        ||
+        (MCastFilterCnt > Mode->MaxMCastFilterCount) ||
+        (MCastFilter == NULL)                           ) {
+      return EFI_INVALID_PARAMETER;
+    }
+    //
+    // Check the validity of all multicast addresses before to change
+    // anything.
+    //
+    for (Count = 0; Count < MCastFilterCnt; Count++) {
+      if ((MCastFilter[Count].Addr[0] & 1) == 0) {
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+
+    //
+    // Go through each filter address and set appropriate bits on hash table
+    //
+    for (Count = 0; Count < MCastFilterCnt; Count++) {
+      Mac = &(MCastFilter[Count]);
+      CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS));
+
+      Crc = GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN);
+      //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired
+
+      //
+      // The most significant 6 bits of the MAC address CRC constitute the hash
+      // value of the MAC address.
+      //
+      HashValue = (Crc >> 26) & 0x3F;
+
+      // Select hashlow register if MSB is not set
+      if ((HashValue & 0x20) == 0) {
+        MultHashTableLow |= (1 << HashValue);
+      } else {
+        MultHashTableHigh |= (1 << (HashValue & 0x1F));
+      }
+    }
+    Mode->MCastFilterCount = MCastFilterCnt;
+  } else if (ResetMCastFilter) {
+    Mode->MCastFilterCount = 0;
+  } else {
+    MultHashTableLow  = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL);
+    MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH);
+  }
+
+  //
+  // Before to change anything, stop and reset the reception of
+  // packets.
+  //
+  StopRx (STOP_RX_CLEAR, Snp);
+
+  //
+  // Write the mask of the selected hash values for the multicast filtering.
+  // The two masks are set to zero if the multicast filtering is not enabled.
+  //
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow);
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh);
+
+  ReceiveFilterSetting = (Mode->ReceiveFilterSetting | Enable) & (~Disable);
+
+  //
+  // Read MAC controller
+  //
+  MacCSRValue  = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
+  MacCSRValue &= ~(MACCR_HPFILT | MACCR_BCAST | MACCR_PRMS | MACCR_MCPAS);
+
+  if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {
+    Lan9118SetMacAddress (&Mode->CurrentAddress, Snp);
+    DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n"));
+  } else {
+    //
+    // The Unicast packets do not have to be listen to, set the MAC
+    // address of the LAN9118 to be the "not configured" all zeroes
+    // ethernet MAC address.
+    //
+    ZeroMem (&ZeroMac, NET_ETHER_ADDR_LEN);
+    Lan9118SetMacAddress (&ZeroMac, Snp);
+  }
+
+  if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {
+    MacCSRValue |= MACCR_HPFILT;
+    DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n"));
+  }
+
+  if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {
+    MacCSRValue |= MACCR_MCPAS;
+    DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n"));
+  }
+
+  if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) == 0) {
+    MacCSRValue |= MACCR_BCAST;
+  } else {
+    DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n"));
+  }
+
+  if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {
+    MacCSRValue |= MACCR_PRMS;
+    DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n"));
+  }
+
+  //
+  // Write the options to the MAC_CSR
+  //
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue);
+
+  //
+  // If we have to retrieve something, start packet reception.
+  //
+  Mode->ReceiveFilterSetting = ReceiveFilterSetting;
+  if (ReceiveFilterSetting != 0) {
+    StartRx (0, Snp);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Modify of reset the current station address
+
+  @param[in]  Snp               A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
+                                instance.
+  @param[in]  Reset             Flag used to reset the station address to the
+                                LAN9118's permanent address.
+  @param[in]  New               New station address to be used for the network interface.
+
+  @retval  EFI_SUCCESS            The LAN9118's station address was updated.
+  @retval  EFI_NOT_STARTED        The LAN9118 has not been started.
+  @retval  EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE :
+                                  . The "New" station address is invalid.
+                                  . "Reset" is FALSE and "New" is NULL.
+  @retval  EFI_DEVICE_ERROR       The LAN9118 has been started but not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpStationAddress (
+  IN  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp,
+  IN  BOOLEAN                      Reset,
+  IN  EFI_MAC_ADDRESS              *New
+)
+{
+  UINT32 Count;
+  UINT8  PermAddr[NET_ETHER_ADDR_LEN];
+
+  DEBUG ((DEBUG_NET, "SnpStationAddress()\n"));
+
+  // Check Snp instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check that driver was started and initialised
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Get the Permanent MAC address if need reset
+  if (Reset) {
+    // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0
+    if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) {
+      for (Count = 0; Count < NET_ETHER_ADDR_LEN; Count++) {
+        PermAddr[Count] = IndirectEEPROMRead32 (Count + 1);
+      }
+      New = (EFI_MAC_ADDRESS *) PermAddr;
+      Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp);
+    } else {
+      DEBUG ((EFI_D_ERROR, "LAN9118: Warning: No valid MAC address in EEPROM, using fallback\n"));
+      New = (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress));
+    }
+  } else {
+    // Otherwise use the specified new MAC address
+    if (New == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    //
+    // If it is a multicast address, it is not valid.
+    //
+    if (New->Addr[0] & 0x01) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  CopyMem (&Snp->Mode->CurrentAddress, New, NET_ETHER_ADDR_LEN);
+
+  //
+  // If packet reception is currently activated, stop and reset it,
+  // set the new ethernet address and restart the packet reception.
+  // Otherwise, nothing to do, the MAC address will be updated in
+  // SnpReceiveFilters() when the UNICAST packet reception will be
+  // activated.
+  //
+  if (Snp->Mode->ReceiveFilterSetting  != 0) {
+    StopRx (STOP_RX_CLEAR, Snp);
+    Lan9118SetMacAddress (New, Snp);
+    StartRx (0, Snp);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/*
+ *  UEFI Statistics() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpStatistics (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN Reset,
+  IN  OUT   UINTN *StatSize,
+      OUT   EFI_NETWORK_STATISTICS *Statistics
+  )
+{
+  LAN9118_DRIVER  *LanDriver;
+  EFI_STATUS      Status;
+
+  LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
+
+  DEBUG ((DEBUG_NET, "SnpStatistics()\n"));
+
+  // Check Snp instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check that driver was started and initialised
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  //
+  // Do a reset if required. It is not clearly stated in the UEFI specification
+  // whether the reset has to be done before to copy the statistics in "Statictics"
+  // or after. It is a bit strange to do it before but that is what is expected by
+  // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89,
+  // 0x54,0x7e,0x4f,0xad,0x4f,0x24".
+  //
+  if (Reset) {
+    ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));
+  }
+
+  Status = EFI_SUCCESS;
+  if (StatSize == NULL) {
+    if (Statistics != NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+  } else {
+    if (Statistics == NULL) {
+      Status = EFI_BUFFER_TOO_SMALL;
+    } else {
+      // Fill in the statistics
+      CopyMem (
+        Statistics, &LanDriver->Stats,
+        MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS))
+        );
+      if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) {
+        Status = EFI_BUFFER_TOO_SMALL;
+      }
+    }
+    *StatSize = sizeof (EFI_NETWORK_STATISTICS);
+  }
+
+  return Status;
+}
+
+/*
+ *  UEFI MCastIPtoMAC() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpMcastIptoMac (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN IsIpv6,
+  IN        EFI_IP_ADDRESS *Ip,
+      OUT   EFI_MAC_ADDRESS *McastMac
+  )
+{
+  DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n"));
+
+  // Check Snp instance
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check that driver was started and initialised
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Check parameters
+  if ((McastMac == NULL) || (Ip == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Make sure MAC address is empty
+  ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));
+
+  // If we need ipv4 address
+  if (!IsIpv6) {
+    // Most significant 25 bits of a multicast HW address are set.
+    // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)
+    McastMac->Addr[0] = 0x01;
+    McastMac->Addr[1] = 0x00;
+    McastMac->Addr[2] = 0x5E;
+
+    // Lower 23 bits from ipv4 address
+    McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)
+    McastMac->Addr[4] = Ip->v4.Addr[2];
+    McastMac->Addr[5] = Ip->v4.Addr[3];
+  } else {
+    // Most significant 16 bits of multicast v6 HW address are set
+    // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)
+    McastMac->Addr[0] = 0x33;
+    McastMac->Addr[1] = 0x33;
+
+    // lower four octets are taken from ipv6 address
+    McastMac->Addr[2] = Ip->v6.Addr[8];
+    McastMac->Addr[3] = Ip->v6.Addr[9];
+    McastMac->Addr[4] = Ip->v6.Addr[10];
+    McastMac->Addr[5] = Ip->v6.Addr[11];
+  }
+
+  return EFI_SUCCESS;
+}
+
+/*
+ *  UEFI NvData() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpNvData (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* pobj,
+  IN        BOOLEAN read_write,
+  IN        UINTN offset,
+  IN        UINTN buff_size,
+  IN  OUT   VOID *data
+  )
+{
+  DEBUG ((DEBUG_NET, "SnpNvData()\n"));
+
+  return EFI_UNSUPPORTED;
+}
+
+
+/*
+ *  UEFI GetStatus () function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpGetStatus (
+  IN   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp,
+  OUT  UINT32                       *IrqStat  OPTIONAL,
+  OUT  VOID                         **TxBuff  OPTIONAL
+  )
+{
+  UINT32          FifoInt;
+  EFI_STATUS      Status;
+  UINTN           NumTxStatusEntries;
+  UINT32          TxStatus;
+  UINT16          PacketTag;
+  UINT32          Interrupts;
+  LAN9118_DRIVER *LanDriver;
+
+  LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
+
+  // Check preliminaries
+  if (Snp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check that driver was started and initialised
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Check and acknowledge TX Status interrupt (this will happen if the
+  // consumer of SNP does not call GetStatus.)
+  // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we
+  // should check for it and dump the TX Status FIFO.
+  FifoInt = Lan9118MmioRead32 (LAN9118_FIFO_INT);
+
+  // Clear the TX Status FIFO Overflow
+  if ((FifoInt & INSTS_TXSO) == 0) {
+    FifoInt |= INSTS_TXSO;
+    Lan9118MmioWrite32 (LAN9118_FIFO_INT, FifoInt);
+  }
+
+  // Read interrupt status if IrqStat is not NULL
+  if (IrqStat != NULL) {
+    *IrqStat = 0;
+
+    // Check for receive interrupt
+    if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO
+      *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+      Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);
+    }
+
+    // Check for transmit interrupt
+    if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {
+      *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+      Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);
+    }
+
+    // Check for software interrupt
+    if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) {
+      *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;
+      Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT);
+    }
+  }
+
+  // Check Status of transmitted packets
+  // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)
+
+  NumTxStatusEntries = Lan9118MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;
+  if (NumTxStatusEntries > 0) {
+    TxStatus = Lan9118MmioRead32 (LAN9118_TX_STATUS);
+    PacketTag = TxStatus >> 16;
+    TxStatus = TxStatus & 0xFFFF;
+    if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) {
+      DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));
+      if (TxStatus & TXSTATUS_NO_CA) {
+        DEBUG ((EFI_D_ERROR, "- No carrier\n"));
+      }
+      if (TxStatus & TXSTATUS_DEF) {
+        DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));
+      }
+      if (TxStatus & TXSTATUS_EDEF) {
+        DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));
+      }
+      if (TxStatus & TXSTATUS_ECOLL) {
+        DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));
+      }
+      if (TxStatus & TXSTATUS_LCOLL) {
+        DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));
+      }
+      if (TxStatus & TXSTATUS_LOST_CA) {
+        DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));
+      }
+      return EFI_DEVICE_ERROR;
+    } else if (TxBuff != NULL) {
+      LanDriver->Stats.TxTotalFrames += 1;
+      *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];
+    }
+  } else if (TxBuff != NULL) {
+    *TxBuff = NULL;
+  }
+
+  // Check for a TX Error interrupt
+  Interrupts = Lan9118MmioRead32 (LAN9118_INT_STS);
+  if (Interrupts & INSTS_TXE) {
+    DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));
+
+    // Software reset, the TXE interrupt is cleared by the reset.
+    Status = SoftReset (0, Snp);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));
+      return EFI_DEVICE_ERROR;
+    }
+
+    // Reactivate the LEDs
+    Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Restart the transmitter and if necessary the receiver.
+    // Do not ask for FIFO reset as it has already been done
+    // by SoftReset().
+    //
+    StartTx (START_TX_MAC | START_TX_CFG, Snp);
+    if (Snp->Mode->ReceiveFilterSetting != 0) {
+      StartRx (0, Snp);
+    }
+  }
+
+  // Update the media status
+  Status = CheckLinkStatus (0, Snp);
+  if (EFI_ERROR(Status)) {
+    Snp->Mode->MediaPresent = FALSE;
+  } else {
+    Snp->Mode->MediaPresent = TRUE;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/*
+ *  UEFI Transmit() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpTransmit (
+  IN  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp,
+  IN  UINTN                        HdrSize,
+  IN  UINTN                        BuffSize,
+  IN  VOID*                        Data,
+  IN  EFI_MAC_ADDRESS              *SrcAddr  OPTIONAL,
+  IN  EFI_MAC_ADDRESS              *DstAddr  OPTIONAL,
+  IN  UINT16                       *Protocol OPTIONAL
+  )
+{
+  LAN9118_DRIVER *LanDriver;
+  UINT32 TxFreeSpace;
+  UINT32 TxStatusSpace;
+  INT32 Count;
+  UINT32 CommandA;
+  UINT32 CommandB;
+  UINT16 LocalProtocol;
+  UINT32 *LocalData;
+  UINT16 PacketTag;
+
+#if defined(EVAL_PERFORMANCE)
+  UINT64 Perf;
+  UINT64 StartClock;
+  UINT64 EndClock;
+
+  Perf = GetPerformanceCounterProperties (NULL, NULL);
+  StartClock = GetPerformanceCounter ();
+#endif
+
+  LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
+
+  // Check preliminaries
+  if ((Snp == NULL) || (Data == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check that driver was started and initialised
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  // Ensure header is correct size if non-zero
+  if (HdrSize) {
+    if (HdrSize != Snp->Mode->MediaHeaderSize) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if ((DstAddr == NULL) || (Protocol == NULL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Check validity of BufferSize
+  //
+  if (BuffSize < Snp->Mode->MediaHeaderSize) {
+      return EFI_BUFFER_TOO_SMALL;
+  }
+
+  // Before transmitting check the link status
+  /*if (CheckLinkStatus (0, Snp) < 0) {
+    return EFI_NOT_READY;
+  }*/
+
+  // Get DATA FIFO free space in bytes
+  TxFreeSpace = TxDataFreeSpace (0, Snp);
+  if (TxFreeSpace < BuffSize) {
+    return EFI_NOT_READY;
+  }
+
+  // Get STATUS FIFO used space in bytes
+  TxStatusSpace = TxStatusUsedSpace (0, Snp);
+  if (TxStatusSpace > 500) {
+    return EFI_NOT_READY;
+  }
+
+  // If DstAddr is not provided, get it from Buffer (we trust that the caller
+  // has provided a well-formed frame).
+  if (DstAddr == NULL) {
+    DstAddr = (EFI_MAC_ADDRESS *) Data;
+  }
+
+  // Check for the nature of the frame
+  if ((DstAddr->Addr[0] & 0x1) == 1) {
+    LanDriver->Stats.TxMulticastFrames += 1;
+  } else {
+    LanDriver->Stats.TxUnicastFrames += 1;
+  }
+
+  // Check if broadcast
+  if (DstAddr->Addr[0] == 0xFF) {
+    LanDriver->Stats.TxBroadcastFrames += 1;
+  }
+
+  PacketTag = LanDriver->NextPacketTag;
+  LanDriver->NextPacketTag++;
+
+  if (HdrSize) {
+
+    // Format pointer
+    LocalData = (UINT32*) Data;
+    LocalProtocol = *Protocol;
+
+    // Create first buffer to pass to controller (for the header)
+    CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);
+    CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);
+
+    // Write the commands first
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA);
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB);
+
+    // Write the destination address
+    Lan9118MmioWrite32 (LAN9118_TX_DATA,
+               (DstAddr->Addr[0]) |
+               (DstAddr->Addr[1] << 8) |
+               (DstAddr->Addr[2] << 16) |
+               (DstAddr->Addr[3] << 24)
+               );
+
+    Lan9118MmioWrite32 (LAN9118_TX_DATA,
+               (DstAddr->Addr[4]) |
+               (DstAddr->Addr[5] << 8) |
+               (SrcAddr->Addr[0] << 16) | // Write the Source Address
+               (SrcAddr->Addr[1] << 24)
+               );
+
+    Lan9118MmioWrite32 (LAN9118_TX_DATA,
+               (SrcAddr->Addr[2]) |
+               (SrcAddr->Addr[3] << 8) |
+               (SrcAddr->Addr[4] << 16) |
+               (SrcAddr->Addr[5] << 24)
+               );
+
+    // Write the Protocol
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));
+
+    // Next buffer is the payload
+    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
+
+    // Write the commands
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA);
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB);
+
+    // Write the payload
+    for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {
+      Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);
+    }
+  } else {
+    // Format pointer
+    LocalData = (UINT32*) Data;
+
+    // Create a buffer to pass to controller
+    CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;
+    CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);
+
+    // Write the commands first
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA);
+    Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB);
+
+    // Write all the data
+    for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {
+      Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);
+    }
+  }
+
+  // Save the address of the submitted packet so we can notify the consumer that
+  // it has been sent in GetStatus. When the packet tag appears in the Tx Status
+  // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.
+  LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;
+
+#if defined(EVAL_PERFORMANCE)
+  EndClock = GetPerformanceCounter ();
+  DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));
+#endif
+
+  LanDriver->Stats.TxGoodFrames += 1;
+
+  return EFI_SUCCESS;
+}
+
+
+/*
+ *  UEFI Receive() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpReceive (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+      OUT   UINTN *HdrSize                OPTIONAL,
+  IN  OUT   UINTN *BuffSize,
+      OUT   VOID *Data,
+      OUT   EFI_MAC_ADDRESS *SrcAddr      OPTIONAL,
+      OUT   EFI_MAC_ADDRESS *DstAddr      OPTIONAL,
+      OUT   UINT16 *Protocol              OPTIONAL
+  )
+{
+  LAN9118_DRIVER  *LanDriver;
+  UINT32          IntSts;
+  UINT32          RxFifoStatus;
+  UINT32          NumPackets;
+  UINT32          RxCfgValue;
+  UINT32          PLength; // Packet length
+  UINT32          ReadLimit;
+  UINT32          Count;
+  UINT32          Padding;
+  UINT32          *RawData;
+  EFI_MAC_ADDRESS Dst;
+  EFI_MAC_ADDRESS Src;
+  UINTN           DroppedFrames;
+  EFI_STATUS      Status;
+
+  LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
+
+#if defined(EVAL_PERFORMANCE)
+  UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);
+  UINT64 StartClock = GetPerformanceCounter ();
+#endif
+
+  // Check preliminaries
+  if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check that driver was started and initialised
+  if (Snp->Mode->State == EfiSimpleNetworkStarted) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
+    return EFI_DEVICE_ERROR;
+  } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
+    DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
+    return EFI_NOT_STARTED;
+  }
+
+  //
+  // If the receiver raised the RXE error bit, check if the receiver status
+  // FIFO is full and if not just acknowledge the error. The two other
+  // conditions to get a RXE error are :
+  // . the RX data FIFO is read whereas being empty.
+  // . the RX status FIFO is read whereas being empty.
+  // The RX data and status FIFO are read by this driver only in the following
+  // code of this function. After the readings, the RXE error bit is checked
+  // and if raised, the controller is reset. Thus, at this point, we consider
+  // that the only valid reason to get an RXE error is the receiver status
+  // FIFO being full. And if this is not the case, we consider that this is
+  // a spurious error and we just get rid of it. We experienced such 'spurious'
+  // errors when running the driver on an A57 on Juno. No valid reason to
+  // explain those errors has been found so far and everything seems to
+  // work perfectly when they are just ignored.
+  //
+  IntSts = Lan9118MmioRead32 (LAN9118_INT_STS);
+  if ((IntSts & INSTS_RXE) && (!(IntSts & INSTS_RSFF))) {
+    Lan9118MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);
+  }
+
+  // Count dropped frames
+  DroppedFrames = Lan9118MmioRead32 (LAN9118_RX_DROP);
+  LanDriver->Stats.RxDroppedFrames += DroppedFrames;
+
+  NumPackets = RxStatusUsedSpace (0, Snp) / 4;
+  if (!NumPackets) {
+    return EFI_NOT_READY;
+  }
+
+  // Read Rx Status (only if not empty)
+  RxFifoStatus = Lan9118MmioRead32 (LAN9118_RX_STATUS);
+  LanDriver->Stats.RxTotalFrames += 1;
+
+  // First check for errors
+  if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||
+      (RxFifoStatus & RXSTATUS_RXW_TO) ||
+      (RxFifoStatus & RXSTATUS_FTL) ||
+      (RxFifoStatus & RXSTATUS_LCOLL) ||
+      (RxFifoStatus & RXSTATUS_LE) ||
+      (RxFifoStatus & RXSTATUS_DB))
+  {
+    DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Check if we got a CRC error
+  if (RxFifoStatus & RXSTATUS_CRC_ERROR) {
+    DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));
+    LanDriver->Stats.RxCrcErrorFrames += 1;
+    LanDriver->Stats.RxDroppedFrames += 1;
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Check if we got a runt frame
+  if (RxFifoStatus & RXSTATUS_RUNT) {
+    DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));
+    LanDriver->Stats.RxUndersizeFrames += 1;
+    LanDriver->Stats.RxDroppedFrames += 1;
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Check filtering status for this packet
+  if (RxFifoStatus & RXSTATUS_FILT_FAIL) {
+    DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));
+    // fast forward?
+  }
+
+  // Check if we got a broadcast frame
+  if (RxFifoStatus & RXSTATUS_BCF) {
+    LanDriver->Stats.RxBroadcastFrames += 1;
+  }
+
+  // Check if we got a multicast frame
+  if (RxFifoStatus & RXSTATUS_MCF) {
+    LanDriver->Stats.RxMulticastFrames += 1;
+  }
+
+  // Check if we got a unicast frame
+  if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {
+    LanDriver->Stats.RxUnicastFrames += 1;
+  }
+
+  // Get the received packet length
+  PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);
+  LanDriver->Stats.RxTotalBytes += (PLength - 4);
+
+  // If padding is applied, read more DWORDs
+  if (PLength % 4) {
+    Padding = 4 - (PLength % 4);
+    ReadLimit = (PLength + Padding)/4;
+  } else {
+    ReadLimit = PLength/4;
+    Padding = 0;
+  }
+
+  // Check buffer size
+  if (*BuffSize < (PLength + Padding)) {
+    *BuffSize = PLength + Padding;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  // Set the amount of data to be transferred out of FIFO for THIS packet
+  // This can be used to trigger an interrupt, and status can be checked
+  RxCfgValue = Lan9118MmioRead32 (LAN9118_RX_CFG);
+  RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);
+  RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);
+
+  // Set end alignment to 4-bytes
+  RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);
+  Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);
+
+  // Update buffer size
+  *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as
+                       // 4 bytes longer than packet actually is, unless
+                       // packet is < 64 bytes
+
+  if (HdrSize != NULL)
+    *HdrSize = Snp->Mode->MediaHeaderSize;
+
+  // Format the pointer
+  RawData = (UINT32*)Data;
+
+  // Read Rx Packet
+  for (Count = 0; Count < ReadLimit; Count++) {
+    RawData[Count] = Lan9118MmioRead32 (LAN9118_RX_DATA);
+  }
+
+  // Get the destination address
+  if (DstAddr != NULL) {
+    Dst.Addr[0] = (RawData[0] & 0xFF);
+    Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;
+    Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;
+    Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;
+    Dst.Addr[4] = (RawData[1] & 0xFF);
+    Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;
+    CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);
+  }
+
+  // Get the source address
+  if (SrcAddr != NULL) {
+    Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;
+    Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;
+    Src.Addr[2] = (RawData[2] & 0xFF);
+    Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;
+    Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;
+    Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;
+    CopyMem (SrcAddr, &Src, NET_ETHER_ADDR_LEN);
+  }
+
+  // Get the protocol
+  if (Protocol != NULL) {
+    *Protocol = NTOHS (RawData[3] & 0xFFFF);
+  }
+
+  // Check for Rx errors (worst possible error)
+  if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {
+    DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));
+
+    // Software reset, the RXE interrupt is cleared by the reset.
+    Status = SoftReset (0, Snp);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));
+      return EFI_DEVICE_ERROR;
+    }
+
+    // Reactivate the LEDs
+    Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Restart the receiver and the transmitter without resetting the FIFOs
+    // as it has been done by SoftReset().
+    //
+    StartRx (0, Snp);
+    StartTx (START_TX_MAC | START_TX_CFG, Snp);
+
+    // Say that command could not be sent
+    return EFI_DEVICE_ERROR;
+  }
+
+#if defined(EVAL_PERFORMANCE)
+  UINT64 EndClock = GetPerformanceCounter ();
+  DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));
+#endif
+
+  LanDriver->Stats.RxGoodFrames += 1;
+
+  return EFI_SUCCESS;
+}

+ 304 - 0
Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h

@@ -0,0 +1,304 @@
+/** @file
+*
+*  WARNING:
+*  This driver fails to follow the UEFI driver model without a good
+*  reason, and only remains in the tree because it is still used by
+*  a small number of platforms. It will be removed when no longer used.
+*  New platforms should not use it, and no one should use this as
+*  reference code for developing new drivers.
+*
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef __LAN9118_DXE_H__
+#define __LAN9118_DXE_H__
+
+#include <Uefi.h>
+#include <Uefi/UefiSpec.h>
+#include <Base.h>
+
+// Protocols used by this driver
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/PxeBaseCode.h>
+#include <Protocol/DevicePath.h>
+
+// Libraries used by this driver
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/NetLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "Lan9118DxeUtil.h"
+#include "Lan9118DxeHw.h"
+
+#define LAN9118_STALL     2
+
+#define LAN9118_DEFAULT_MAC_ADDRL     0x00F70200
+#define LAN9118_DEFAULT_MAC_ADDRH     0x00009040
+
+#define LAN9118_TX_DATA_SIZE          4608
+#define LAN9118_TX_STATUS_SIZE        512
+#define LAN9118_RX_DATA_SIZE          10560
+#define LAN9118_RX_STATUS_SIZE        704
+
+#define LAN9118_TX_RING_NUM_ENTRIES 32
+
+/*------------------------------------------------------------------------------
+  LAN9118 Information Structure
+------------------------------------------------------------------------------*/
+
+typedef struct {
+  // Driver signature
+  UINT32            Signature;
+  EFI_HANDLE        ControllerHandle;
+
+  // EFI SNP protocol instances
+  EFI_SIMPLE_NETWORK_PROTOCOL Snp;
+  EFI_SIMPLE_NETWORK_MODE SnpMode;
+
+  // EFI Snp statistics instance
+  EFI_NETWORK_STATISTICS Stats;
+
+  // Saved transmitted buffers so we can notify consumers when packets have been sent.
+  UINT16  NextPacketTag;
+  VOID    *TxRing[LAN9118_TX_RING_NUM_ENTRIES];
+} LAN9118_DRIVER;
+
+#define LAN9118_SIGNATURE                       SIGNATURE_32('l', 'a', 'n', '9')
+#define INSTANCE_FROM_SNP_THIS(a)               CR(a, LAN9118_DRIVER, Snp, LAN9118_SIGNATURE)
+
+
+/*---------------------------------------------------------------------------------------------------------------------
+
+  UEFI-Compliant functions for EFI_SIMPLE_NETWORK_PROTOCOL
+
+  Refer to the Simple Network Protocol section (21.1) in the UEFI 2.3.1 Specification for related definitions
+
+---------------------------------------------------------------------------------------------------------------------*/
+
+
+/*
+ *  UEFI Start() function
+ *
+ *  Parameters:
+ *
+ *  @param pobj:  A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ *
+ *  Description:
+ *
+ *  This function starts a network interface. If the network interface successfully starts, then
+ *  EFI_SUCCESS will be returned.
+ */
+EFI_STATUS
+EFIAPI
+SnpStart (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+  );
+
+/*
+ *  UEFI Stop() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpStop (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+  );
+
+/*
+ *  UEFI Initialize() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpInitialize (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        UINTN rx_buff_size,
+  IN        UINTN tx_buff_size
+  );
+
+/*
+ *  UEFI Reset() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpReset (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN ext_ver
+  );
+
+/*
+ *  UEFI Shutdown() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpShutdown (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+  );
+
+/*
+ *  UEFI ReceiveFilters() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpReceiveFilters (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        UINT32 enable,
+  IN        UINT32 disable,
+  IN        BOOLEAN reset_mfilter,
+  IN        UINTN num_mfilter,
+  IN        EFI_MAC_ADDRESS *mfilter
+  );
+
+/*
+ *  UEFI StationAddress() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpStationAddress (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN reset,
+  IN        EFI_MAC_ADDRESS *new_maddr
+  );
+
+/*
+ *  UEFI Statistics() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpStatistics (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN reset,
+  IN  OUT   UINTN *stat_size,
+      OUT   EFI_NETWORK_STATISTICS *stat_table
+  );
+
+/*
+ *  UEFI MCastIPtoMAC() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpMcastIptoMac (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN use_ipv6,
+  IN        EFI_IP_ADDRESS *ip_addr,
+      OUT   EFI_MAC_ADDRESS *mac_addr
+  );
+
+/*
+ *  UEFI NvData() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpNvData (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        BOOLEAN read_write,
+  IN        UINTN offset,
+  IN        UINTN buff_size,
+  IN  OUT   VOID *data
+  );
+
+/*
+ *  UEFI GetStatus() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpGetStatus (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+      OUT   UINT32 *irq_stat  OPTIONAL,
+      OUT   VOID **tx_buff    OPTIONAL
+  );
+
+/*
+ *  UEFI Transmit() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpTransmit (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+  IN        UINTN hdr_size,
+  IN        UINTN buff_size,
+  IN        VOID *data,
+  IN        EFI_MAC_ADDRESS *src_addr   OPTIONAL,
+  IN        EFI_MAC_ADDRESS *dest_addr  OPTIONAL,
+  IN        UINT16 *protocol            OPTIONAL
+  );
+
+/*
+ *  UEFI Receive() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpReceive (
+  IN        EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+      OUT   UINTN *hdr_size               OPTIONAL,
+  IN  OUT   UINTN *buff_size,
+      OUT   VOID *data,
+      OUT   EFI_MAC_ADDRESS *src_addr     OPTIONAL,
+      OUT   EFI_MAC_ADDRESS *dest_addr    OPTIONAL,
+      OUT   UINT16 *protocol              OPTIONAL
+  );
+
+
+/*---------------------------------------------------------------------------------------------------------------------
+
+  UEFI-Compliant functions for EFI_COMPONENT_NAME2_PROTOCOL
+
+  Refer to the Component Name Protocol section (10.5) in the UEFI 2.3.1 Specification for related definitions
+
+---------------------------------------------------------------------------------------------------------------------*/
+
+/*
+ *  UEFI GetDriverName() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpGetDriverName (
+  IN        EFI_COMPONENT_NAME2_PROTOCOL *Snp,
+  IN        CHAR8 *Lang,
+      OUT   CHAR16 **DriverName
+  );
+
+/*
+ *  UEFI GetControllerName() function
+ *
+ */
+EFI_STATUS
+EFIAPI
+SnpGetControllerName (
+  IN        EFI_COMPONENT_NAME2_PROTOCOL *Cnp,
+  IN        EFI_HANDLE ControllerHandle,
+  IN        EFI_HANDLE ChildHandle            OPTIONAL,
+  IN        CHAR8 *Lang,
+      OUT   CHAR16 **ControllerName
+  );
+
+/*------------------------------------------------------------------------------
+  Utility functions
+------------------------------------------------------------------------------*/
+
+EFI_MAC_ADDRESS
+GetCurrentMacAddress (
+  VOID
+  );
+
+#endif // __LAN9118_DXE_H__

+ 58 - 0
Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf

@@ -0,0 +1,58 @@
+#/** @file
+#  INF file for the LAN9118 Network Controller Driver.
+#
+#  WARNING:
+#  This driver fails to follow the UEFI driver model without a good
+#  reason, and only remains in the tree because it is still used by
+#  a small number of platforms. It will be removed when no longer used.
+#  New platforms should not use it, and no one should use this as
+#  reference code for developing new drivers.
+#
+#  Copyright (c) 2012-2015, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010006
+  BASE_NAME                      = Lan9118Dxe
+  FILE_GUID                      = 4356b162-d0b2-11e1-8952-4437e6a60ea5
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 0.1
+  ENTRY_POINT                    = Lan9118DxeEntry
+
+[Sources.common]
+  Lan9118Dxe.c
+  Lan9118DxeUtil.c
+  Lan9118Dxe.h
+
+[Packages]
+  NetworkPkg/NetworkPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Platform/ARM/VExpressPkg/ArmVExpressPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  UefiLib
+  NetLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  IoLib
+  DevicePathLib
+
+[Protocols]
+  gEfiSimpleNetworkProtocolGuid
+  gEfiMetronomeArchProtocolGuid
+  gEfiPxeBaseCodeProtocolGuid
+  gEfiDevicePathProtocolGuid
+
+[FixedPcd]
+  gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultMacAddress
+  gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout
+  gArmVExpressTokenSpaceGuid.PcdLan9118NegotiationFeatureMask
+
+[Depex]
+  TRUE

+ 401 - 0
Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h

@@ -0,0 +1,401 @@
+/** @file
+*
+*  WARNING:
+*  This driver fails to follow the UEFI driver model without a good
+*  reason, and only remains in the tree because it is still used by
+*  a small number of platforms. It will be removed when no longer used.
+*  New platforms should not use it, and no one should use this as
+*  reference code for developing new drivers.
+*
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef __LAN9118_DXE_HW_H__
+#define __LAN9118_DXE_HW_H__
+
+/*------------------------------------------------------------------------------
+  LAN9118 SMCS Registers
+------------------------------------------------------------------------------*/
+
+// Base address as on the VE board
+#define LAN9118_BA                            ((UINT32) PcdGet32(PcdLan9118DxeBaseAddress))
+
+/* ------------- Tx and Rx Data and Status Memory Locations ------------------*/
+#define LAN9118_RX_DATA                       (0x00000000 + LAN9118_BA)
+#define LAN9118_RX_STATUS                     (0x00000040 + LAN9118_BA)
+#define LAN9118_RX_STATUS_PEEK                (0x00000044 + LAN9118_BA)
+#define LAN9118_TX_DATA                       (0x00000020 + LAN9118_BA)
+#define LAN9118_TX_STATUS                     (0x00000048 + LAN9118_BA)
+#define LAN9118_TX_STATUS_PEEK                (0x0000004C + LAN9118_BA)
+
+/* ------------- System Control and Status Registers -------------------------*/
+#define LAN9118_ID_REV                        (0x00000050 + LAN9118_BA)    // Chip ID and Revision
+#define LAN9118_IRQ_CFG                       (0x00000054 + LAN9118_BA)    // Interrupt Configuration
+#define LAN9118_INT_STS                       (0x00000058 + LAN9118_BA)    // Interrupt Status
+#define LAN9118_INT_EN                        (0x0000005C + LAN9118_BA)    // Interrupt Enable
+//#define LAN9118_RESERVED                    (0x00000060)
+#define LAN9118_BYTE_TEST                     (0x00000064 + LAN9118_BA)    // Byte Order Test
+#define LAN9118_FIFO_INT                      (0x00000068 + LAN9118_BA)    // FIFO Level Interrupts
+#define LAN9118_RX_CFG                        (0x0000006C + LAN9118_BA)    // Receive Configuration
+#define LAN9118_TX_CFG                        (0x00000070 + LAN9118_BA)    // Transmit Configuration
+#define LAN9118_HW_CFG                        (0x00000074 + LAN9118_BA)    // Hardware Configuration
+#define LAN9118_RX_DP_CTL                     (0x00000078 + LAN9118_BA)    // Receive Data-Path Configuration
+#define LAN9118_RX_FIFO_INF                   (0x0000007C + LAN9118_BA)    // Receive FIFO Information
+#define LAN9118_TX_FIFO_INF                   (0x00000080 + LAN9118_BA)    // Transmit FIFO Information
+#define LAN9118_PMT_CTRL                      (0x00000084 + LAN9118_BA)    // Power Management Control
+#define LAN9118_GPIO_CFG                      (0x00000088 + LAN9118_BA)    // General Purpose IO Configuration
+#define LAN9118_GPT_CFG                       (0x0000008C + LAN9118_BA)    // General Purpose Timer Configuration
+#define LAN9118_GPT_CNT                       (0x00000090 + LAN9118_BA)    // General Purpose Timer Current Count
+#define LAN9118_WORD_SWAP                     (0x00000098 + LAN9118_BA)    // Word Swap Control
+#define LAN9118_FREE_RUN                      (0x0000009C + LAN9118_BA)    // Free-Run 25MHz Counter
+#define LAN9118_RX_DROP                       (0x000000A0 + LAN9118_BA)    // Receiver Dropped Frames Counter
+#define LAN9118_MAC_CSR_CMD                   (0x000000A4 + LAN9118_BA)    // MAC CSR Synchronizer Command
+#define LAN9118_MAC_CSR_DATA                  (0x000000A8 + LAN9118_BA)    // MAC CSR Synchronizer Data
+#define LAN9118_AFC_CFG                       (0x000000AC + LAN9118_BA)    // Automatic Flow Control Configuration
+#define LAN9118_E2P_CMD                       (0x000000B0 + LAN9118_BA)    // EEPROM Command
+#define LAN9118_E2P_DATA                      (0x000000B4 + LAN9118_BA)    // EEPROM Data
+
+/*
+ * Required delays following write cycles (number of BYTE_TEST reads)
+ * Taken from Table 6.1 in Revision 1.5 (07-11-08) of the LAN9118 datasheet.
+ * Where no delay listed, 0 has been assumed.
+ */
+#define LAN9118_RX_DATA_WR_DELAY              0
+#define LAN9118_RX_STATUS_WR_DELAY            0
+#define LAN9118_RX_STATUS_PEEK_WR_DELAY       0
+#define LAN9118_TX_DATA_WR_DELAY              0
+#define LAN9118_TX_STATUS_WR_DELAY            0
+#define LAN9118_TX_STATUS_PEEK_WR_DELAY       0
+#define LAN9118_ID_REV_WR_DELAY               0
+#define LAN9118_IRQ_CFG_WR_DELAY              3
+#define LAN9118_INT_STS_WR_DELAY              2
+#define LAN9118_INT_EN_WR_DELAY               1
+#define LAN9118_BYTE_TEST_WR_DELAY            0
+#define LAN9118_FIFO_INT_WR_DELAY             1
+#define LAN9118_RX_CFG_WR_DELAY               1
+#define LAN9118_TX_CFG_WR_DELAY               1
+#define LAN9118_HW_CFG_WR_DELAY               1
+#define LAN9118_RX_DP_CTL_WR_DELAY            1
+#define LAN9118_RX_FIFO_INF_WR_DELAY          0
+#define LAN9118_TX_FIFO_INF_WR_DELAY          3
+#define LAN9118_PMT_CTRL_WR_DELAY             7
+#define LAN9118_GPIO_CFG_WR_DELAY             1
+#define LAN9118_GPT_CFG_WR_DELAY              1
+#define LAN9118_GPT_CNT_WR_DELAY              3
+#define LAN9118_WORD_SWAP_WR_DELAY            1
+#define LAN9118_FREE_RUN_WR_DELAY             4
+#define LAN9118_RX_DROP_WR_DELAY              0
+#define LAN9118_MAC_CSR_CMD_WR_DELAY          1
+#define LAN9118_MAC_CSR_DATA_WR_DELAY         1
+#define LAN9118_AFC_CFG_WR_DELAY              1
+#define LAN9118_E2P_CMD_WR_DELAY              1
+#define LAN9118_E2P_DATA_WR_DELAY             1
+
+/*
+ * Required delays following read cycles (number of BYTE_TEST reads)
+ * Taken from Table 6.2 in Revision 1.5 (07-11-08) of the LAN9118 datasheet.
+ * Where no delay listed, 0 has been assumed.
+ */
+#define LAN9118_RX_DATA_RD_DELAY              3
+#define LAN9118_RX_STATUS_RD_DELAY            3
+#define LAN9118_RX_STATUS_PEEK_RD_DELAY       0
+#define LAN9118_TX_DATA_RD_DELAY              0
+#define LAN9118_TX_STATUS_RD_DELAY            3
+#define LAN9118_TX_STATUS_PEEK_RD_DELAY       0
+#define LAN9118_ID_REV_RD_DELAY               0
+#define LAN9118_IRQ_CFG_RD_DELAY              0
+#define LAN9118_INT_STS_RD_DELAY              0
+#define LAN9118_INT_EN_RD_DELAY               0
+#define LAN9118_BYTE_TEST_RD_DELAY            0
+#define LAN9118_FIFO_INT_RD_DELAY             0
+#define LAN9118_RX_CFG_RD_DELAY               0
+#define LAN9118_TX_CFG_RD_DELAY               0
+#define LAN9118_HW_CFG_RD_DELAY               0
+#define LAN9118_RX_DP_CTL_RD_DELAY            0
+#define LAN9118_RX_FIFO_INF_RD_DELAY          0
+#define LAN9118_TX_FIFO_INF_RD_DELAY          0
+#define LAN9118_PMT_CTRL_RD_DELAY             0
+#define LAN9118_GPIO_CFG_RD_DELAY             0
+#define LAN9118_GPT_CFG_RD_DELAY              0
+#define LAN9118_GPT_CNT_RD_DELAY              0
+#define LAN9118_WORD_SWAP_RD_DELAY            0
+#define LAN9118_FREE_RUN_RD_DELAY             0
+#define LAN9118_RX_DROP_RD_DELAY              4
+#define LAN9118_MAC_CSR_CMD_RD_DELAY          0
+#define LAN9118_MAC_CSR_DATA_RD_DELAY         0
+#define LAN9118_AFC_CFG_RD_DELAY              0
+#define LAN9118_E2P_CMD_RD_DELAY              0
+#define LAN9118_E2P_DATA_RD_DELAY             0
+
+// Receiver Status bits
+#define RXSTATUS_CRC_ERROR                    BIT1                      // Cyclic Redundancy Check Error
+#define RXSTATUS_DB                           BIT2                      // Dribbling bit: Frame had non-integer multiple of 8bits
+#define RXSTATUS_MII_ERROR                    BIT3                      // Receive error during interception
+#define RXSTATUS_RXW_TO                       BIT4                      // Incoming frame larger than 2kb
+#define RXSTATUS_FT                           BIT5                      // 1: Ether type / 0: 802.3 type frame
+#define RXSTATUS_LCOLL                        BIT6                      // Late collision detected
+#define RXSTATUS_FTL                          BIT7                      // Frame longer than Ether type
+#define RXSTATUS_MCF                          BIT10                     // Frame has Multicast Address
+#define RXSTATUS_RUNT                         BIT11                     // Bad frame
+#define RXSTATUS_LE                           BIT12                     // Actual length of frame different than it claims
+#define RXSTATUS_BCF                          BIT13                     // Frame has Broadcast Address
+#define RXSTATUS_ES                           BIT15                     // Reports any error from bits 1,6,7 and 11
+#define RXSTATUS_PL_MASK                      (0x3FFF0000)              // Packet length bit mask
+#define GET_RXSTATUS_PACKET_LENGTH(RxStatus)  (((RxStatus) >> 16) & 0x3FFF) // Packet length bit mask
+#define RXSTATUS_FILT_FAIL                    BIT30                     // The frame failed filtering test
+
+// Transmitter Status bits
+#define TXSTATUS_DEF                          BIT0                      // Packet tx was deferred
+#define TXSTATUS_EDEF                         BIT2                      // Tx ended because of excessive deferral (> 24288 bit times)
+#define TXSTATUS_CC_MASK                      (0x00000078)              // Collision Count (before Tx) bit mask
+#define TXSTATUS_ECOLL                        BIT8                      // Tx ended because of Excessive Collisions (makes CC_MASK invalid after 16 collisions)
+#define TXSTATUS_LCOLL                        BIT9                      // Packet Tx aborted after coll window of 64 bytes
+#define TXSTATUS_NO_CA                        BIT10                     // Carrier signal not present during Tx (bad?)
+#define TXSTATUS_LOST_CA                      BIT11                     // Lost carrier during Tx
+#define TXSTATUS_ES                           BIT15                     // Reports any errors from bits 1,2,8,9,10 and 11
+#define TXSTATUS_PTAG_MASK                    (0xFFFF0000)              // Mask for Unique ID of packets (So we know who the packets are for)
+
+// ID_REV register bits
+#define IDREV_ID                              ((Lan9118MmioRead32(LAN9118_ID_REV) & 0xFFFF0000) >> 16)
+#define IDREV_REV                             (Lan9118MmioRead32(LAN9118_ID_REV) & 0x0000FFFF)
+
+// Interrupt Config Register bits
+#define IRQCFG_IRQ_TYPE                       BIT0                    // IRQ Buffer type
+#define IRQCFG_IRQ_POL                        BIT4                    // IRQ Polarity
+#define IRQCFG_IRQ_EN                         BIT8                    // Enable external interrupt
+#define IRQCFG_IRQ_INT                        BIT12                   // State of internal interrupts line
+#define IRQCFG_INT_DEAS_STS                   BIT13                   // State of deassertion interval
+#define IRQCFG_INT_DEAS_CLR                   BIT14                   // Clear the deassertion counter
+#define IRQCFG_INT_DEAS_MASK                  (0xFF000000)            // Interrupt deassertion interval value mask
+
+// Interrupt Status Register bits
+#define INSTS_GPIO_MASK                       (0x7)                   // GPIO interrupts mask
+#define INSTS_RSFL                            (0x8)                   // Rx Status FIFO Level reached
+#define INSTS_RSFF                            BIT4                    // Rx Status FIFO full
+#define INSTS_RXDF_INT                        BIT6                    // Rx Frame dropped
+#define INSTS_TSFL                            BIT7                    // Tx Status FIFO Level reached
+#define INSTS_TSFF                            BIT8                    // Tx Status FIFO full
+#define INSTS_TDFA                            BIT9                    // Tx Data FIFO Level exceeded
+#define INSTS_TDFO                            BIT10                   // Tx Data FIFO full
+#define INSTS_TXE                             BIT13                   // Transmitter Error
+#define INSTS_RXE                             BIT14                   // Receiver Error
+#define INSTS_RWT                             BIT15                   // Packet > 2048 bytes received
+#define INSTS_TXSO                            BIT16                   // Tx Status FIFO Overflow
+#define INSTS_PME_INT                         BIT17                   // PME Signal detected
+#define INSTS_PHY_INT                         BIT18                   // Indicates PHY Interrupt
+#define INSTS_GPT_INT                         BIT19                   // GP Timer wrapped past 0xFFFF
+#define INSTS_RXD_INT                         BIT20                   // Indicates that amount of data written to RX_CFG was cleared
+#define INSTS_TX_IOC                          BIT21                   // Finished loading IOC flagged buffer to Tx FIFO
+#define INSTS_RXDFH_INT                       BIT23                   // Rx Dropped frames went past 0x7FFFFFFF
+#define INSTS_RXSTOP_INT                      BIT24                   // Rx was stopped
+#define INSTS_TXSTOP_INT                      BIT25                   // Tx was stopped
+#define INSTS_SW_INT                          BIT31                   // Software Interrupt occurred
+
+// Interrupt Enable Register bits
+
+
+// Hardware Config Register bits
+#define HWCFG_SRST                            BIT0                       // Software Reset bit         (SC)
+#define HWCFG_SRST_TO                         BIT1                       // Software Reset Timeout bit (RO)
+#define HWCFG_BMODE                           BIT2                       // 32/16 bit Mode bit         (RO)
+#define HWCFG_TX_FIFO_SIZE_MASK               (~ (UINT32)0xF0000)        // Mask to Clear FIFO Size
+#define HWCFG_MBO                             BIT20                      // Must Be One bit
+
+// Power Management Control Register
+#define MPTCTRL_READY                         BIT0                // Device ready indicator
+#define MPTCTRL_PME_EN                        BIT1                // Enable external PME signals
+#define MPTCTRL_PME_POL                       BIT2                // Set polarity of PME signals
+#define MPTCTRL_PME_IND                       BIT3                // Signal type of PME (refer to Spec)
+#define MPTCTRL_WUPS_MASK                     (0x18)              // Wake up status indicator mask
+#define MPTCTRL_PME_TYPE                      BIT6                // PME Buffer type (Open Drain or Push-Pull)
+#define MPTCTRL_ED_EN                         BIT8                // Energy-detect enable
+#define MPTCTRL_WOL_EN                        BIT9                // Enable wake-on-lan
+#define MPTCTRL_PHY_RST                       BIT10               // Reset the PHY
+#define MPTCTRL_PM_MODE_MASK                  (BIT12 | BIT13)     // Set the power mode
+
+// PHY control register bits
+#define PHYCR_COLL_TEST                       BIT7                  // Collision test enable
+#define PHYCR_DUPLEX_MODE                     BIT8                  // Set Duplex Mode
+#define PHYCR_RST_AUTO                        BIT9                  // Restart Auto-Negotiation of Link abilities
+#define PHYCR_PD                              BIT11                 // Power-Down switch
+#define PHYCR_AUTO_EN                         BIT12                 // Auto-Negotiation Enable
+#define PHYCR_SPEED_SEL                       BIT13                 // Link Speed Selection
+#define PHYCR_LOOPBK                          BIT14                 // Set loopback mode
+#define PHYCR_RESET                           BIT15                 // Do a PHY reset
+
+// PHY status register bits
+#define PHYSTS_EXT_CAP                        BIT0                  // Extended Capabilities Register capability
+#define PHYSTS_JABBER                         BIT1                  // Jabber condition detected
+#define PHYSTS_LINK_STS                       BIT2                  // Link Status
+#define PHYSTS_AUTO_CAP                       BIT3                  // Auto-Negotiation Capability
+#define PHYSTS_REMOTE_FAULT                   BIT4                  // Remote fault detected
+#define PHYSTS_AUTO_COMP                      BIT5                  // Auto-Negotiation Completed
+#define PHYSTS_10BASET_HDPLX                  BIT11                 // 10Mbps Half-Duplex ability
+#define PHYSTS_10BASET_FDPLX                  BIT12                 // 10Mbps Full-Duplex ability
+#define PHYSTS_100BASETX_HDPLX                BIT13                 // 100Mbps Half-Duplex ability
+#define PHYSTS_100BASETX_FDPLX                BIT14                 // 100Mbps Full-Duplex ability
+#define PHYSTS_100BASE_T4                     BIT15                 // Base T4 ability
+
+// PHY Auto-Negotiation advertisement
+#define PHYANA_SEL_MASK                       ((UINT32)0x1F)        // Link type selector
+#define PHYANA_10BASET                        BIT5                  // Advertise 10BASET capability
+#define PHYANA_10BASETFD                      BIT6                  // Advertise 10BASET Full duplex capability
+#define PHYANA_100BASETX                      BIT7                  // Advertise 100BASETX capability
+#define PHYANA_100BASETXFD                    BIT8                  // Advertise 100 BASETX Full duplex capability
+#define PHYANA_PAUSE_OP_MASK                  (3 << 10)             // Advertise PAUSE frame capability
+#define PHYANA_REMOTE_FAULT                   BIT13                 // Remote fault detected
+
+
+// PHY Auto-Negotiation Link Partner Ability
+
+// PHY Auto-Negotiation Expansion
+
+// PHY Mode control/status
+
+// PHY Special Modes
+
+// PHY Special control/status
+
+// PHY Interrupt Source Flags
+
+// PHY Interrupt Mask
+
+// PHY Super Special control/status
+#define PHYSSCS_HCDSPEED_MASK                 (7 << 2)              // Speed indication
+#define PHYSSCS_AUTODONE                      BIT12                 // Auto-Negotiation Done
+
+
+// MAC control register bits
+#define MACCR_RX_EN                       BIT2                     // Enable Receiver bit
+#define MACCR_TX_EN                       BIT3                     // Enable Transmitter bit
+#define MACCR_DFCHK                       BIT5                     // Deferral Check bit
+#define MACCR_PADSTR                      BIT8                     // Automatic Pad Stripping bit
+#define MACCR_BOLMT_MASK                  (0xC0)                   // Back-Off limit mask
+#define MACCR_DISRTY                      BIT10                    // Disable Transmit Retry bit
+#define MACCR_BCAST                       BIT11                    // Disable Broadcast Frames bit
+#define MACCR_LCOLL                       BIT12                    // Late Collision Control bit
+#define MACCR_HPFILT                      BIT13                    // Hash/Perfect Filtering Mode bit
+#define MACCR_HO                          BIT15                    // Hash Only Filtering Mode
+#define MACCR_PASSBAD                     BIT16                    // Receive all frames that passed filter bit
+#define MACCR_INVFILT                     BIT17                    // Enable Inverse Filtering bit
+#define MACCR_PRMS                        BIT18                    // Promiscuous Mode bit
+#define MACCR_MCPAS                       BIT19                    // Pass all Multicast packets bit
+#define MACCR_FDPX                        BIT20                    // Full Duplex Mode bit
+#define MACCR_LOOPBK                      BIT21                    // Loopback operation mode bit
+#define MACCR_RCVOWN                      BIT23                    // Disable Receive Own frames bit
+#define MACCR_RX_ALL                      BIT31                    // Receive all Packets and route to Filter
+
+// Wake-Up Control and Status Register
+#define WUCSR_MPEN                        BIT1                     // Magic Packet enable (allow wake from Magic P)
+#define WUCSR_WUEN                        BIT2                     // Allow remote wake up using Wake-Up Frames
+#define WUCSR_MPR_MASK                    (0x10)                   // Received Magic Packet
+#define WUCSR_WUFR_MASK                   (0x20)                   // Received Wake-Up Frame
+#define WUCSR_GUE                         BIT9                     // Enable wake on global unicast frames
+
+// RX Configuration Register bits
+#define RXCFG_RXDOFF_MASK                 (0x1F00)                 // Rx Data Offset in Bytes
+#define RXCFG_RX_DUMP                     BIT15                    // Clear Rx data and status FIFOs
+#define RXCFG_RX_DMA_CNT_MASK             (0x0FFF0000)             // Amount of data to be read from Rx FIFO
+#define RXCFG_RX_DMA_CNT(cnt)             (((cnt) & 0xFFF) << 16)  // Amount of data to be read from Rx FIFO
+#define RXCFG_RX_END_ALIGN_MASK           (0xC0000000)             // Alignment to preserve
+
+// TX Configuration Register bits
+#define TXCFG_STOP_TX                     BIT0                     // Stop the transmitter
+#define TXCFG_TX_ON                       BIT1                     // Start the transmitter
+#define TXCFG_TXSAO                       BIT2                     // Tx Status FIFO full
+#define TXCFG_TXD_DUMP                    BIT14                    // Clear Tx Data FIFO
+#define TXCFG_TXS_DUMP                    BIT15                    // Clear Tx Status FIFO
+
+// Rx FIFO Information Register bits
+#define RXFIFOINF_RXDUSED_MASK            (0xFFFF)                 // Rx Data FIFO Used Space
+#define RXFIFOINF_RXSUSED_MASK            (0xFF0000)               // Rx Status FIFO Used Space
+
+// Tx FIFO Information Register bits
+#define TXFIFOINF_TDFREE_MASK             (0xFFFF)                 // Tx Data FIFO Free Space
+#define TXFIFOINF_TXSUSED_MASK            (0xFF0000)               // Tx Status FIFO Used Space
+
+// E2P Register
+#define E2P_EPC_BUSY                BIT31
+#define E2P_EPC_CMD_READ            (0)
+#define E2P_EPC_TIMEOUT             BIT9
+#define E2P_EPC_MAC_ADDRESS_LOADED  BIT8
+#define E2P_EPC_ADDRESS(address)    ((address) & 0xFFFF)
+
+// GPIO Configuration register
+#define GPIO_GPIO0_PUSH_PULL        BIT16
+#define GPIO_GPIO1_PUSH_PULL        BIT17
+#define GPIO_GPIO2_PUSH_PULL        BIT18
+#define GPIO_LED1_ENABLE            BIT28
+#define GPIO_LED2_ENABLE            BIT29
+#define GPIO_LED3_ENABLE            BIT30
+
+// MII_ACC bits
+#define MII_ACC_MII_BUSY        BIT0
+#define MII_ACC_MII_WRITE       BIT1
+#define MII_ACC_MII_READ        0
+
+#define MII_ACC_PHY_VALUE             BIT11
+#define MII_ACC_MII_REG_INDEX(index)  (((index) & 0x1F) << 6)
+
+//
+// PHY Control Indexes
+//
+#define PHY_INDEX_BASIC_CTRL              0
+#define PHY_INDEX_BASIC_STATUS            1
+#define PHY_INDEX_ID1                     2
+#define PHY_INDEX_ID2                     3
+#define PHY_INDEX_AUTO_NEG_ADVERT         4
+#define PHY_INDEX_AUTO_NEG_LINK_ABILITY   5
+#define PHY_INDEX_AUTO_NEG_EXP            6
+#define PHY_INDEX_MODE                    17
+#define PHY_INDEX_SPECIAL_MODES           18
+#define PHY_INDEX_SPECIAL_CTLR            27
+#define PHY_INDEX_INT_SRC                 29
+#define PHY_INDEX_INT_MASK                30
+#define PHY_INDEX_SPECIAL_PHY_CTLR        31
+
+// Indirect MAC Indexes
+#define INDIRECT_MAC_INDEX_CR         1
+#define INDIRECT_MAC_INDEX_ADDRH      2
+#define INDIRECT_MAC_INDEX_ADDRL      3
+#define INDIRECT_MAC_INDEX_HASHH      4
+#define INDIRECT_MAC_INDEX_HASHL      5
+#define INDIRECT_MAC_INDEX_MII_ACC    6
+#define INDIRECT_MAC_INDEX_MII_DATA   7
+
+//
+// MAC CSR Synchronizer Command register
+//
+#define MAC_CSR_BUSY            BIT31
+#define MAC_CSR_READ            BIT30
+#define MAC_CSR_WRITE           0
+#define MAC_CSR_ADDR(Addr)      ((Addr) & 0xFF)
+
+//
+// TX Packet Format
+//
+#define TX_CMD_A_COMPLETION_INT             BIT31
+#define TX_CMD_A_FIRST_SEGMENT              BIT13
+#define TX_CMD_A_LAST_SEGMENT               BIT12
+#define TX_CMD_A_BUFF_SIZE(size)            ((size) & 0x000003FF)
+#define TX_CMD_A_DATA_START_OFFSET(offset)  (((offset) & 0x1F) << 16)
+#define TX_CMD_B_PACKET_LENGTH(size)        ((size) & 0x000003FF)
+#define TX_CMD_B_PACKET_TAG(tag)            (((tag) & 0x3FF) << 16)
+
+// Hardware Configuration Register
+#define HW_CFG_TX_FIFO_SIZE_MASK        (0xF << 16)
+#define HW_CFG_TX_FIFO_SIZE(size)       (((size) & 0xF) << 16)
+
+// EEPROM Definition
+#define EEPROM_EXTERNAL_SERIAL_EEPROM   0xA5
+
+//
+// Conditional compilation flags
+//
+//#define EVAL_PERFORMANCE
+
+
+#endif /* __LAN9118_DXE_HDR_H__ */

+ 1039 - 0
Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c

@@ -0,0 +1,1039 @@
+/** @file
+*
+*  WARNING:
+*  This driver fails to follow the UEFI driver model without a good
+*  reason, and only remains in the tree because it is still used by
+*  a small number of platforms. It will be removed when no longer used.
+*  New platforms should not use it, and no one should use this as
+*  reference code for developing new drivers.
+*
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include "Lan9118Dxe.h"
+
+STATIC EFI_MAC_ADDRESS mZeroMac = { { 0 } };
+
+/**
+  This internal function reverses bits for 32bit data.
+
+  @param  Value                 The data to be reversed.
+
+  @return                       Data reversed.
+
+**/
+UINT32
+ReverseBits (
+  UINT32  Value
+  )
+{
+  UINTN   Index;
+  UINT32  NewValue;
+
+  NewValue = 0;
+  for (Index = 0; Index < 32; Index++) {
+    if ((Value & (1 << Index)) != 0) {
+      NewValue = NewValue | (1 << (31 - Index));
+    }
+  }
+
+  return NewValue;
+}
+
+/*
+**  Create Ethernet CRC
+**
+**  INFO USED:
+**    1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check
+**
+**    2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html
+**
+**    3: http://en.wikipedia.org/wiki/Computation_of_CRC
+*/
+UINT32
+GenEtherCrc32 (
+  IN    EFI_MAC_ADDRESS *Mac,
+  IN    UINT32 AddrLen
+  )
+{
+  INT32 Iter;
+  UINT32 Remainder;
+  UINT8 *Ptr;
+
+  Iter = 0;
+  Remainder = 0xFFFFFFFF;    // 0xFFFFFFFF is standard seed for Ethernet
+
+  // Convert Mac Address to array of bytes
+  Ptr = (UINT8*)Mac;
+
+  // Generate the Crc bit-by-bit (LSB first)
+  while (AddrLen--) {
+    Remainder ^= *Ptr++;
+    for (Iter = 0;Iter < 8;Iter++) {
+      // Check if exponent is set
+      if (Remainder & 1) {
+        Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL;
+      } else {
+        Remainder = (Remainder >> 1) ^ 0;
+      }
+    }
+  }
+
+  // Reverse the bits before returning (to Big Endian)
+  //TODO: Need to be reviewed. Do we want to do a bit reverse or a byte reverse (in this case use SwapBytes32())
+  return ReverseBits (Remainder);
+}
+
+// Function to read from MAC indirect registers
+UINT32
+IndirectMACRead32 (
+  UINT32 Index
+  )
+{
+  UINT32 MacCSR;
+
+  // Check index is in the range
+  ASSERT(Index <= 12);
+
+  // Wait until CSR busy bit is cleared
+  while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
+
+  // Set CSR busy bit to ensure read will occur
+  // Set the R/W bit to indicate we are reading
+  // Set the index of CSR Address to access desired register
+  MacCSR = MAC_CSR_BUSY | MAC_CSR_READ | MAC_CSR_ADDR(Index);
+
+  // Write to the register
+  Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR);
+
+  // Wait until CSR busy bit is cleared
+  while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
+
+  // Now read from data register to get read value
+  return Lan9118MmioRead32 (LAN9118_MAC_CSR_DATA);
+}
+
+/*
+ * LAN9118 chips have special restrictions on some back-to-back Write/Read or
+ * Read/Read pairs of accesses. After a read or write that changes the state of
+ * the device, there is a period in which stale values may be returned in
+ * response to a read. This period is dependent on the registers accessed.
+ *
+ * We must delay prior reads by this period. This can either be achieved by
+ * timer-based delays, or by performing dummy reads of the BYTE_TEST register,
+ * for which the recommended number of reads is described in the LAN9118 data
+ * sheet. This is required in addition to any memory barriers.
+ *
+ * This function performs a number of dummy reads of the BYTE_TEST register, as
+ * a building block for the above.
+ */
+VOID
+WaitDummyReads (
+  UINTN Count
+  )
+{
+  while (Count--)
+    MmioRead32(LAN9118_BYTE_TEST);
+}
+
+UINT32
+Lan9118RawMmioRead32(
+  UINTN Address,
+  UINTN Delay
+  )
+{
+  UINT32 Value;
+
+  Value = MmioRead32(Address);
+  WaitDummyReads(Delay);
+  return Value;
+}
+
+UINT32
+Lan9118RawMmioWrite32(
+  UINTN Address,
+  UINT32 Value,
+  UINTN Delay
+  )
+{
+  MmioWrite32(Address, Value);
+  WaitDummyReads(Delay);
+  return Value;
+}
+
+// Function to write to MAC indirect registers
+UINT32
+IndirectMACWrite32 (
+  UINT32 Index,
+  UINT32 Value
+  )
+{
+  UINT32 ValueWritten;
+  UINT32 MacCSR;
+
+  // Check index is in the range
+  ASSERT(Index <= 12);
+
+  // Wait until CSR busy bit is cleared
+  while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
+
+  // Set CSR busy bit to ensure read will occur
+  // Set the R/W bit to indicate we are writing
+  // Set the index of CSR Address to access desired register
+  MacCSR = MAC_CSR_BUSY | MAC_CSR_WRITE | MAC_CSR_ADDR(Index);
+
+  // Now write the value to the register before issuing the write command
+  ValueWritten = Lan9118MmioWrite32 (LAN9118_MAC_CSR_DATA, Value);
+
+  // Write the config to the register
+  Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR);
+
+  // Wait until CSR busy bit is cleared
+  while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
+
+  return ValueWritten;
+}
+
+// Function to read from MII register (PHY Access)
+UINT32
+IndirectPHYRead32 (
+  UINT32 Index
+  )
+{
+  UINT32 ValueRead;
+  UINT32 MiiAcc;
+
+  // Check it is a valid index
+  ASSERT(Index < 31);
+
+  // Wait for busy bit to clear
+  while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
+
+  // Clear the R/W bit to indicate we are reading
+  // Set the index of the MII register
+  // Set the PHY Address
+  // Set the MII busy bit to allow read
+  MiiAcc = MII_ACC_MII_READ | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY;
+
+  // Now write this config to register
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF);
+
+  // Wait for busy bit to clear
+  while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
+
+  // Now read the value of the register
+  ValueRead = (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA) & 0xFFFF); // only lower 16 bits are valid for any PHY register
+
+  return ValueRead;
+}
+
+
+// Function to write to the MII register (PHY Access)
+UINT32
+IndirectPHYWrite32 (
+  UINT32 Index,
+  UINT32 Value
+  )
+{
+  UINT32 MiiAcc;
+  UINT32 ValueWritten;
+
+  // Check it is a valid index
+  ASSERT(Index < 31);
+
+  // Wait for busy bit to clear
+  while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
+
+  // Clear the R/W bit to indicate we are reading
+  // Set the index of the MII register
+  // Set the PHY Address
+  // Set the MII busy bit to allow read
+  MiiAcc = MII_ACC_MII_WRITE | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY;
+
+  // Write the desired value to the register first
+  ValueWritten = IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA, (Value & 0xFFFF));
+
+  // Now write the config to register
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF);
+
+  // Wait for operation to terminate
+  while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
+
+  return ValueWritten;
+}
+
+
+/* ---------------- EEPROM Operations ------------------ */
+
+
+// Function to read from EEPROM memory
+UINT32
+IndirectEEPROMRead32 (
+  UINT32 Index
+  )
+{
+  UINT32 EepromCmd;
+
+  // Set the busy bit to ensure read will occur
+  EepromCmd = E2P_EPC_BUSY | E2P_EPC_CMD_READ;
+
+  // Set the index to access desired EEPROM memory location
+  EepromCmd |= E2P_EPC_ADDRESS(Index);
+
+  // Write to Eeprom command register
+  Lan9118MmioWrite32 (LAN9118_E2P_CMD, EepromCmd);
+
+  // Wait until operation has completed
+  while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
+
+  // Check that operation didn't time out
+  if (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) {
+    DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Read command on index %x\n",Index));
+    return 0;
+  }
+
+  // Wait until operation has completed
+  while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
+
+  // Finally read the value
+  return Lan9118MmioRead32 (LAN9118_E2P_DATA);
+}
+
+// Function to write to EEPROM memory
+UINT32
+IndirectEEPROMWrite32 (
+  UINT32 Index,
+  UINT32 Value
+  )
+{
+  UINT32 ValueWritten;
+  UINT32 EepromCmd;
+
+  ValueWritten = 0;
+
+  // Read the EEPROM Command register
+  EepromCmd = Lan9118MmioRead32 (LAN9118_E2P_CMD);
+
+  // Set the busy bit to ensure read will occur
+  EepromCmd |= ((UINT32)1 << 31);
+
+  // Set the EEPROM command to write(0b011)
+  EepromCmd &= ~(7 << 28);    // Clear the command first
+  EepromCmd |= (3 << 28);     // Write 011
+
+  // Set the index to access desired EEPROM memory location
+  EepromCmd |= (Index & 0xF);
+
+  // Write the value to the data register first
+  ValueWritten = Lan9118MmioWrite32 (LAN9118_E2P_DATA, Value);
+
+  // Write to Eeprom command register
+  Lan9118MmioWrite32 (LAN9118_E2P_CMD, EepromCmd);
+
+  // Wait until operation has completed
+  while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
+
+  // Check that operation didn't time out
+  if (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) {
+    DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Write command at memloc 0x%x, with value 0x%x\n",Index, Value));
+    return 0;
+  }
+
+  // Wait until operation has completed
+  while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
+
+  return ValueWritten;
+}
+
+/* ---------------- General Operations ----------------- */
+
+VOID
+Lan9118SetMacAddress (
+  EFI_MAC_ADDRESS             *Mac,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL,
+                      (Mac->Addr[0] & 0xFF) |
+                      ((Mac->Addr[1] & 0xFF) << 8) |
+                      ((Mac->Addr[2] & 0xFF) << 16) |
+                      ((Mac->Addr[3] & 0xFF) << 24)
+                    );
+
+  IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH,
+                      (UINT32)(Mac->Addr[4] & 0xFF) |
+                      ((Mac->Addr[5] & 0xFF) << 8)
+                    );
+}
+
+VOID
+Lan9118ReadMacAddress (
+  OUT EFI_MAC_ADDRESS *MacAddress
+  )
+{
+  UINT32          MacAddrHighValue;
+  UINT32          MacAddrLowValue;
+
+  // Read the Mac Addr high register
+  MacAddrHighValue = (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH) & 0xFFFF);
+  // Read the Mac Addr low register
+  MacAddrLowValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL);
+
+  SetMem (MacAddress, sizeof(*MacAddress), 0);
+  MacAddress->Addr[0] = (MacAddrLowValue & 0xFF);
+  MacAddress->Addr[1] = (MacAddrLowValue & 0xFF00) >> 8;
+  MacAddress->Addr[2] = (MacAddrLowValue & 0xFF0000) >> 16;
+  MacAddress->Addr[3] = (MacAddrLowValue & 0xFF000000) >> 24;
+  MacAddress->Addr[4] = (MacAddrHighValue & 0xFF);
+  MacAddress->Addr[5] = (MacAddrHighValue & 0xFF00) >> 8;
+}
+
+/*
+ *  Power up the 9118 and find its MAC address.
+ *
+ *  This operation can be carried out when the LAN9118 is in any power state
+ *
+ */
+EFI_STATUS
+Lan9118Initialize (
+  IN  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINTN  Retries;
+  UINT64 DefaultMacAddress;
+
+  // Attempt to wake-up the device if it is in a lower power state
+  if (((Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12) != 0) {
+    DEBUG ((DEBUG_NET, "Waking from reduced power state.\n"));
+    Lan9118MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF);
+  }
+
+  // Check that device is active
+  Retries = 20;
+  while ((Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) == 0 && --Retries) {
+    gBS->Stall (LAN9118_STALL);
+  }
+  if (!Retries) {
+    return EFI_TIMEOUT;
+  }
+
+  // Check that EEPROM isn't active
+  Retries = 20;
+  while ((Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY) && --Retries){
+    gBS->Stall (LAN9118_STALL);
+  }
+  if (!Retries) {
+    return EFI_TIMEOUT;
+  }
+
+  // Check if a MAC address was loaded from EEPROM, and if it was, set it as the
+  // current address.
+  if ((Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_MAC_ADDRESS_LOADED) == 0) {
+    DEBUG ((EFI_D_ERROR, "Warning: There was an error detecting EEPROM or loading the MAC Address.\n"));
+
+    // If we had an address before (set by StationAddress), continue to use it
+    if (CompareMem (&Snp->Mode->CurrentAddress, &mZeroMac, NET_ETHER_ADDR_LEN)) {
+      Lan9118SetMacAddress (&Snp->Mode->CurrentAddress, Snp);
+    } else {
+      // If there are no cached addresses, then fall back to a default
+      DEBUG ((EFI_D_WARN, "Warning: using driver-default MAC address\n"));
+      DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress);
+      Lan9118SetMacAddress((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp);
+      CopyMem (&Snp->Mode->CurrentAddress, &DefaultMacAddress, NET_ETHER_ADDR_LEN);
+    }
+  } else {
+    // Store the MAC address that was loaded from EEPROM
+    Lan9118ReadMacAddress (&Snp->Mode->CurrentAddress);
+    CopyMem (&Snp->Mode->PermanentAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
+  }
+
+  // Clear and acknowledge interrupts
+  Lan9118MmioWrite32 (LAN9118_INT_EN, 0);
+  Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0);
+  Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
+
+  // Do self tests here?
+
+  return EFI_SUCCESS;
+}
+
+
+// Perform software reset on the LAN9118
+// Return 0 on success, -1 on error
+EFI_STATUS
+SoftReset (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 HwConf;
+  UINT32 ResetTime;
+
+  // Initialize variable
+  ResetTime = 0;
+
+  // Stop Rx and Tx
+  StopTx (STOP_TX_MAC | STOP_TX_CFG | STOP_TX_CLEAR, Snp);
+  StopRx (STOP_RX_CLEAR, Snp); // Clear receiver FIFO
+
+  // Issue the reset
+  HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG);
+  HwConf |= 1;
+
+  // Set the Must Be One (MBO) bit
+  if (((HwConf & HWCFG_MBO) >> 20) == 0) {
+    HwConf |= HWCFG_MBO;
+  }
+
+  // Check that EEPROM isn't active
+  while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
+
+  // Write the configuration
+  Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf);
+
+  // Wait for reset to complete
+  while (Lan9118MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) {
+
+    gBS->Stall (LAN9118_STALL);
+    ResetTime += 1;
+
+    // If time taken exceeds 100us, then there was an error condition
+    if (ResetTime > 1000) {
+      Snp->Mode->State = EfiSimpleNetworkStopped;
+      return EFI_TIMEOUT;
+    }
+  }
+
+  // Check that EEPROM isn't active
+  while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
+
+  // TODO we probably need to re-set the mac address here.
+
+  // Clear and acknowledge all interrupts
+  if (Flags & SOFT_RESET_CLEAR_INT) {
+    Lan9118MmioWrite32 (LAN9118_INT_EN, 0);
+    Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0);
+    Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
+  }
+
+  // Do self tests here?
+  if (Flags & SOFT_RESET_SELF_TEST) {
+
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+// Perform PHY software reset
+EFI_STATUS
+PhySoftReset (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 PmtCtrl = 0;
+
+  // PMT PHY reset takes precedence over BCR
+  if (Flags & PHY_RESET_PMT) {
+    PmtCtrl = Lan9118MmioRead32 (LAN9118_PMT_CTRL);
+    PmtCtrl |= MPTCTRL_PHY_RST;
+    Lan9118MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl);
+
+    // Wait for completion
+    while (Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) {
+      gBS->Stall (LAN9118_STALL);
+    }
+  // PHY Basic Control Register reset
+  } else if (Flags & PHY_RESET_BCR) {
+    IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET);
+
+    // Wait for completion
+    while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) {
+      gBS->Stall (LAN9118_STALL);
+    }
+  }
+
+  // Clear and acknowledge all interrupts
+  if (Flags & PHY_SOFT_RESET_CLEAR_INT) {
+    Lan9118MmioWrite32 (LAN9118_INT_EN, 0);
+    Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0);
+    Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+// Configure hardware for LAN9118
+EFI_STATUS
+ConfigureHardware (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 GpioConf;
+
+  // Check if we want to use LEDs on GPIO
+  if (Flags & HW_CONF_USE_LEDS) {
+    GpioConf = Lan9118MmioRead32 (LAN9118_GPIO_CFG);
+
+    // Enable GPIO as LEDs and Config as Push-Pull driver
+    GpioConf |= GPIO_GPIO0_PUSH_PULL | GPIO_GPIO1_PUSH_PULL | GPIO_GPIO2_PUSH_PULL |
+                GPIO_LED1_ENABLE | GPIO_LED2_ENABLE | GPIO_LED3_ENABLE;
+
+    // Write the configuration
+    Lan9118MmioWrite32 (LAN9118_GPIO_CFG, GpioConf);
+  }
+
+  return EFI_SUCCESS;
+}
+
+// Configure flow control
+EFI_STATUS
+ConfigureFlow (
+  UINT32 Flags,
+  UINT32 HighTrig,
+  UINT32 LowTrig,
+  UINT32 BPDuration,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  return EFI_SUCCESS;
+}
+
+// Do auto-negotiation
+EFI_STATUS
+AutoNegotiate (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 PhyControl;
+  UINT32 PhyStatus;
+  UINT32 Features;
+  UINT32 Retries;
+
+  // First check that auto-negotiation is supported
+  PhyStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS);
+  if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) {
+    DEBUG ((EFI_D_ERROR, "Auto-negotiation not supported.\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Check that link is up first
+  if ((PhyStatus & PHYSTS_LINK_STS) == 0) {
+    // Wait until it is up or until Time Out
+    Retries = FixedPcdGet32 (PcdLan9118DefaultNegotiationTimeout) / LAN9118_STALL;
+    while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_LINK_STS) == 0) {
+      gBS->Stall (LAN9118_STALL);
+      Retries--;
+      if (!Retries) {
+        DEBUG ((EFI_D_ERROR, "Link timeout in auto-negotiation.\n"));
+        return EFI_TIMEOUT;
+      }
+    }
+  }
+
+  // Configure features to advertise
+  Features = IndirectPHYRead32 (PHY_INDEX_AUTO_NEG_ADVERT);
+
+  if ((Flags & AUTO_NEGOTIATE_ADVERTISE_ALL) > 0) {
+    // Link speed capabilities
+    Features |= (PHYANA_10BASET | PHYANA_10BASETFD | PHYANA_100BASETX | PHYANA_100BASETXFD);
+
+    // Pause frame capabilities
+    Features &= ~(PHYANA_PAUSE_OP_MASK);
+    Features |= 3 << 10;
+  }
+  Features &= FixedPcdGet32 (PcdLan9118NegotiationFeatureMask);
+
+  // Write the features
+  IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, Features);
+
+  // Read control register
+  PhyControl = IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL);
+
+  // Enable Auto-Negotiation
+  if ((PhyControl & PHYCR_AUTO_EN) == 0) {
+    PhyControl |= PHYCR_AUTO_EN;
+  }
+
+  // Restart auto-negotiation
+  PhyControl |= PHYCR_RST_AUTO;
+
+  // Enable collision test if required to do so
+  if (Flags & AUTO_NEGOTIATE_COLLISION_TEST) {
+    PhyControl |= PHYCR_COLL_TEST;
+  } else {
+    PhyControl &= ~ PHYCR_COLL_TEST;
+  }
+
+  // Write this configuration
+  IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl);
+
+  // Wait until process has completed
+  while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0);
+
+  return EFI_SUCCESS;
+}
+
+// Check the Link Status and take appropriate action
+EFI_STATUS
+CheckLinkStatus (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  // Get the PHY Status
+  UINT32 PhyBStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS);
+
+  if (PhyBStatus & PHYSTS_LINK_STS) {
+    return EFI_SUCCESS;
+  } else {
+    return EFI_DEVICE_ERROR;
+  }
+}
+
+// Stop the transmitter
+EFI_STATUS
+StopTx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 MacCsr;
+  UINT32 TxCfg;
+
+  MacCsr = 0;
+  TxCfg = 0;
+
+  // Check if we want to clear tx
+  if (Flags & STOP_TX_CLEAR) {
+    TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
+    TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP;
+    Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
+  }
+
+  // Check if already stopped
+  if (Flags & STOP_TX_MAC) {
+    MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
+
+    if (MacCsr & MACCR_TX_EN) {
+      MacCsr &= ~MACCR_TX_EN;
+      IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
+    }
+  }
+
+  if (Flags & STOP_TX_CFG) {
+    TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
+
+    if (TxCfg & TXCFG_TX_ON) {
+      TxCfg |= TXCFG_STOP_TX;
+      Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
+
+      // Wait for Tx to finish transmitting
+      while (Lan9118MmioRead32 (LAN9118_TX_CFG) & TXCFG_STOP_TX);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+// Stop the receiver
+EFI_STATUS
+StopRx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 MacCsr;
+  UINT32 RxCfg;
+
+  RxCfg = 0;
+
+  // Check if already stopped
+  MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
+
+  if (MacCsr & MACCR_RX_EN) {
+    MacCsr &= ~ MACCR_RX_EN;
+    IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
+  }
+
+  // Check if we want to clear receiver FIFOs
+  if (Flags & STOP_RX_CLEAR) {
+    RxCfg = Lan9118MmioRead32 (LAN9118_RX_CFG);
+    RxCfg |= RXCFG_RX_DUMP;
+    Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfg);
+
+    while (Lan9118MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP);
+  }
+
+  return EFI_SUCCESS;
+}
+
+// Start the transmitter
+EFI_STATUS
+StartTx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 MacCsr;
+  UINT32 TxCfg;
+
+  MacCsr = 0;
+  TxCfg = 0;
+
+  // Check if we want to clear tx
+  if (Flags & START_TX_CLEAR) {
+    TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
+    TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP;
+    Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
+  }
+
+  // Check if tx was started from MAC and enable if not
+  if (Flags & START_TX_MAC) {
+    MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
+    if ((MacCsr & MACCR_TX_EN) == 0) {
+      MacCsr |= MACCR_TX_EN;
+      IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
+    }
+  }
+
+  // Check if tx was started from TX_CFG and enable if not
+  if (Flags & START_TX_CFG) {
+    TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
+    if ((TxCfg & TXCFG_TX_ON) == 0) {
+      TxCfg |= TXCFG_TX_ON;
+      Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
+    }
+  }
+
+  // Set the tx data trigger level
+
+  return EFI_SUCCESS;
+}
+
+// Start the receiver
+EFI_STATUS
+StartRx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 MacCsr;
+  UINT32 RxCfg;
+
+  RxCfg = 0;
+
+  // Check if already started
+  MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
+
+  if ((MacCsr & MACCR_RX_EN) == 0) {
+    // Check if we want to clear receiver FIFOs before starting
+    if (Flags & START_RX_CLEAR) {
+      RxCfg = Lan9118MmioRead32 (LAN9118_RX_CFG);
+      RxCfg |= RXCFG_RX_DUMP;
+      Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfg);
+
+      while (Lan9118MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP);
+    }
+
+    MacCsr |= MACCR_RX_EN;
+    IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
+  }
+
+  return EFI_SUCCESS;
+}
+
+// Check Tx Data available space
+UINT32
+TxDataFreeSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 TxInf;
+  UINT32 FreeSpace;
+
+  // Get the amount of free space from information register
+  TxInf = Lan9118MmioRead32 (LAN9118_TX_FIFO_INF);
+  FreeSpace = (TxInf & TXFIFOINF_TDFREE_MASK);
+
+  return FreeSpace; // Value in bytes
+}
+
+// Check Tx Status used space
+UINT32
+TxStatusUsedSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 TxInf;
+  UINT32 UsedSpace;
+
+  // Get the amount of used space from information register
+  TxInf = Lan9118MmioRead32 (LAN9118_TX_FIFO_INF);
+  UsedSpace = (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16;
+
+  return UsedSpace << 2; // Value in bytes
+}
+
+// Check Rx Data used space
+UINT32
+RxDataUsedSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 RxInf;
+  UINT32 UsedSpace;
+
+  // Get the amount of used space from information register
+  RxInf = Lan9118MmioRead32 (LAN9118_RX_FIFO_INF);
+  UsedSpace = (RxInf & RXFIFOINF_RXDUSED_MASK);
+
+  return UsedSpace; // Value in bytes (rounded up to nearest DWORD)
+}
+
+// Check Rx Status used space
+UINT32
+RxStatusUsedSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 RxInf;
+  UINT32 UsedSpace;
+
+  // Get the amount of used space from information register
+  RxInf = Lan9118MmioRead32 (LAN9118_RX_FIFO_INF);
+  UsedSpace = (RxInf & RXFIFOINF_RXSUSED_MASK) >> 16;
+
+  return UsedSpace << 2; // Value in bytes
+}
+
+
+// Change the allocation of FIFOs
+EFI_STATUS
+ChangeFifoAllocation (
+  IN      UINT32 Flags,
+  IN  OUT UINTN  *TxDataSize    OPTIONAL,
+  IN  OUT UINTN  *RxDataSize    OPTIONAL,
+  IN  OUT UINT32 *TxStatusSize  OPTIONAL,
+  IN  OUT UINT32 *RxStatusSize  OPTIONAL,
+  IN  OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  )
+{
+  UINT32 HwConf;
+  UINT32 TxFifoOption;
+
+  // Check that desired sizes don't exceed limits
+  if (*TxDataSize > TX_FIFO_MAX_SIZE)
+    return EFI_INVALID_PARAMETER;
+
+#if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE)
+  if (*RxDataSize > RX_FIFO_MAX_SIZE) {
+    return EFI_INVALID_PARAMETER;
+  }
+#endif
+
+  if (Flags & ALLOC_USE_DEFAULT) {
+    return EFI_SUCCESS;
+  }
+
+  // If we use the FIFOs (always use this first)
+  if (Flags & ALLOC_USE_FIFOS) {
+    // Read the current value of allocation
+    HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG);
+    TxFifoOption = (HwConf >> 16) & 0xF;
+
+    // Choose the correct size (always use larger than requested if possible)
+    if (*TxDataSize < TX_FIFO_MIN_SIZE) {
+      *TxDataSize = TX_FIFO_MIN_SIZE;
+      *RxDataSize = 13440;
+      *RxStatusSize = 896;
+      TxFifoOption = 2;
+    } else if ((*TxDataSize > TX_FIFO_MIN_SIZE) && (*TxDataSize <= 2560)) {
+      *TxDataSize = 2560;
+      *RxDataSize = 12480;
+      *RxStatusSize = 832;
+      TxFifoOption = 3;
+    } else if ((*TxDataSize > 2560) && (*TxDataSize <= 3584)) {
+      *TxDataSize = 3584;
+      *RxDataSize = 11520;
+      *RxStatusSize = 768;
+      TxFifoOption = 4;
+    } else if ((*TxDataSize > 3584) && (*TxDataSize <= 4608)) { // default option
+      *TxDataSize = 4608;
+      *RxDataSize = 10560;
+      *RxStatusSize = 704;
+      TxFifoOption = 5;
+    } else if ((*TxDataSize > 4608) && (*TxDataSize <= 5632)) {
+      *TxDataSize = 5632;
+      *RxDataSize = 9600;
+      *RxStatusSize = 640;
+      TxFifoOption = 6;
+    } else if ((*TxDataSize > 5632) && (*TxDataSize <= 6656)) {
+      *TxDataSize = 6656;
+      *RxDataSize = 8640;
+      *RxStatusSize = 576;
+      TxFifoOption = 7;
+    } else if ((*TxDataSize > 6656) && (*TxDataSize <= 7680)) {
+      *TxDataSize = 7680;
+      *RxDataSize = 7680;
+      *RxStatusSize = 512;
+      TxFifoOption = 8;
+    } else if ((*TxDataSize > 7680) && (*TxDataSize <= 8704)) {
+      *TxDataSize = 8704;
+      *RxDataSize = 6720;
+      *RxStatusSize = 448;
+      TxFifoOption = 9;
+    } else if ((*TxDataSize > 8704) && (*TxDataSize <= 9728)) {
+      *TxDataSize = 9728;
+      *RxDataSize = 5760;
+      *RxStatusSize = 384;
+      TxFifoOption = 10;
+    } else if ((*TxDataSize > 9728) && (*TxDataSize <= 10752)) {
+      *TxDataSize = 10752;
+      *RxDataSize = 4800;
+      *RxStatusSize = 320;
+      TxFifoOption = 11;
+    } else if ((*TxDataSize > 10752) && (*TxDataSize <= 11776)) {
+      *TxDataSize = 11776;
+      *RxDataSize = 3840;
+      *RxStatusSize = 256;
+      TxFifoOption = 12;
+    } else if ((*TxDataSize > 11776) && (*TxDataSize <= 12800)) {
+      *TxDataSize = 12800;
+      *RxDataSize = 2880;
+      *RxStatusSize = 192;
+      TxFifoOption = 13;
+    } else if ((*TxDataSize > 12800) && (*TxDataSize <= 13824)) {
+      *TxDataSize = 13824;
+      *RxDataSize = 1920;
+      *RxStatusSize = 128;
+      TxFifoOption = 14;
+    }
+  } else {
+    ASSERT(0); // Untested code path
+    HwConf = 0;
+    TxFifoOption = 0;
+  }
+
+  // Do we need DMA?
+  if (Flags & ALLOC_USE_DMA) {
+    return EFI_UNSUPPORTED; // Unsupported as of now
+  }
+  // Clear and assign the new size option
+  HwConf &= ~(0xF0000);
+  HwConf |= ((TxFifoOption & 0xF) << 16);
+  Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf);
+
+  return EFI_SUCCESS;
+}

+ 283 - 0
Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h

@@ -0,0 +1,283 @@
+/** @file
+*
+*  WARNING:
+*  This driver fails to follow the UEFI driver model without a good
+*  reason, and only remains in the tree because it is still used by
+*  a small number of platforms. It will be removed when no longer used.
+*  New platforms should not use it, and no one should use this as
+*  reference code for developing new drivers.
+*
+*  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef __LAN9118_DXE_UTIL_H__
+#define __LAN9118_DXE_UTIL_H__
+
+// Most common CRC32 Polynomial for little endian machines
+#define CRC_POLYNOMIAL               0xEDB88320
+
+/**
+  This internal function reverses bits for 32bit data.
+
+  @param  Value                 The data to be reversed.
+
+  @return                       Data reversed.
+
+**/
+UINT32
+ReverseBits (
+  UINT32  Value
+  );
+
+// Create an Ethernet CRC
+UINT32
+GenEtherCrc32 (
+  IN    EFI_MAC_ADDRESS *Mac,
+  IN    UINT32 AddrLen
+  );
+
+UINT32
+Lan9118RawMmioRead32(
+  UINTN Address,
+  UINTN Delay
+  );
+#define Lan9118MmioRead32(a) \
+	Lan9118RawMmioRead32(a, a ## _RD_DELAY)
+
+UINT32
+Lan9118RawMmioWrite32(
+  UINTN Address,
+  UINT32 Value,
+  UINTN Delay
+  );
+#define Lan9118MmioWrite32(a, v) \
+	Lan9118RawMmioWrite32(a, v, a ## _WR_DELAY)
+
+/* ------------------ MAC CSR Access ------------------- */
+
+// Read from MAC indirect registers
+UINT32
+IndirectMACRead32 (
+  UINT32 Index
+  );
+
+
+// Write to indirect registers
+UINT32
+IndirectMACWrite32 (
+  UINT32 Index,
+  UINT32 Value
+  );
+
+
+/* --------------- PHY Registers Access ---------------- */
+
+// Read from MII register (PHY Access)
+UINT32
+IndirectPHYRead32(
+  UINT32 Index
+  );
+
+
+// Write to the MII register (PHY Access)
+UINT32
+IndirectPHYWrite32(
+  UINT32 Index,
+  UINT32 Value
+  );
+
+/* ---------------- EEPROM Operations ------------------ */
+
+// Read from EEPROM memory
+UINT32
+IndirectEEPROMRead32 (
+  UINT32 Index
+  );
+
+// Write to EEPROM memory
+UINT32
+IndirectEEPROMWrite32 (
+  UINT32 Index,
+  UINT32 Value
+  );
+
+/* ---------------- General Operations ----------------- */
+
+VOID
+Lan9118SetMacAddress (
+  EFI_MAC_ADDRESS             *Mac,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Initialise the LAN9118
+EFI_STATUS
+Lan9118Initialize (
+  IN  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Flags for software reset
+#define SOFT_RESET_CHECK_MAC_ADDR_LOAD                  BIT0
+#define SOFT_RESET_CLEAR_INT                            BIT1
+#define SOFT_RESET_SELF_TEST                            BIT2
+
+// Perform software reset on the LAN9118
+EFI_STATUS
+SoftReset (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Flags for PHY reset
+#define PHY_RESET_PMT                                   BIT0
+#define PHY_RESET_BCR                                   BIT1
+#define PHY_SOFT_RESET_CLEAR_INT                        BIT2
+
+// Perform PHY software reset
+EFI_STATUS
+PhySoftReset (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Flags for Hardware configuration
+#define HW_CONF_USE_LEDS                                BIT0
+
+// Configure hardware for LAN9118
+EFI_STATUS
+ConfigureHardware (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Configure flow control
+EFI_STATUS
+ConfigureFlow (
+  UINT32 Flags,
+  UINT32 HighTrig,
+  UINT32 LowTrig,
+  UINT32 BPDuration,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Flags for auto negotiation
+#define AUTO_NEGOTIATE_COLLISION_TEST         BIT0
+#define AUTO_NEGOTIATE_ADVERTISE_ALL          BIT1
+
+// Do auto-negotiation
+EFI_STATUS
+AutoNegotiate (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Check the Link Status and take appropriate action
+EFI_STATUS
+CheckLinkStatus (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Stop transmitter flags
+#define STOP_TX_MAC                       BIT0
+#define STOP_TX_CFG                       BIT1
+#define STOP_TX_CLEAR                     BIT2
+
+// Stop the transmitter
+EFI_STATUS
+StopTx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Stop receiver flags
+#define STOP_RX_CLEAR                     BIT0
+
+// Stop the receiver
+EFI_STATUS
+StopRx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Start transmitter flags
+#define START_TX_MAC                      BIT0
+#define START_TX_CFG                      BIT1
+#define START_TX_CLEAR                    BIT2
+
+// Start the transmitter
+EFI_STATUS
+StartTx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Stop receiver flags
+#define START_RX_CLEAR                     BIT0
+
+// Start the receiver
+EFI_STATUS
+StartRx (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Check Tx Data available space
+UINT32
+TxDataFreeSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Check Tx Status used space
+UINT32
+TxStatusUsedSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Check Rx Data used space
+UINT32
+RxDataUsedSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+// Check Rx Status used space
+UINT32
+RxStatusUsedSpace (
+  UINT32 Flags,
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+
+// Flags for FIFO allocation
+#define ALLOC_USE_DEFAULT                 BIT0
+#define ALLOC_USE_FIFOS                   BIT1
+#define ALLOC_USE_DMA                     BIT2
+
+// FIFO min and max sizes
+#define TX_FIFO_MIN_SIZE            0x00000600
+#define TX_FIFO_MAX_SIZE            0x00003600
+//#define RX_FIFO_MIN_SIZE
+//#define RX_FIFO_MAX_SIZE
+
+// Change the allocation of FIFOs
+EFI_STATUS
+ChangeFifoAllocation (
+  IN      UINT32 Flags,
+  IN  OUT UINTN  *TxDataSize    OPTIONAL,
+  IN  OUT UINTN  *RxDataSize    OPTIONAL,
+  IN  OUT UINT32 *TxStatusSize  OPTIONAL,
+  IN  OUT UINT32 *RxStatusSize  OPTIONAL,
+  IN  OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+  );
+
+VOID
+Lan9118ReadMacAddress (
+  OUT EFI_MAC_ADDRESS *Mac
+  );
+
+#endif // __LAN9118_DXE_UTIL_H__