From patchwork Mon Oct 7 19:39:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Reece R. Pollack" X-Patchwork-Id: 20872 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vb0-f70.google.com (mail-vb0-f70.google.com [209.85.212.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 414B024697 for ; Mon, 7 Oct 2013 19:40:37 +0000 (UTC) Received: by mail-vb0-f70.google.com with SMTP id h10sf14823184vbh.5 for ; Mon, 07 Oct 2013 12:40:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe:content-type; bh=lNRBbkciC52fJrvoDV0ocdwUsp1T/oxDHRVb0WAYVtk=; b=fhB6Xn5ctRLbjM4H4+rlJV8DK4VvXkyInffoAk7Imz8zs3Gyg0CsoO6EPuK5XXTAHi cfCv9Su7x2SWKmMNHfavocXs9xMJz5kZeVbPaR4Bm9RpD9kZGm2YxqXPaKonl0f50Trq 8H1cpDdvgLWwxYuqPTSGe7Mh12BLXSB6JZ3YUW/SOFqLovF7IXrKy1ocePJa4a+J1C8G /zsFTQDizRoClHC3OL6ylU4NwkvMse3HsxNXUc69S5KABaq2A9+PxkFlM+m+LY3qBKOp B83y4xhYbSbCXLTWOj/1Za7frnw5v//CqjDukw5gcNup9pdEddFutXYghyQGs/C1Iria Amvg== X-Received: by 10.236.129.194 with SMTP id h42mr30771852yhi.11.1381174837096; Mon, 07 Oct 2013 12:40:37 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.30.37 with SMTP id p5ls517977qeh.51.gmail; Mon, 07 Oct 2013 12:40:37 -0700 (PDT) X-Received: by 10.52.230.102 with SMTP id sx6mr23392670vdc.15.1381174836968; Mon, 07 Oct 2013 12:40:36 -0700 (PDT) Received: from mail-vb0-f49.google.com (mail-vb0-f49.google.com [209.85.212.49]) by mx.google.com with ESMTPS id nr7si8182456vec.27.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 07 Oct 2013 12:40:36 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.49 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.49; Received: by mail-vb0-f49.google.com with SMTP id w16so3652288vbb.36 for ; Mon, 07 Oct 2013 12:40:36 -0700 (PDT) X-Gm-Message-State: ALoCoQmSBYjEqO/MmIspuO5ag5MZPtSAUTZEyRwIZlO2SewW/tB9rKXTXwFcWBdFV3pfseTnMT7/ X-Received: by 10.220.13.20 with SMTP id z20mr28005919vcz.0.1381174836479; Mon, 07 Oct 2013 12:40:36 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp149558vcz; Mon, 7 Oct 2013 12:40:35 -0700 (PDT) X-Received: by 10.60.96.169 with SMTP id dt9mr47428964oeb.27.1381174832297; Mon, 07 Oct 2013 12:40:32 -0700 (PDT) Received: from devils.ext.ti.com (devils.ext.ti.com. [198.47.26.153]) by mx.google.com with ESMTPS id cx4si22561300oeb.45.1969.12.31.16.00.00 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 07 Oct 2013 12:40:32 -0700 (PDT) Received-SPF: neutral (google.com: 198.47.26.153 is neither permitted nor denied by best guess record for domain of x0183204@udx0183204) client-ip=198.47.26.153; Received: from dflxv15.itg.ti.com ([128.247.5.124]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id r97JeV0b015703; Mon, 7 Oct 2013 14:40:31 -0500 Received: from DFLE73.ent.ti.com (dfle73.ent.ti.com [128.247.5.110]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id r97JeVar016850; Mon, 7 Oct 2013 14:40:31 -0500 Received: from dlep33.itg.ti.com (157.170.170.75) by DFLE73.ent.ti.com (128.247.5.110) with Microsoft SMTP Server id 14.2.342.3; Mon, 7 Oct 2013 14:40:31 -0500 Received: from udx0183204 (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep33.itg.ti.com (8.14.3/8.13.8) with ESMTP id r97JeUqY012428; Mon, 7 Oct 2013 14:40:31 -0500 Received: from x0183204 by udx0183204 with local (Exim 4.80) (envelope-from ) id 1VTGfO-0004Up-LJ; Mon, 07 Oct 2013 15:40:30 -0400 From: "Reece R. Pollack" To: CC: "Reece R. Pollack" , Subject: [PATCH 04/10] ArmPlatformPkg: Added LAN9118 Dxe driver Date: Mon, 7 Oct 2013 15:39:55 -0400 Message-ID: <1381174801-17221-5-git-send-email-reece.pollack@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1381174801-17221-1-git-send-email-reece.pollack@linaro.org> References: <1381174801-17221-1-git-send-email-reece.pollack@linaro.org> MIME-Version: 1.0 X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: reece.pollack@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.49 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: "Reece R. Pollack" Added a driver for the SMSC LAN9118 Ethernet controller, used on the baseboard of the Versatile Express reference system. Note that per-CPU support patches are committed in their respective branches rather than here. Signed-off-by: Reece R. Pollack --- ArmPlatformPkg/ArmPlatformPkg.dec | 5 + ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc | 1 + ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c | 2592 +++++++++++++++++++++ ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf | 55 + ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h | 325 +++ 5 files changed, 2978 insertions(+) create mode 100644 ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c create mode 100644 ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf create mode 100644 ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec index 3358225..2c4f888 100644 --- a/ArmPlatformPkg/ArmPlatformPkg.dec +++ b/ArmPlatformPkg/ArmPlatformPkg.dec @@ -139,6 +139,11 @@ gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L""|VOID*|0x0000001B gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths|L""|VOID*|0x0000001C + # + # LAN9118 Ethernet Driver PCDs + # + gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x000000FF + [PcdsFixedAtBuild.ARM] # Stack for CPU Cores in Secure Monitor Mode gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase|0|UINT32|0x00000007 diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc index cb04012..fe0604b 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc @@ -366,4 +366,5 @@ MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf + ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c new file mode 100644 index 0000000..9239132 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c @@ -0,0 +1,2592 @@ +/** @file +* +* Copyright (c) 2012-2013, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include + +// Protocols used by this driver +#include +#include +#include +#include + +// Libraries used by this driver +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LAN9118DxeHw.h" + +#define LAN9118_TPL TPL_CALLBACK + +// Most common CRC32 Polynomial for little endian machines +#define CRC_POLYNOMIAL 0xEDB88320 + +/* ------------------ Debug Functions ------------------ */ + +// Flags for printing register values +#define PRINT_REGISTERS_MAC BIT0 +#define PRINT_REGISTERS_PHY BIT1 +#define PRINT_REGISTERS_ALL (BIT0 | BIT1) +#define PRINT_REGISTERS_SEL_MAC BIT12 +#define PRINT_REGISTERS_SEL_PHY BIT13 + + +/* ------------------ MAC CSR Access ------------------- */ + + +// Flags for software reset +#define SOFT_RESET_CHECK_MAC_ADDR_LOAD BIT0 +#define SOFT_RESET_CLEAR_INT BIT1 +#define SOFT_RESET_SELF_TEST BIT2 + +// Flags for PHY reset +#define PHY_RESET_PMT BIT0 +#define PHY_RESET_BCR BIT1 +#define PHY_RESET_CHECK_LINK BIT2 +#define PHY_SOFT_RESET_CLEAR_INT BIT3 + +// Flags for Hardware configuration +#define HW_CONF_USE_LEDS BIT0 + +// Stop transmitter flags +#define STOP_TX_MAC BIT0 +#define STOP_TX_CFG BIT1 +#define STOP_TX_CLEAR BIT2 + +// Stop receiver flags +#define STOP_RX_CLEAR BIT0 + +// Start transmitter flags +#define START_TX_MAC BIT0 +#define START_TX_CFG BIT1 +#define START_TX_CLEAR BIT2 + +// Stop receiver flags +#define START_RX_CLEAR BIT0 + +// Flags for FIFO allocation +#define ALLOC_USE_DEFAULT 0x00000001 +#define ALLOC_USE_FIFOS 0x00000002 +#define ALLOC_USE_DMA 0x00000004 + +// 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 +#define LAN9118_STALL 2 + +#define LAN9118_DEFAULT_MAC_ADDRL 0x00F70200 +#define LAN9118_DEFAULT_MAC_ADDRH 0x00009040 + +/*--------------------------------------------------------------------------------------------------------------------- + + LAN9118 Information Structure + +---------------------------------------------------------------------------------------------------------------------*/ + +#define LAN9118_TX_CACHE_DEPTH 16 + +// TxCache management structure +typedef struct { + VOID *buffadr; + UINTN refcount; +} LAN9118_TX_CACHE; + +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; + + // Transmit Completion Cache + VOID *TxCache[LAN9118_TX_CACHE_DEPTH]; +} LAN9118_DRIVER; + +#define LAN9118_SIGNATURE SIGNATURE_32('l', 'a', 'n', '9') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN9118_DRIVER, Snp, LAN9118_SIGNATURE) + + +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 + } +}; + +/** + 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) + return ReverseBits (Remainder); +} + +#ifndef MDEPKG_NDEBUG +STATIC CONST CHAR16 *Mac2Str (EFI_MAC_ADDRESS *Mac) +{ + static CHAR16 MacStr[18]; + + if (Mac == NULL) { + return L""; + } + + UnicodeSPrintAsciiFormat (MacStr, sizeof(MacStr), + "%02x:%02x:%02x:%02x:%02x:%02x", + Mac->Addr[0], Mac->Addr[1], Mac->Addr[2], + Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]); + return MacStr; +} +#endif + +// 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 ((MmioRead32 (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 + MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Now read from data register to get read value + return MmioRead32 (LAN9118_MAC_CSR_DATA); +} + +// 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 ((MmioRead32 (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 = MmioWrite32 (LAN9118_MAC_CSR_DATA, Value); + + // Write the config to the register + MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (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; +} + + +// DEBUG: Print all register values +UINT32 +PrintRegisters ( + IN UINT32 Flags, + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 Count; + UINT32 RegValue; + + // Select MAC register if defined (5 LSBs select register) + if (Flags & PRINT_REGISTERS_SEL_MAC) { + RegValue = IndirectMACRead32 (Flags & 0x1FF); + DEBUG((EFI_D_ERROR, "MAC Register %02x:\thex: 0x%08x\n",Flags & 0x1FF, RegValue)); + return 0; + } + + // Select PHY register if defined (5 LSBs select register) + if (Flags & PRINT_REGISTERS_SEL_PHY) { + RegValue = IndirectPHYRead32 (Flags & 0x1FF); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n",Flags & 0x1FF, RegValue)); + return 0; + } + + // Loop through all MAC registers + if (Flags & PRINT_REGISTERS_MAC) { + for (Count = 1;Count <= 0xC;Count++) { + RegValue = IndirectMACRead32 (Count); + DEBUG((EFI_D_ERROR, "MAC Register %02x:\thex: 0x%08x\n", Count, RegValue)); + } + } + + // Print PHY registers + if (Flags & PRINT_REGISTERS_PHY) { + for (Count = 0;Count <= 6;Count ++) { + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + } + + Count = 17; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 18; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 27; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 29; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 30; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + + Count = 31; + RegValue = IndirectPHYRead32 (Count); + DEBUG((EFI_D_ERROR, "PHY Register %d:\thex: 0x%08x\n", Count, RegValue)); + } + + return 0; +} + + +/* ---------------- EEPROM Operations ------------------ */ + + +// Function to read from EEPROM memory +UINT32 +IndirectEEPROMRead32 ( + UINT32 Index +) +{ + // Eeprom command + UINT32 EepromCmd = 0;//= MmioRead32 (LAN9118_E2P_CMD); + + // Set the busy bit to ensure read will occur + EepromCmd |= ((UINT32)1 << 31); + + // Set the EEPROM command to read(0b000) + EepromCmd &= ~(0x70000000); // Clear the command first + EepromCmd |= (0 << 28); // Not necessary, but here for clarity + + // Set the index to access desired EEPROM memory location + EepromCmd |= (Index & 0xF); + + // Write to Eeprom command register + MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + gBS->Stall (LAN9118_STALL); + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (MmioRead32 (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 (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Finally read the value + return MmioRead32 (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 = MmioRead32 (LAN9118_E2P_CMD); + + // Set the busy bit to ensure read will occur + EepromCmd |= ((UINT32)1 << 31); + + // Set the EEPROM command to write(0b011) + EepromCmd &= ~(0x70000000); // 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 = MmioWrite32 (LAN9118_E2P_DATA, Value); + + // Write to Eeprom command register + MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + gBS->Stall (LAN9118_STALL); + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (MmioRead32 (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 (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + return ValueWritten; +} + +/* ---------------- General Operations ----------------- */ + + +// 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 = MmioRead32 (LAN9118_TX_CFG); + TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + + // 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 = MmioRead32 (LAN9118_TX_CFG); + + if (TxCfg & TXCFG_TX_ON) { + TxCfg |= TXCFG_STOP_TX; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + + // Wait for Tx to finish transmitting + while (MmioRead32 (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 = MmioRead32 (LAN9118_RX_CFG); + RxCfg |= RXCFG_RX_DUMP; + MmioWrite32 (LAN9118_RX_CFG, RxCfg); + gBS->Stall (LAN9118_STALL); + + while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + 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; + + // 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 = MmioRead32 (LAN9118_HW_CFG); + HwConf |= HWCFG_SRST | HWCFG_MBO; + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Write the configuration + MmioWrite32 (LAN9118_HW_CFG, HwConf); + gBS->Stall (LAN9118_STALL); + + // Wait for reset to complete + ResetTime = 1000; + while (MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) { + + gBS->Stall (LAN9118_STALL); + + // If time taken exceeds 1000us, then there was an error condition + if (--ResetTime == 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + return EFI_TIMEOUT; + } + } + + // Check that MAC Address loaded successfully (if required) + if (Flags & SOFT_RESET_CHECK_MAC_ADDR_LOAD) { + if ((MmioRead32 (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" + " Using hard-coded MAC Address.\n")); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, LAN9118_DEFAULT_MAC_ADDRL); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, LAN9118_DEFAULT_MAC_ADDRH); + } + } + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Clear and acknowledge all interrupts + if (Flags & SOFT_RESET_CLEAR_INT) { + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + // Do self tests here? + if (Flags & SOFT_RESET_SELF_TEST) { + + } + + return EFI_SUCCESS; +} + + +// Check the Link Status and take appropriate action +BOOLEAN +CheckLinkStatus ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PhyBStatus; + + // Get the PHY Status + PhyBStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + + return (PhyBStatus & PHYSTS_LINK_STS) != 0; +} + +// Perform PHY software reset +INT32 +PhySoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PmtCtrl = 0; + UINT32 LinkTo = 0; + + // PMT PHY reset takes precedence over BCR + if (Flags & PHY_RESET_PMT) { + PmtCtrl = MmioRead32 (LAN9118_PMT_CTRL); + PmtCtrl |= MPTCTRL_PHY_RST; + MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl); + + // Wait for completion + while (MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) { + gBS->Stall (LAN9118_STALL); + } + // PHY Basic Control Register reset + } else if (Flags & PHY_RESET_PMT) { + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET); + + // Wait for completion + while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) { + gBS->Stall (LAN9118_STALL); + } + } + + // Check the link status + if (Flags & PHY_RESET_CHECK_LINK) { + LinkTo = 100000; // 2 second (could be 50% more) + while (!CheckLinkStatus(Snp) && (LinkTo > 0)) { + gBS->Stall (LAN9118_STALL); + LinkTo--; + } + + // Timed out + if (LinkTo <= 0) { + return -1; + } + } + + // Clear and acknowledge all interrupts + if (Flags & PHY_SOFT_RESET_CLEAR_INT) { + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + return 0; +} + + +// 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 = MmioRead32 (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 + MmioWrite32 (LAN9118_GPIO_CFG, GpioConf); + gBS->Stall (LAN9118_STALL); + } + + 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 ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINTN Retries; + UINT32 PhyControl; + UINT32 PhyStatus; + UINT32 PhyAdvert; + + // First check that auto-negotiation is supported + PhyStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) { + return EFI_SUCCESS; + } + + // Translate capabilities to advertise + PhyAdvert = PHYANA_CSMA; + + if ((PhyStatus & PHYSTS_10BASET_HDPLX) != 0) { + PhyAdvert |= PHYANA_10BASET; + } + if ((PhyStatus & PHYSTS_10BASET_FDPLX) != 0) { + PhyAdvert |= PHYANA_10BASETFD; + } + if ((PhyStatus & PHYSTS_100BASETX_HDPLX) != 0) { + PhyAdvert |= PHYANA_100BASETX; + } + if ((PhyStatus & PHYSTS_100BASETX_FDPLX) != 0) { + PhyAdvert |= PHYANA_100BASETXFD; + } + if ((PhyStatus & PHYSTS_100BASE_T4) != 0) { + PhyAdvert |= PHYANA_100BASET4; + } + + // Write the features + IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert); + + // Restart Auto-Negotiation + PhyControl = IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL); + PhyControl &= ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE); + PhyControl |= PHYCR_AUTO_EN | PHYCR_RST_AUTO; + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl); + + // Wait up to 2 seconds for the process to complete + Retries = 2000000; + while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0) { + if (--Retries == 0) { + DEBUG((EFI_D_ERROR, "LAN9118: PHY auto-negotiation timed-out\n")); + return EFI_TIMEOUT; + } + gBS->Stall (100); + } + + return EFI_SUCCESS; +} + +// Start the transmitter +EFI_STATUS +StartTx ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + LAN9118_DRIVER *LanDriver; + UINT32 MacCsr; + UINT32 TxCfg; + + // Clear the transmitter + TxCfg = MmioRead32 (LAN9118_TX_CFG); + TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + + // Clear the TxCache + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + ZeroMem (LanDriver->TxCache, sizeof(LanDriver->TxCache)); + + // Start the MAC + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + gBS->Stall (LAN9118_STALL); + if ((MacCsr & MACCR_TX_EN) == 0) { + MacCsr |= MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + gBS->Stall (LAN9118_STALL); + } + + // Enable the transmitter + TxCfg = MmioRead32 (LAN9118_TX_CFG); + gBS->Stall (LAN9118_STALL); + if ((TxCfg & TXCFG_TX_ON) == 0) { + TxCfg |= TXCFG_TX_ON; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + + // 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 = MmioRead32 (LAN9118_RX_CFG); + RxCfg |= RXCFG_RX_DUMP; + MmioWrite32 (LAN9118_RX_CFG, RxCfg); + gBS->Stall (LAN9118_STALL); + + while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + MacCsr |= MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + gBS->Stall (LAN9118_STALL); + } + + return EFI_SUCCESS; +} + +// Check Tx Data available space +UINT32 +TxDataFreeSpace ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 FreeSpace; + + // Get the amount of free space from information register + TxInf = MmioRead32 (LAN9118_TX_FIFO_INF); + FreeSpace = (TxInf & TXFIFOINF_TDFREE_MASK); + + return FreeSpace; // Value in bytes +} + +// Check Tx Status used space +UINT32 +TxStatusUsedSpace ( + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + TxInf = MmioRead32 (LAN9118_TX_FIFO_INF); + UsedSpace = (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16; + + return UsedSpace; +} + +// 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 = MmioRead32 (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 = MmioRead32 (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 = MmioRead32 (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); + MmioWrite32 (LAN9118_HW_CFG, HwConf); + gBS->Stall (LAN9118_STALL); + + return EFI_SUCCESS; +} + +/*--------------------------------------------------------------------------------------------------------------------- + + Utility functions + +---------------------------------------------------------------------------------------------------------------------*/ + +EFI_MAC_ADDRESS +GetCurrentMacAddress ( + VOID + ) +{ + UINT32 MacAddrHighValue; + UINT32 MacAddrLowValue; + EFI_MAC_ADDRESS MacAddress; + + // 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; + + DEBUG((DEBUG_NET, "GetCurrentMacAddress() = %s\n", Mac2Str (&MacAddress))); + return MacAddress; +} + +#define ReturnUnlock(s) do { Status = (s); goto exit_unlock; } while(0) + +/* +** 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 + ) +{ + EFI_MAC_ADDRESS *Mac; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check state + if ((Snp->Mode->State == EfiSimpleNetworkStarted) || (Snp->Mode->State == EfiSimpleNetworkInitialized)) { + ReturnUnlock (EFI_ALREADY_STARTED); + } else if (Snp->Mode->State == EfiSimpleNetworkMaxState) { + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Attempt to wake-up the device if it is in a lower power state + if (((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12) != 0) { + DEBUG((DEBUG_NET, "Waking from reduced power state.\n")); + MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF); + gBS->Stall (LAN9118_STALL); + } + + // Check that device is active + while ((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) == 0); + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + Mac = &Snp->Mode->CurrentAddress; + DEBUG((DEBUG_NET, "Using current address %s\n", Mac2Str(Mac))); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, + (Mac->Addr[3] << 24) | + (Mac->Addr[2] << 16) | + (Mac->Addr[1] << 8) | + Mac->Addr[0] + ); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, + (Mac->Addr[5] << 8) | + Mac->Addr[4] + ); + + // Clear and acknowledge interrupts + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + + // Change state + Snp->Mode->State = EfiSimpleNetworkStarted; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Stop() function +** +*/ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check state of the driver + if ((Snp->Mode->State == EfiSimpleNetworkStopped) || (Snp->Mode->State == EfiSimpleNetworkMaxState)) { + ReturnUnlock (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: + ReturnUnlock (EFI_DEVICE_ERROR); + } + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +// Allocated receive and transmit buffers +STATIC UINT32 gTxBuffer = 0; + +// Buffer sizes +STATIC UINT32 gTxDataSize = 0; +STATIC UINT32 gTxStatusSize = 0; +STATIC UINT32 gRxDataSize = 0; +STATIC UINT32 gRxStatusSize = 0; + +/* +** UEFI Initialize() function +** +*/ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN RxBufferSize OPTIONAL, + IN UINTN TxBufferSize OPTIONAL + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 PmConf; + INT32 AllocResult; + + // Initialize variables + // Global variables to hold tx and rx FIFO allocation + gTxBuffer = 0; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkInitialized) { + DEBUG((EFI_D_WARN, "LAN9118 Driver already initialized\n")); + ReturnUnlock (EFI_SUCCESS); + } else + if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "LAN9118 Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a PHY reset + if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + DEBUG((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n")); + ReturnUnlock (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")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Read the PM register + PmConf = MmioRead32 (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 + MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + gBS->Stall (LAN9118_STALL); + gBS->Stall (LAN9118_STALL); + + // Configure GPIO and HW + Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + // Assign the transmitter buffer size (default values) + gTxDataSize = 4608; + gTxStatusSize = 512; // this never changes + gRxDataSize = 10560; + gRxStatusSize = 704; + + // Check that a buff size was specified + if (TxBufferSize) { + AllocResult = ChangeFifoAllocation ( + ALLOC_USE_FIFOS, + &TxBufferSize, + &RxBufferSize, + &gTxStatusSize, + &gRxStatusSize, + Snp + ); + + if (AllocResult < 0) { + return EFI_OUT_OF_RESOURCES; + } + + gTxDataSize = gTxDataSize; + gTxStatusSize = gTxStatusSize; + gTxDataSize = TxBufferSize; + gRxDataSize = RxBufferSize; + } + + // Set the current MAC Address + Snp->Mode->CurrentAddress = GetCurrentMacAddress (); + + // Set the permanent MAC Address + Snp->Mode->PermanentAddress = Snp->Mode->CurrentAddress; + + // Do auto-negotiation if supported + Status = AutoNegotiate (Snp); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_WARN, "Lan9118: Auto Negotiation not supported.\n")); + } + + // Configure flow control depending on speed capabilities + Status = ConfigureFlow (0, 0, 0, 0, Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + // Enable the receiver and transmitter + Status = StartRx (0, Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + Status = StartTx (Snp); + if (EFI_ERROR(Status)) { + ReturnUnlock (Status); + } + + // Now acknowledge all interrupts + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + + // Declare the driver as initialized + Snp->Mode->State = EfiSimpleNetworkInitialized; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Reset () function +** +*/ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Verification + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 PmConf; + UINT32 HwConf; + UINT32 ResetFlags; + + PmConf = 0; + HwConf = 0; + ResetFlags = 0; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // 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")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a PHY reset + if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + ReturnUnlock (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; + } + + if (SoftReset (ResetFlags, Snp) < 0) { + DEBUG((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Read the PM register + PmConf = MmioRead32 (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 + MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + gBS->Stall (LAN9118_STALL); + + // Check that a buffer size was specified in SnpInitialize + if (gTxBuffer != 0) { + HwConf = MmioRead32 (LAN9118_HW_CFG); // Read the HW register + HwConf &= ~((UINT32)0xF0000); // Clear buffer bits first + HwConf |= (gTxBuffer << 16); // assign size chosen in SnpInitialize + + MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf + gBS->Stall (LAN9118_STALL); + } + + // Enable the receiver and transmitter and clear their contents + StartRx (START_RX_CLEAR, Snp); + StartTx (Snp); + + // Now acknowledge all interrupts + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Shutdown () function +** +*/ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // 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")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Initiate a PHY reset + PhySoftReset (PHY_RESET_PMT, Snp); + + // Initiate a software reset + if (SoftReset (0, Snp) < 0) { + DEBUG((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI ReceiveFilters() function +** +*/ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN Reset, + IN UINTN NumMfilter OPTIONAL, + IN EFI_MAC_ADDRESS *Mfilter OPTIONAL + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 MacCSRValue; + UINT32 MultHashTableHigh; + UINT32 MultHashTableLow; + UINT32 Crc; + UINT8 BitToSelect; + UINT32 Count; + + MacCSRValue = 0; + MultHashTableHigh = 0; + MultHashTableLow = 0; + Crc = 0xFFFFFFFF; + BitToSelect = 0; + Count = 0; + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // If reset then clear the filter registers + if (Reset) { + Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, 0x00000000); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, 0x00000000); + } + + // Set the hash tables + if ((NumMfilter > 0) && (!Reset)) { + + // Read the Multicast High Hash Table + MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH); + + // Read the Multicast Low Hash Table + MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL); + + // Go through each filter address and set appropriate bits on hash table + for (Count = 0; Count < NumMfilter; Count++) { + + // Generate a 32-bit CRC for Ethernet + Crc = GenEtherCrc32 (&Mfilter[Count],6); + //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired + + // Get the most significant 6 bits to index hash registers + BitToSelect = (Crc >> 26) & 0x3F; + + // Select hashlow register if MSB is not set + if ((BitToSelect & 0x20) == 0) { + MultHashTableLow |= (1 << BitToSelect); + } else { + MultHashTableHigh |= (1 << (BitToSelect & 0x1F)); + } + } + + // Write the desired hash + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh); + } + + // Read MAC controller + MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + // Set the options for the MAC_CSR + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + StartRx (0, Snp); + DEBUG((DEBUG_NET, "Allowing Unicast Frame Reception\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + StopRx (0, Snp); + DEBUG((DEBUG_NET, "Disabling Unicast Frame Reception\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + MacCSRValue |= MACCR_HPFILT; + DEBUG((DEBUG_NET, "Allowing Multicast Frame Reception\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + MacCSRValue &= ~MACCR_HPFILT; + DEBUG((DEBUG_NET, "Disabling Multicast Frame Reception\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { + MacCSRValue &= ~(MACCR_BCAST); + DEBUG((DEBUG_NET, "Allowing Broadcast Frame Reception\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { + MacCSRValue |= MACCR_BCAST; + DEBUG((DEBUG_NET, "Disabling Broadcast Frame Reception\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + MacCSRValue |= MACCR_PRMS; + DEBUG((DEBUG_NET, "Enabling Promiscuous Mode\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + MacCSRValue &= ~MACCR_PRMS; + DEBUG((DEBUG_NET, "Disabling Promiscuous Mode\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS); + DEBUG((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS); + DEBUG((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n")); + } + + // Write the options to the MAC_CSR + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue); + gBS->Stall (LAN9118_STALL); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI StationAddress() function +** +*/ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +) +{ + DEBUG((DEBUG_NET, "SnpStationAddress(%d, %s)\n", Reset, Mac2Str(NewMac))); + + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 Count; + UINT8 PermAddr[6]; + + Count = 0; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Get the Permanent MAC address if need reset + if (Reset) { + // Try using EEPROM first + if ((IndirectEEPROMRead32 (0) & 0xFF) == 0xA5) { + for (Count = 1; Count < 7; Count++) { + PermAddr[Count - 1] = IndirectEEPROMRead32 (Count); + } + + // Write address + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, (UINT32)((UINT32)PermAddr[0]) | ((UINT32)PermAddr[1] << 8) | ((UINT32)PermAddr[2] << 16) | ((UINT32)PermAddr[3] << 24)); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, (UINT32)((((UINT32)PermAddr[4]) | ((UINT32)PermAddr[5] << 8)) & 0xFFFF)); + } else { + // Otherwise make our own + DEBUG((EFI_D_WARN, "Warning: No valid EEPROM detected. Using a hard coded address.\n")); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, LAN9118_DEFAULT_MAC_ADDRL); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, LAN9118_DEFAULT_MAC_ADDRH); + } + + // Otherwise use the specified new MAC address + } else { + if (NewMac == NULL) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + + // Write address + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, (UINT32)((UINT32)NewMac->Addr[0]) | ((UINT32)NewMac->Addr[1] << 8) | ((UINT32)NewMac->Addr[2] << 16) | ((UINT32)NewMac->Addr[3] << 24)); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, (UINT32)((((UINT32)NewMac->Addr[4]) | ((UINT32)NewMac->Addr[5] << 8)) & 0xFFFF)); + } + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** 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_TPL SavedTpl; + EFI_STATUS Status; + + DEBUG((DEBUG_NET, "SnpStatistics()\n")); + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check pointless condition + if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) { + return EFI_SUCCESS; + } + + // Check the parameters + if ((StatSize == NULL) && (Statistics != NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Do a reset if required + if (Reset) { + ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + // Check buffer size + if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { + *StatSize = sizeof(EFI_NETWORK_STATISTICS); + ReturnUnlock (EFI_BUFFER_TOO_SMALL); + } + + // Fill in the statistics + CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + 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 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 + 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 ms 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 + 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 + ) +{ + LAN9118_DRIVER *LanDriver; + EFI_STATUS Status; + EFI_TPL SavedTpl; + UINT32 FifoInt; + UINT32 IntStatus; + BOOLEAN MediaPresent; + UINT32 TxStatus; + INTN TxCacheIndex; + + // Check preliminaries + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + ReturnUnlock (EFI_NOT_STARTED); + } + + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Set the transmit status available level + FifoInt = MmioRead32 (LAN9118_FIFO_INT); + + if ((FifoInt & 0x00FF0000) == 0) { + FifoInt |= (1 << 16); + MmioWrite32 (LAN9118_FIFO_INT, FifoInt); + } + + IntStatus = MmioRead32 (LAN9118_INT_STS); + if ((IntStatus & (INSTS_TXSTOP_INT | INSTS_RXSTOP_INT | INSTS_TXSO | INSTS_RWT | + INSTS_RXE | INSTS_TXE | INSTS_TDFO | INSTS_TDFA | INSTS_TSFF | + INSTS_TSFL | INSTS_RXDF_INT | INSTS_RSFF)) != 0) { + DEBUG((EFI_D_WARN, "IntStatus: %08x\n", IntStatus)); + } + + // Report interrupt status if IrqStat is not NULL + if (IrqStat != NULL) { + *IrqStat = 0; + + // Check for receive interrupt + if (IntStatus & INSTS_RSFL) { // Data moved from rx FIFO + *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL); + } + + // Check for transmit interrupt + if (IntStatus & INSTS_TSFL) { + *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL); + } + + // Check for software interrupt + if (IntStatus & INSTS_SW_INT) { + *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT); + } + } + + // Return the recycled transmit address + if ((TxBuff != NULL) && (TxStatusUsedSpace (Snp) > 0)) { + TxStatus = MmioRead32 (LAN9118_TX_STATUS); + + TxCacheIndex = ((INTN)(TxStatus >> 16) & 0xffff) - 1; + if ((0 <= TxCacheIndex) && (TxCacheIndex < LAN9118_TX_CACHE_DEPTH)) { + if (LanDriver->TxCache[TxCacheIndex] != NULL) { + *TxBuff = LanDriver->TxCache[TxCacheIndex]; + LanDriver->TxCache[TxCacheIndex] = NULL; + } else { + *TxBuff = NULL; + } + } else { + *TxBuff = NULL; + } + + // Check Tx Status (we ignore TXSTATUS_NO_CA has it might happen in Full Duplex) + if (((TxStatus & TXSTATUS_ES) != 0) && ((TxStatus & TXSTATUS_NO_CA) == 0)) { + DEBUG((EFI_D_WARN, "Warning: There was an error transmitting TxStatus=0x%X:\n", TxStatus)); + if (TxStatus & TXSTATUS_DEF) { + DEBUG((EFI_D_WARN, "- Packet tx was deferred\n")); + } + if (TxStatus & TXSTATUS_EDEF) { + DEBUG((EFI_D_WARN, "- Tx ended because of excessive deferral\n")); + } + if (TxStatus & TXSTATUS_ECOLL) { + DEBUG((EFI_D_WARN, "- Tx ended because of Excessive Collisions\n")); + } + if (TxStatus & TXSTATUS_LCOLL) { + DEBUG((EFI_D_WARN, "- Packet Tx aborted after coll window of 64 bytes\n")); + } + if (TxStatus & TXSTATUS_LOST_CA) { + DEBUG((EFI_D_WARN, "- Lost carrier during Tx\n")); + } + } + } + + // Update the media status + MediaPresent = CheckLinkStatus (Snp); + if (MediaPresent != Snp->Mode->MediaPresent) { + DEBUG((EFI_D_WARN, "LAN9118: Link %s\n", MediaPresent ? L"up" : L"down")); + } + Snp->Mode->MediaPresent = MediaPresent; + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** 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; + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT32 TxFreeSpace; + UINT32 TxStatusSpace; + INT32 Count; + UINT32 CommandA; + UINT32 CommandB; + UINT16 LocalProtocol; + UINT32 *LocalData; + INTN TxCacheIndex; + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + TxCacheIndex = (-1); + + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + ReturnUnlock (EFI_NOT_STARTED); + } + + // Ensure header is correct size if non-zero + if (HdrSize) { + if (HdrSize != Snp->Mode->MediaHeaderSize) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + + if ((DstAddr == NULL) || (Protocol == NULL)) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + } + + // Before transmitting check the link status + if (!Snp->Mode->MediaPresent) { + ReturnUnlock (EFI_NOT_READY); + } + + // Find a free entry in the TxCache array + for (TxCacheIndex = LAN9118_TX_CACHE_DEPTH - 1; TxCacheIndex >= 0; --TxCacheIndex) { + if (LanDriver->TxCache[TxCacheIndex] == NULL) { + break; + } + } + if (TxCacheIndex < 0) { + ReturnUnlock (EFI_NOT_READY); + } + LanDriver->TxCache[TxCacheIndex] = Data; + + // Get DATA FIFO free space in bytes + TxFreeSpace = TxDataFreeSpace (Snp); + if (TxFreeSpace < BuffSize) { + ReturnUnlock (EFI_NOT_READY); + } + + // Get STATUS FIFO used space in DWORDS + TxStatusSpace = TxStatusUsedSpace (Snp); + if (TxStatusSpace > 125) { + ReturnUnlock (EFI_NOT_READY); + } + + // 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; + } + + 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(TxCacheIndex + 1) | TX_CMD_B_PACKET_LENGTH(BuffSize); + + // Write the commands first + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the destination address + MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[0]) | + (DstAddr->Addr[1] << 8) | + (DstAddr->Addr[2] << 16) | + (DstAddr->Addr[3] << 24) + ); + + MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[4]) | + (DstAddr->Addr[5] << 8) | + + // Write the Source Address + (SrcAddr->Addr[0] << 16) | + (SrcAddr->Addr[1] << 24) + ); + + MmioWrite32 (LAN9118_TX_DATA, + (SrcAddr->Addr[2]) | + (SrcAddr->Addr[3] << 8) | + (SrcAddr->Addr[4] << 16) | + (SrcAddr->Addr[5] << 24) + ); + + // Write the Protocol + MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS(LocalProtocol))); + + // Next buffer is the payload + CommandA = TX_CMD_A_COMPLETION_INT | TX_CMD_A_START_OFFSET(2) | + TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE(BuffSize - HdrSize); + + // Write the commands + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the payload + for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { + MmioWrite32 (LAN9118_TX_DATA,LocalData[Count + 3]); + } + + // Get STATUS FIFO used space in bytes + /*TxStatusSpace = TxStatusUsedSpace (0, Snp); + DEBUG((EFI_D_ERROR, "Status FIFO Size after write: %d\n",TxStatusSpace)); + + // Data written debug + DEBUG((EFI_D_ERROR, "Payload written: %d bytes",BuffSize - HdrSize)); + for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { + if ((Count % 6) == 0) + DEBUG((EFI_D_ERROR, "\n")); + DEBUG((DEBUG_NET, "0x%08X", NTOHL(LocalData[Count + 3]))); + } + DEBUG((EFI_D_ERROR, "\n")); + */ + + } else { + + // Format pointer + LocalData = (UINT32*) Data; + + // Create a buffer to pass to controller + CommandA = TX_CMD_A_COMPLETION_INT | TX_CMD_A_FIRST_SEGMENT | + TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE(BuffSize); + CommandB = TX_CMD_B_PACKET_TAG(TxCacheIndex + 1) | TX_CMD_B_PACKET_LENGTH(BuffSize); + + // Write the commands first + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write all the data + for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) { + MmioWrite32 (LAN9118_TX_DATA,LocalData[Count]); + } + + // Data written debug + /*DEBUG((EFI_D_ERROR, "Packet written:")); + for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) { + if ((Count % 6) == 0) + DEBUG((EFI_D_ERROR, "\n")); + DEBUG((DEBUG_NET, "0x%08X",LocalData[Count])); + }*/ + } + + LanDriver->Stats.TxTotalFrames += 1; + LanDriver->Stats.TxGoodFrames += 1; + TxCacheIndex = (-1); + Status = EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + if (TxCacheIndex >= 0) { + LanDriver->TxCache[TxCacheIndex] = NULL; + } + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** 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 + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + LAN9118_DRIVER *LanDriver; + UINT32 RxFifoStatus; + UINT32 NumPackets; + UINT32 RxDataUsed; + UINT32 RxStatusUsed; + UINT32 RxCfgValue; + UINT32 PLength; // Packet length + UINT32 ReadLimit; + UINT32 Count; + UINT32 Padding; + UINT32 *RawData; + EFI_MAC_ADDRESS Dst; + EFI_MAC_ADDRESS Src; + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl = gBS->RaiseTPL (LAN9118_TPL); + + // Check state + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + ReturnUnlock (EFI_NOT_STARTED); + } + + LanDriver = INSTANCE_FROM_SNP_THIS(Snp); + + // Before receiving check the link status + /*if (CheckLinkStatus (Snp) < 0) { + ReturnUnlock (EFI_NOT_READY); + }*/ + + // Get the used space in rx fifo + RxDataUsed = RxDataUsedSpace (0, Snp); + if (RxDataUsed > gRxDataSize - 4) { + LanDriver->Stats.RxDroppedFrames += 1; + ReturnUnlock (EFI_NOT_READY); + } + + // Get the used status space + RxStatusUsed = RxStatusUsedSpace (0, Snp); + if (RxStatusUsed > gRxStatusSize - 4) { + LanDriver->Stats.RxDroppedFrames += 1; + ReturnUnlock (EFI_NOT_READY); + } + + // Get the number of packets to read + NumPackets = RxStatusUsed >> 2; + if (!NumPackets) { + ReturnUnlock (EFI_NOT_READY); + } + + // Read Rx Status (only if not empty) + RxFifoStatus = MmioRead32 (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")); + ReturnUnlock (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; + ReturnUnlock (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; + ReturnUnlock (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 = (RxFifoStatus & RXSTATUS_PL_MASK) >> 16; + LanDriver->Stats.RxTotalBytes += (PLength - 4); + + // Check buffer size + if (*BuffSize < PLength) { + *BuffSize = PLength; + ReturnUnlock (EFI_BUFFER_TOO_SMALL); + } + + // If padding is applied, read more DWORDs + if (PLength % 4) { + Padding = 4 - (PLength % 4); + ReadLimit = (PLength + Padding)/4; + } else { + ReadLimit = PLength/4; + Padding = 0; + } + + // Set the amount of data to be transfered out of FIFO for THIS packet + // This can be used to trigger an interrupt, and status can be checked + RxCfgValue = MmioRead32 (LAN9118_RX_CFG); + RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK); + RxCfgValue |= (ReadLimit & 0xFFFF) << 16; + + // Set end alignment to 4-bytes + RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK); + MmioWrite32 (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] = MmioRead32 (LAN9118_RX_DATA); + } + + // Check for Rx errors (worst possible error) + if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) { + DEBUG((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n")); + + // Initiate a software reset + if (SoftReset (0, Snp) < 0) { + DEBUG((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Acknowledge the RXE + MmioWrite32 (LAN9118_INT_STS, INSTS_RXE); + gBS->Stall (LAN9118_STALL); + + // Restart the rx (and do not clear FIFO) + StartRx (0, Snp); + + // Say that command could not be sent + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // 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); + } + + LanDriver->Stats.RxGoodFrames += 1; + Status = EFI_SUCCESS; + +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + + +/* +** Entry point for the LAN9118 driver +** +*/ +EFI_STATUS +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)); + Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool(sizeof(LAN9118_DEVICE_PATH), &Lan9118PathTemplate); + + // 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 + + // Update network mode information + SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;/* | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;*/ + // Current allowed settings + SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + // LAN9118 has 64bit multicast hash table + 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); + + // Assign fields for device path + Lan9118Path->Lan9118.MacAddress = GetCurrentMacAddress (); + Lan9118Path->Lan9118.IfType = Snp->Mode->IfType; + + // Initialise the protocol + ControllerHandle = 0; + 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; +} diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf new file mode 100644 index 0000000..232f502 --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf @@ -0,0 +1,55 @@ +#/** @file +# INF file for the LAN9118 Network Controller Driver. +# +# Copyright (c) 2012-2013, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[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 + LAN9118DxeHw.h + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + NetworkPkg/NetworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + UefiLib + NetLib + UefiDriverEntryPoint + BaseMemoryLib + ArmLib + IoLib + TimerLib + DevicePathLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress + +[Depex] + TRUE diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h new file mode 100644 index 0000000..f622d0b --- /dev/null +++ b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h @@ -0,0 +1,325 @@ +/** @file +* +* Copyright (c) 2012-2013, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#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_RESERVED (0x00000094) +#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 +//#define LAN9118_RESERVED (0x000000B8 - 0x000000FC) + + +// 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 // Incomming 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 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 ((MmioRead32(LAN9118_ID_REV) & 0xFFFF0000) >> 16) +#define IDREV_REV (MmioRead32(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 BIT3 // 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 (0x2) // Software Reset Timeout bit (RO) +#define HWCFG_BMODE (0x4) // 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_CSMA BIT0 // Advertise CSMA capability +#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_100BASET4 BIT9 // 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_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_TIMEOUT BIT9 +#define E2P_EPC_MAC_ADDRESS_LOADED BIT8 + +// 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_START_OFFSET(off) (((off) & 0x1f) << 16) +#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_B_PACKET_TAG(tag) ((tag) << 16) +#define TX_CMD_B_PACKET_LENGTH(size) ((size) & 0x000003FF) + +// +// Conditional compilation flags +// +//#define USE_TX_BUFFER +//#define EVAL_PERFORMANCE + + +#endif /* __LAN9118_DXE_HDR_H__ */