summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Kinney <steven.kinney@linaro.org>2013-10-11 08:24:36 -0500
committerSteven Kinney <steven.kinney@linaro.org>2013-10-11 08:24:36 -0500
commitb33864ebd9b8863af3048ab9d4b032018eba9293 (patch)
tree07956490855a50c46bd1e32c009896ad2c1c2032
parent45d75888b5bdad1fe66c73cc85436e1e4909a9b6 (diff)
parent047715198e85afb90e062c44e78aa3bf5e3c3a73 (diff)
Merging uefi-next/linaro-release into masterlinaro-uefi-2013.09-02
Signed-off-by: Steven Kinney <steven.kinney@linaro.org>
-rw-r--r--ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.c829
-rw-r--r--ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.h42
-rw-r--r--ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.inf49
-rw-r--r--ArmPlatformPkg/ArmPlatformPkg.dec11
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc3
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf23
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.dsc3
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.fdf21
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc14
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf17
-rwxr-xr-xArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc4
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.dsc3
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf17
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc3
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf19
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.dsc2
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf16
-rw-r--r--ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc24
-rw-r--r--ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c2592
-rw-r--r--ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf55
-rw-r--r--ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118DxeHw.h325
-rw-r--r--ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c2235
-rw-r--r--ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf58
-rw-r--r--ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h278
-rwxr-xr-x[-rw-r--r--]MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c33
-rw-r--r--MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c6
26 files changed, 6657 insertions, 25 deletions
diff --git a/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.c b/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.c
new file mode 100644
index 000000000..bd2d7008c
--- /dev/null
+++ b/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.c
@@ -0,0 +1,829 @@
+/** @file
+
+ This code responsible for constructing and updating SMBIOS table into system table.
+Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+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 "UpdateSmbios.h"
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE0 BIOS Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE0 mBIOSInfoType0 = {
+ { EFI_SMBIOS_TYPE_BIOS_INFORMATION, sizeof (SMBIOS_TABLE_TYPE0), 0 },
+ 1, // Vendor String
+ 2, // BiosVersion String
+ 0xE000, // BiosSegment
+ 3, // BiosReleaseDate String
+ 0x7F, // BiosSize
+ { // BiosCharacteristics
+ 0, // Reserved :2; ///< Bits 0-1.
+ 0, // Unknown :1;
+ 0, // BiosCharacteristicsNotSupported :1;
+ 0, // IsaIsSupported :1;
+ 0, // McaIsSupported :1;
+ 0, // EisaIsSupported :1;
+ 1, // PciIsSupported :1;
+ 0, // PcmciaIsSupported :1;
+ 0, // PlugAndPlayIsSupported :1;
+ 0, // ApmIsSupported :1;
+ 1, // BiosIsUpgradable :1;
+ 1, // BiosShadowingAllowed :1;
+ 0, // VlVesaIsSupported :1;
+ 0, // EscdSupportIsAvailable :1;
+ 0, // BootFromCdIsSupported :1;
+ 1, // SelectableBootIsSupported :1;
+ 0, // RomBiosIsSocketed :1;
+ 0, // BootFromPcmciaIsSupported :1;
+ 0, // EDDSpecificationIsSupported :1;
+ 0, // JapaneseNecFloppyIsSupported :1;
+ 0, // JapaneseToshibaFloppyIsSupported :1;
+ 0, // Floppy525_360IsSupported :1;
+ 0, // Floppy525_12IsSupported :1;
+ 0, // Floppy35_720IsSupported :1;
+ 0, // Floppy35_288IsSupported :1;
+ 0, // PrintScreenIsSupported :1;
+ 0, // Keyboard8042IsSupported :1;
+ 0, // SerialIsSupported :1;
+ 0, // PrinterIsSupported :1;
+ 0, // CgaMonoIsSupported :1;
+ 0, // NecPc98 :1;
+ 0 // ReservedForVendor :32; ///< Bits 32-63. Bits 32-47 reserved for BIOS vendor
+ ///< and bits 48-63 reserved for System Vendor.
+ },
+ { // BIOSCharacteristicsExtensionBytes[]
+ 0x81, // AcpiIsSupported :1;
+ // UsbLegacyIsSupported :1;
+ // AgpIsSupported :1;
+ // I2OBootIsSupported :1;
+ // Ls120BootIsSupported :1;
+ // AtapiZipDriveBootIsSupported :1;
+ // Boot1394IsSupported :1;
+ // SmartBatteryIsSupported :1;
+ // BIOSCharacteristicsExtensionBytes[1]
+ 0x0a, // BiosBootSpecIsSupported :1;
+ // FunctionKeyNetworkBootIsSupported :1;
+ // TargetContentDistributionEnabled :1;
+ // UefiSpecificationSupported :1;
+ // VirtualMachineSupported :1;
+ // ExtensionByte2Reserved :3;
+ },
+ 0x00, // SystemBiosMajorRelease
+ 0x01, // SystemBiosMinorRelease
+ 0xFF, // EmbeddedControllerFirmwareMajorRelease
+ 0xFF, // EmbeddedControllerFirmwareMinorRelease
+};
+
+
+CHAR8 *mBIOSInfoType0Strings[] = {
+ "edk2.sourceforge.net", // Vendor String
+ __TIME__, // BiosVersion String
+ __DATE__, // BiosReleaseDate String
+ NULL
+};
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE1 System Information
+************************************************************************/
+SMBIOS_TABLE_TYPE1 mSysInfoType1 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_INFORMATION, sizeof (SMBIOS_TABLE_TYPE1), 0 },
+ 1, // Manufacturer String
+ 2, // ProductName String
+ 3, // Version String
+ 4, // SerialNumber String
+ { 0x25EF0280, 0xEC82, 0x42B0, { 0x8F, 0xB6, 0x10, 0xAD, 0xCC, 0xC6, 0x7C, 0x02 } },
+ SystemWakeupTypePowerSwitch,
+ 5, // SKUNumber String
+ 6, // Family String
+};
+CHAR8 *mSysInfoType1Strings[] = {
+ "edk2.sourceforge.net",
+ "EmulatorPkg",
+ "1.0",
+ "System Serial#",
+ "System SKU#",
+ "edk2",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE2 Board Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE2 mBoardInfoType2 = {
+ { EFI_SMBIOS_TYPE_BASEBOARD_INFORMATION, sizeof (SMBIOS_TABLE_TYPE2), 0 },
+ 1, // Manufacturer String
+ 2, // ProductName String
+ 3, // Version String
+ 4, // SerialNumber String
+ 5, // AssetTag String
+ { // FeatureFlag
+ 1, // Motherboard :1;
+ 0, // RequiresDaughterCard :1;
+ 0, // Removable :1;
+ 0, // Replaceable :1;
+ 0, // HotSwappable :1;
+ 0, // Reserved :3;
+ },
+ 6, // LocationInChassis String
+ 0, // ChassisHandle;
+ BaseBoardTypeMotherBoard, // BoardType;
+ 0, // NumberOfContainedObjectHandles;
+ { 0 } // ContainedObjectHandles[1];
+};
+CHAR8 *mBoardInfoType2Strings[] = {
+ "edk2.sourceforge.net",
+ "EmulatorPkg",
+ "1.0",
+ "Base Board Serial#",
+ "Base Board Asset Tag#",
+ "Part Component",
+ NULL
+};
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE3 Enclosure Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE3 mEnclosureInfoType3 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_ENCLOSURE, sizeof (SMBIOS_TABLE_TYPE3), 0 },
+ 1, // Manufacturer String
+ MiscChassisTypeLapTop, // Type;
+ 2, // Version String
+ 3, // SerialNumber String
+ 4, // AssetTag String
+ ChassisStateSafe, // BootupState;
+ ChassisStateSafe, // PowerSupplyState;
+ ChassisStateSafe, // ThermalState;
+ ChassisSecurityStatusNone,// SecurityStatus;
+ { 0, 0, 0, 0 }, // OemDefined[4];
+ 0, // Height;
+ 0, // NumberofPowerCords;
+ 0, // ContainedElementCount;
+ 0, // ContainedElementRecordLength;
+ { 0 }, // ContainedElements[1];
+};
+CHAR8 *mEnclosureInfoType3Strings[] = {
+ "edk2.sourceforge.net",
+ "EmulatorPkg",
+ "Chassis Board Serial#",
+ "Chassis Board Asset Tag#",
+ NULL
+};
+
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE4 Processor Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE4 mProcessorInfoType4 = {
+
+ { EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION, sizeof (SMBIOS_TABLE_TYPE4), 0},
+
+ 1, // Socket String
+ ProcessorOther, // ProcessorType; ///< The enumeration value from PROCESSOR_TYPE_DATA.
+ ProcessorFamilyOther, // ProcessorFamily; ///< The enumeration value from PROCESSOR_FAMILY_DATA.
+ 2, // ProcessorManufacture String;
+ { // ProcessorId;
+ { // PROCESSOR_SIGNATURE
+ 0, // ProcessorSteppingId:4;
+ 0, // ProcessorModel: 4;
+ 0, // ProcessorFamily: 4;
+ 0, // ProcessorType: 2;
+ 0, // ProcessorReserved1: 2;
+ 0, // ProcessorXModel: 4;
+ 0, // ProcessorXFamily: 8;
+ 0, // ProcessorReserved2: 4;
+ },
+
+ { // PROCESSOR_FEATURE_FLAGS
+ 0, // ProcessorFpu :1;
+ 0, // ProcessorVme :1;
+ 0, // ProcessorDe :1;
+ 0, // ProcessorPse :1;
+ 0, // ProcessorTsc :1;
+ 0, // ProcessorMsr :1;
+ 0, // ProcessorPae :1;
+ 0, // ProcessorMce :1;
+ 0, // ProcessorCx8 :1;
+ 0, // ProcessorApic :1;
+ 0, // ProcessorReserved1 :1;
+ 0, // ProcessorSep :1;
+ 0, // ProcessorMtrr :1;
+ 0, // ProcessorPge :1;
+ 0, // ProcessorMca :1;
+ 0, // ProcessorCmov :1;
+ 0, // ProcessorPat :1;
+ 0, // ProcessorPse36 :1;
+ 0, // ProcessorPsn :1;
+ 0, // ProcessorClfsh :1;
+ 0, // ProcessorReserved2 :1;
+ 0, // ProcessorDs :1;
+ 0, // ProcessorAcpi :1;
+ 0, // ProcessorMmx :1;
+ 0, // ProcessorFxsr :1;
+ 0, // ProcessorSse :1;
+ 0, // ProcessorSse2 :1;
+ 0, // ProcessorSs :1;
+ 0, // ProcessorReserved3 :1;
+ 0, // ProcessorTm :1;
+ 0, // ProcessorReserved4 :2;
+ }
+ },
+ 3, // ProcessorVersion String;
+ { // Voltage;
+ 1, // ProcessorVoltageCapability5V :1;
+ 1, // ProcessorVoltageCapability3_3V :1;
+ 1, // ProcessorVoltageCapability2_9V :1;
+ 0, // ProcessorVoltageCapabilityReserved :1; ///< Bit 3, must be zero.
+ 0, // ProcessorVoltageReserved :3; ///< Bits 4-6, must be zero.
+ 0 // ProcessorVoltageIndicateLegacy :1;
+ },
+ 0, // ExternalClock;
+ 0, // MaxSpeed;
+ 0, // CurrentSpeed;
+ 0x41, // Status;
+ ProcessorUpgradeOther, // ProcessorUpgrade; ///< The enumeration value from PROCESSOR_UPGRADE.
+ 0, // L1CacheHandle;
+ 0, // L2CacheHandle;
+ 0, // L3CacheHandle;
+ 4, // SerialNumber;
+ 5, // AssetTag;
+ 6, // PartNumber;
+ 0, // CoreCount;
+ 0, // EnabledCoreCount;
+ 0, // ThreadCount;
+ 0, // ProcessorCharacteristics;
+ 0, // ProcessorFamily2;
+};
+
+
+CHAR8 *mProcessorInfoType4Strings[] = {
+ "Socket",
+ "edk2.svn.sourceforge.net",
+ "Emulated Processor",
+ "1.0",
+ "1.0",
+ "1.0",
+ NULL
+};
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE7 Cache Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE7 mCacheInfoType7 = {
+ { EFI_SMBIOS_TYPE_CACHE_INFORMATION, sizeof (SMBIOS_TABLE_TYPE7), 0 },
+ 1, // SocketDesignation String
+ 0x018A, // Cache Configuration
+ 0x00FF, // Maximum Size 256k
+ 0x00FF, // Install Size 256k
+ { // Supported SRAM Type
+ 0, //Other :1
+ 0, //Unknown :1
+ 0, //NonBurst :1
+ 1, //Burst :1
+ 0, //PiplelineBurst :1
+ 1, //Synchronous :1
+ 0, //Asynchronous :1
+ 0 //Reserved :9
+ },
+ { // Current SRAM Type
+ 0, //Other :1
+ 0, //Unknown :1
+ 0, //NonBurst :1
+ 1, //Burst :1
+ 0, //PiplelineBurst :1
+ 1, //Synchronous :1
+ 0, //Asynchronous :1
+ 0 //Reserved :9
+ },
+ 0, // Cache Speed unknown
+ CacheErrorMultiBit, // Error Correction Multi
+ CacheTypeUnknown, // System Cache Type
+ CacheAssociativity2Way // Associativity
+};
+CHAR8 *mCacheInfoType7Strings[] = {
+ "Cache1",
+ NULL
+};
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE9 System Slot Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE9 mSysSlotInfoType9 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_SLOTS, sizeof (SMBIOS_TABLE_TYPE9), 0 },
+ 1, // SlotDesignation String
+ SlotTypeOther, // SlotType; ///< The enumeration value from MISC_SLOT_TYPE.
+ SlotDataBusWidthOther, // SlotDataBusWidth; ///< The enumeration value from MISC_SLOT_DATA_BUS_WIDTH.
+ SlotUsageAvailable, // CurrentUsage; ///< The enumeration value from MISC_SLOT_USAGE.
+ SlotLengthOther, // SlotLength; ///< The enumeration value from MISC_SLOT_LENGTH.
+ 0, // SlotID;
+ { // SlotCharacteristics1;
+ 1, // CharacteristicsUnknown :1;
+ 0, // Provides50Volts :1;
+ 0, // Provides33Volts :1;
+ 0, // SharedSlot :1;
+ 0, // PcCard16Supported :1;
+ 0, // CardBusSupported :1;
+ 0, // ZoomVideoSupported :1;
+ 0, // ModemRingResumeSupported:1;
+ },
+ { // SlotCharacteristics2;
+ 0, // PmeSignalSupported :1;
+ 0, // HotPlugDevicesSupported :1;
+ 0, // SmbusSignalSupported :1;
+ 0, // Reserved :5; ///< Set to 0.
+ },
+ 0, // SegmentGroupNum;
+ 0, // BusNum;
+ 0, // DevFuncNum;
+};
+CHAR8 *mSysSlotInfoType9Strings[] = {
+ "SD Card",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE16 Physical Memory ArrayInformation
+************************************************************************/
+
+SMBIOS_TABLE_TYPE16 mPhyMemArrayInfoType16 = {
+ { EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY, sizeof (SMBIOS_TABLE_TYPE16), 0 },
+ MemoryArrayLocationSystemBoard, // Location; ///< The enumeration value from MEMORY_ARRAY_LOCATION.
+ MemoryArrayUseSystemMemory, // Use; ///< The enumeration value from MEMORY_ARRAY_USE.
+ MemoryErrorCorrectionUnknown, // MemoryErrorCorrection; ///< The enumeration value from MEMORY_ERROR_CORRECTION.
+ 0x80000000, // MaximumCapacity;
+ 0xFFFE, // MemoryErrorInformationHandle;
+ 1, // NumberOfMemoryDevices;
+ 0x3fffffffffffffffULL, // ExtendedMaximumCapacity;
+};
+CHAR8 *mPhyMemArrayInfoType16Strings[] = {
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE17 Memory Device Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE17 mMemDevInfoType17 = {
+ { EFI_SMBIOS_TYPE_MEMORY_DEVICE, sizeof (SMBIOS_TABLE_TYPE17), 0 },
+ 0, // MemoryArrayHandle;
+ 0xFFFE, // MemoryErrorInformationHandle;
+ 0xFFFF, // TotalWidth;
+ 0xFFFF, // DataWidth;
+ 0xFFFF, // Size;
+ MemoryFormFactorUnknown, // FormFactor; ///< The enumeration value from MEMORY_FORM_FACTOR.
+ 0xff, // DeviceSet;
+ 1, // DeviceLocator String
+ 2, // BankLocator String
+ MemoryTypeDram, // MemoryType; ///< The enumeration value from MEMORY_DEVICE_TYPE.
+ { // TypeDetail;
+ 0, // Reserved :1;
+ 0, // Other :1;
+ 1, // Unknown :1;
+ 0, // FastPaged :1;
+ 0, // StaticColumn :1;
+ 0, // PseudoStatic :1;
+ 0, // Rambus :1;
+ 0, // Synchronous :1;
+ 0, // Cmos :1;
+ 0, // Edo :1;
+ 0, // WindowDram :1;
+ 0, // CacheDram :1;
+ 0, // Nonvolatile :1;
+ 0, // Registered :1;
+ 0, // Unbuffered :1;
+ 0, // Reserved1 :1;
+ },
+ 0, // Speed;
+ 3, // Manufacturer String
+ 0, // SerialNumber String
+ 0, // AssetTag String
+ 0, // PartNumber String
+ 0, // Attributes;
+ 0, // ExtendedSize;
+ 0, // ConfiguredMemoryClockSpeed;
+};
+CHAR8 *mMemDevInfoType17Strings[] = {
+ "OS Virtual Memory",
+ "malloc",
+ "OSV",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE19 Memory Array Mapped Address Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE19 mMemArrMapInfoType19 = {
+ { EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS, sizeof (SMBIOS_TABLE_TYPE19), 0 },
+ 0x80000000, // StartingAddress;
+ 0xbfffffff, // EndingAddress;
+ 0, // MemoryArrayHandle;
+ 1, // PartitionWidth;
+ 0, // ExtendedStartingAddress;
+ 0, // ExtendedEndingAddress;
+};
+CHAR8 *mMemArrMapInfoType19Strings[] = {
+ NULL
+};
+
+
+
+
+/***********************************************************************
+ SMBIOS data definition TYPE32 Boot Information
+************************************************************************/
+
+SMBIOS_TABLE_TYPE32 mBootInfoType32 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_BOOT_INFORMATION, sizeof (SMBIOS_TABLE_TYPE32), 0 },
+ { 0, 0, 0, 0, 0, 0 }, // Reserved[6];
+ BootInformationStatusNoError // BootStatus
+};
+
+CHAR8 *mBootInfoType32Strings[] = {
+ NULL
+};
+
+
+/**
+
+ Create SMBIOS record.
+
+ Converts a fixed SMBIOS structure and an array of pointers to strings into
+ an SMBIOS record where the strings are cat'ed on the end of the fixed record
+ and terminated via a double NULL and add to SMBIOS table.
+
+ SMBIOS_TABLE_TYPE32 gSmbiosType12 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 },
+ 1 // StringCount
+ };
+
+ CHAR8 *gSmbiosType12Strings[] = {
+ "Not Found",
+ NULL
+ };
+
+ ...
+
+ LogSmbiosData (
+ (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12,
+ gSmbiosType12Strings
+ );
+
+ @param Template Fixed SMBIOS structure, required.
+ @param StringArray Array of strings to convert to an SMBIOS string pack.
+ NULL is OK.
+**/
+
+
+EFI_STATUS
+EFIAPI
+LogSmbiosData (
+ IN EFI_SMBIOS_TABLE_HEADER *Template,
+ IN CHAR8 **StringPack
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_SMBIOS_PROTOCOL *Smbios;
+ EFI_SMBIOS_HANDLE SmbiosHandle;
+ EFI_SMBIOS_TABLE_HEADER *Record;
+ UINTN Index;
+ UINTN StringSize;
+ UINTN Size;
+ CHAR8 *Str;
+
+ //
+ // Locate Smbios protocol.
+ //
+
+ Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);
+
+ if (EFI_ERROR (Status)) {
+
+ return Status;
+
+ }
+
+
+ // Calculate the size of the fixed record and optional string pack
+
+ Size = Template->Length;
+
+ if (StringPack == NULL) {
+
+ // At least a double null is required
+
+ Size += 2;
+
+ } else {
+
+ for (Index = 0; StringPack[Index] != NULL; Index++) {
+
+ StringSize = AsciiStrSize (StringPack[Index]);
+
+ Size += StringSize;
+
+ }
+
+ if (StringPack[0] == NULL) {
+
+ // At least a double null is required
+
+ Size += 1;
+
+ }
+
+ // Don't forget the terminating double null
+
+ Size += 1;
+
+ }
+
+
+
+ // Copy over Template
+ Record = (EFI_SMBIOS_TABLE_HEADER *)AllocateZeroPool (Size);
+
+ if (Record == NULL) {
+
+ return EFI_OUT_OF_RESOURCES;
+
+ }
+
+ CopyMem (Record, Template, Template->Length);
+
+
+
+ // Append string pack
+
+ Str = ((CHAR8 *)Record) + Record->Length;
+
+
+
+ for (Index = 0; StringPack[Index] != NULL; Index++) {
+
+ StringSize = AsciiStrSize (StringPack[Index]);
+
+ CopyMem (Str, StringPack[Index], StringSize);
+
+ Str += StringSize;
+
+ }
+
+ *Str = 0;
+
+ SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+
+ Status = Smbios->Add (
+ Smbios,
+ gImageHandle,
+ &SmbiosHandle,
+ Record
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Record);
+
+ return Status;
+
+}
+
+
+
+/***********************************************************************
+ SMBIOS data update TYPE0 BIOS Information
+************************************************************************/
+
+
+VOID
+BIOSInfoUpdateSmbiosType0 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mBIOSInfoType0, mBIOSInfoType0Strings);
+
+}
+
+
+
+/***********************************************************************
+ SMBIOS data update TYPE1 System Information
+************************************************************************/
+VOID
+SysInfoUpdateSmbiosType1 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mSysInfoType1, mSysInfoType1Strings);
+
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE2 Board Information
+************************************************************************/
+VOID
+BoardInfoUpdateSmbiosType2 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mBoardInfoType2, mBoardInfoType2Strings);
+
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE3 Enclosure Information
+************************************************************************/
+VOID
+EnclosureInfoUpdateSmbiosType3 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mEnclosureInfoType3, mEnclosureInfoType3Strings);
+
+}
+
+
+/***********************************************************************
+ SMBIOS data update TYPE4 Processor Information
+************************************************************************/
+
+
+VOID
+
+ProcessorInfoUpdateSmbiosType4 (
+
+ IN UINTN MaxCpus
+
+ )
+
+{
+
+ mProcessorInfoType4.CoreCount = (UINT8) MaxCpus;
+
+ mProcessorInfoType4.EnabledCoreCount = (UINT8) MaxCpus;
+
+ mProcessorInfoType4.ThreadCount = (UINT8) MaxCpus;
+
+
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mProcessorInfoType4, mProcessorInfoType4Strings);
+
+}
+
+
+/***********************************************************************
+ SMBIOS data update TYPE7 Cache Information
+************************************************************************/
+VOID
+CacheInfoUpdateSmbiosType7 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mCacheInfoType7, mCacheInfoType7Strings);
+
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE9 System Slot Information
+************************************************************************/
+VOID
+SysSlotInfoUpdateSmbiosType9 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mSysSlotInfoType9, mSysSlotInfoType9Strings);
+
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE16 Physical Memory Array Information
+************************************************************************/
+VOID
+PhyMemArrayInfoUpdateSmbiosType16 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mPhyMemArrayInfoType16, mPhyMemArrayInfoType16Strings);
+
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE17 Memory Device Information
+************************************************************************/
+VOID
+MemDevInfoUpdateSmbiosType17 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mMemDevInfoType17, mMemDevInfoType17Strings);
+
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE19 Memory Array Map Information
+************************************************************************/
+VOID
+MemArrMapInfoUpdateSmbiosType19 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mMemArrMapInfoType19, mMemArrMapInfoType19Strings);
+
+}
+
+
+/***********************************************************************
+ SMBIOS data update TYPE32 Boot Information
+************************************************************************/
+VOID
+BootInfoUpdateSmbiosType32 (
+ VOID
+ )
+
+{
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mBootInfoType32, mBootInfoType32Strings);
+
+}
+
+
+/***********************************************************************
+ Driver Entry
+************************************************************************/
+
+EFI_STATUS
+
+EFIAPI
+
+UpdateSmbios (
+
+ IN EFI_HANDLE ImageHandle,
+
+ IN EFI_SYSTEM_TABLE *SystemTable
+
+ )
+
+{
+
+ BIOSInfoUpdateSmbiosType0();
+
+ SysInfoUpdateSmbiosType1();
+
+ BoardInfoUpdateSmbiosType2();
+
+ EnclosureInfoUpdateSmbiosType3();
+
+ ProcessorInfoUpdateSmbiosType4 (2);
+
+ CacheInfoUpdateSmbiosType7();
+
+ SysSlotInfoUpdateSmbiosType9();
+
+ PhyMemArrayInfoUpdateSmbiosType16();
+
+ MemDevInfoUpdateSmbiosType17();
+
+ MemArrMapInfoUpdateSmbiosType19();
+
+ BootInfoUpdateSmbiosType32();
+
+ return EFI_SUCCESS;
+
+}
diff --git a/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.h b/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.h
new file mode 100644
index 000000000..620ccd528
--- /dev/null
+++ b/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.h
@@ -0,0 +1,42 @@
+/** @file
+
+Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+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 _UPDATE_SMBIOS_DRIVER_H_
+#define _UPDATE_SMBIOS_DRIVER_H_
+
+
+#include <PiDxe.h>
+#include <Protocol/Smbios.h>
+#include <IndustryStandard/SmBios.h>
+#include <Guid/SmBios.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+
+EFI_STATUS
+EFIAPI
+UpdateSmbios (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+#endif
+
diff --git a/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.inf b/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.inf
new file mode 100644
index 000000000..36552fd1e
--- /dev/null
+++ b/ArmPkg/Drivers/UpdateSmbios/UpdateSmbios.inf
@@ -0,0 +1,49 @@
+## @file
+#
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+#
+# 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 = 0x00010005
+ BASE_NAME = UpdateSmbios
+ FILE_GUID = 3847D23F-1D95-4772-B60C-4BBFBC4D532F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UpdateSmbios
+
+[Sources]
+ UpdateSmbios.c
+ UpdateSmbios.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiSmbiosProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+
+[Guids]
+
+[Depex]
+ gEfiSmbiosProtocolGuid
+
diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec
index d813f885e..3fc8a7031 100644
--- a/ArmPlatformPkg/ArmPlatformPkg.dec
+++ b/ArmPlatformPkg/ArmPlatformPkg.dec
@@ -141,6 +141,16 @@
gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L""|VOID*|0x0000001B
gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths|L""|VOID*|0x0000001C
+ #
+ # LAN9118 Ethernet Driver PCDs
+ #
+ gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x000000FF
+
+ #
+ # LAN91x Ethernet Driver PCDs
+ #
+ gArmPlatformTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x0|UINT32|0x000000FE
+
[PcdsFixedAtBuild.ARM]
# Stack for CPU Cores in Secure Monitor Mode
gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase|0|UINT32|0x00000007
@@ -152,4 +162,3 @@
# and PcdCPUCoreSecSecondaryStackSize
gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase|0|UINT32|0x00000007
gArmPlatformTokenSpaceGuid.PcdCPUCoreSecMonStackSize|0x0|UINT32|0x00000008
-
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc
index 6addb739e..7bbb464e5 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc
@@ -172,6 +172,9 @@
gArmTokenSpaceGuid.PcdGicDistributorBase|0x2C001000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000
+ # Ethernet (SMSC 91C111)
+ gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000
+
#
# ARM OS Loader
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
index 290e04830..881380763 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf
@@ -26,12 +26,12 @@
[FD.ARM_VEXPRESS_CTA15A7_EFI]
BaseAddress = 0x81000000|gArmTokenSpaceGuid.PcdFdBaseAddress # The base address of the Firmware in remapped DRAM.
-Size = 0x000B0000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device
+Size = 0x000D2000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device
ErasePolarity = 1
BlockSize = 0x00001000
-NumBlocks = 0xB0
+NumBlocks = 0xD2
-0x00000000|0x000B0000
+0x00000000|0x000D2000
gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize
FV = FVMAIN_COMPACT
@@ -123,6 +123,23 @@ READ_LOCK_STATUS = TRUE
INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
#
+ # Networking stack
+ #
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ INF ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf
+
+ #
# UEFI application
#
INF ShellBinPkg/UefiShell/UefiShell.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.dsc
index 37765e929..7ecd431af 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.dsc
@@ -169,6 +169,9 @@
gArmTokenSpaceGuid.PcdGicDistributorBase|0x2C001000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000
+ # Ethernet (SMSC 91C111)
+ gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000
+
#
# ARM OS Loader
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.fdf
index a15a72160..4fec30acf 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15x2.fdf
@@ -74,6 +74,8 @@ FV = FVMAIN_COMPACT
################################################################################
[FV.FVMAIN_SEC]
+FvBaseAddress = 0x0
+FvForceRebase = TRUE
FvAlignment = 8
ERASE_POLARITY = 1
MEMORY_MAPPED = TRUE
@@ -171,7 +173,24 @@ READ_LOCK_STATUS = TRUE
INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
#
- # UEFI application
+ # Networking stack
+ #
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ INF ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf
+
+ #
+ # UEFI application (Shell Embedded Boot Loader)
#
INF ShellBinPkg/UefiShell/UefiShell.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc
index ab2d40099..b9ebb9959 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc
@@ -49,6 +49,14 @@
ArmPlatformLib|ArmPlatformPkg/ArmVExpressPkg/Library/ArmVExpressLibCTA9x4/ArmVExpressLib.inf
ArmTrustZoneLib|ArmPlatformPkg/Drivers/ArmTrustZone/ArmTrustZone.inf
+#!ifdef $(EDK2_ARMVE_NETWORK)
+ # Networking Requirements
+ NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
+ DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
+ UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
+ IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
+#!endif
+
# ARM PL310 L2 Cache Driver
L2X0CacheLib|ArmPlatformPkg/Drivers/PL310L2Cache/PL310L2CacheSec.inf
# ARM PL354 SMC Driver
@@ -197,6 +205,11 @@
#
gArmTokenSpaceGuid.PcdL2x0ControllerBase|0x1E00A000
+ #
+ # LAN9118 Ethernet Driver PCDs
+ #
+ gArmPlatformTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x4E000000
+
################################################################################
#
# Components Section - list of all EDK II Modules needed by this Platform
@@ -300,7 +313,6 @@
MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
- #
# Bds
#
MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
index 42b3c6412..117d8eca7 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.fdf
@@ -217,6 +217,23 @@ READ_LOCK_STATUS = TRUE
INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
#
+ # Networking stack
+ #
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ INF ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf
+
+ #
# UEFI application (Shell Embedded Boot Loader)
#
INF ShellBinPkg/UefiShell/UefiShell.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc
index 566411609..0cd66f749 100755
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc
@@ -21,7 +21,11 @@
PLATFORM_GUID = 0de70077-9b3b-43bf-ba38-0ea37d77141b
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010005
+!ifdef $(EDK2_OUT_DIR)
+ OUTPUT_DIRECTORY = $(EDK2_OUT_DIR)
+!else
OUTPUT_DIRECTORY = Build/ArmVExpress-FVP-AArch64
+!endif
SUPPORTED_ARCHITECTURES = AARCH64
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.dsc
index b531e2103..ad61f827a 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.dsc
@@ -141,6 +141,9 @@
gArmTokenSpaceGuid.PcdGicDistributorBase|0x2C001000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000
+ # Ethernet (SMSC 91C111)
+ gArmPlatformTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x1A000000
+
#
# ARM OS Loader
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
index af42aefa9..be79efdae 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.fdf
@@ -130,6 +130,23 @@ READ_LOCK_STATUS = TRUE
INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
#
+ # Networking stack
+ #
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ INF ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf
+
+ #
# Multiple Console IO support
#
INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc
index 015750089..8f3c11b97 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc
@@ -143,6 +143,9 @@
gArmTokenSpaceGuid.PcdGicDistributorBase|0x2C001000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000
+ # Ethernet (SMSC 91C111)
+ gArmPlatformTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x1A000000
+
#
# ARM OS Loader
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
index 24e55751d..7bcaca029 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf
@@ -128,7 +128,24 @@ READ_LOCK_STATUS = TRUE
INF EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
-
+
+ #
+ # Networking stack
+ #
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ INF ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf
+
#
# Multiple Console IO support
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.dsc
index 9e357c37e..9cdce18ff 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.dsc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.dsc
@@ -153,6 +153,8 @@
gArmTokenSpaceGuid.PcdGicDistributorBase|0x2C001000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C000100
+ # Ethernet (SMSC 91C111)
+ gArmPlatformTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x1A000000
#
# ARM OS Loader
#
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
index 728eb7850..170d598f5 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A9x4.fdf
@@ -128,7 +128,23 @@ READ_LOCK_STATUS = TRUE
INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+ #
+ # Networking stack
#
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ INF ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf
+
# Multiple Console IO support
#
INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
index dee39aa8e..1568c9d84 100644
--- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
+++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
@@ -54,6 +54,12 @@
#BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
BaseMemoryLib|ArmPkg/Library/BaseMemoryLibStm/BaseMemoryLibStm.inf
+ # Networking Requirements
+ NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
+ DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
+ UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
+ IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
+
# ARM Architectural Libraries
CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf
DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf
@@ -344,3 +350,21 @@
gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(38400,8,N,1)/VenPcAnsi()"
gArmPlatformTokenSpaceGuid.PcdPlatformBootTimeOut|10
+[Components.common]
+ #
+ # Networking stack
+ #
+ MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
+ MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+ ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.inf
+ ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf
diff --git a/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c b/ArmPlatformPkg/Drivers/LAN9118Dxe/LAN9118Dxe.c
new file mode 100644
index 000000000..92391323a
--- /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 <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 <Library/PrintLib.h>
+
+#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"<null>";
+ }
+
+ 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 000000000..232f502cc
--- /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 000000000..f622d0b54
--- /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__ */
diff --git a/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c
new file mode 100644
index 000000000..1f17e73f0
--- /dev/null
+++ b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.c
@@ -0,0 +1,2235 @@
+/** @file
+* SMSC LAN91x series Network Controller Driver.
+*
+* Copyright (c) 2013 Linaro.org
+*
+* Derived from the LAN9118 driver. Original sources
+* 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 <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>
+
+// Hardware register definitions
+#include "LAN91xDxeHw.h"
+
+// Debugging output options
+//#define LAN91X_PRINT_REGISTERS 1
+//#define LAN91X_PRINT_PACKET_HEADERS 1
+//#define LAN91X_PRINT_RECEIVE_FILTERS 1
+
+// Chip power-down option -- UNTESTED
+//#define LAN91X_POWER_DOWN 1
+
+/*---------------------------------------------------------------------------------------------------------------------
+
+ LAN91x Information Structure
+
+---------------------------------------------------------------------------------------------------------------------*/
+typedef struct _LAN91X_DRIVER {
+ // 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 Buffer recycle queue
+#define TX_QUEUE_DEPTH 16
+ VOID *TxQueue[TX_QUEUE_DEPTH];
+ UINTN TxQueHead;
+ UINTN TxQueTail;
+
+ // Register access variables
+ UINTN IoBase; // I/O Base Address
+ UINT8 Revision; // Chip Revision Number
+ INT8 PhyAd; // Phy Address
+ UINT8 BankSel; // Currently selected register bank
+
+} LAN91X_DRIVER;
+
+#define LAN91X_NO_PHY (-1) // PhyAd value if PHY not detected
+
+#define LAN91X_SIGNATURE SIGNATURE_32('S', 'M', '9', '1')
+#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN91X_DRIVER, Snp, LAN91X_SIGNATURE)
+
+#define LAN91X_STALL 2
+#define LAN91X_MEMORY_ALLOC_POLLS 100 // Max times to poll for memory allocation
+#define LAN91X_PKT_OVERHEAD 6 // Overhead bytes in packet buffer
+
+// Synchronization TPLs
+#define LAN91X_TPL TPL_CALLBACK
+
+// Most common CRC32 Polynomial for little endian machines
+#define CRC_POLYNOMIAL 0xEDB88320
+
+
+typedef struct {
+ MAC_ADDR_DEVICE_PATH Lan91x;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} LAN91X_DEVICE_PATH;
+
+LAN91X_DEVICE_PATH Lan91xPathTemplate = {
+ {
+ {
+ 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
+ }
+};
+
+// Chip ID numbers and name strings
+#define CHIP_9192 3
+#define CHIP_9194 4
+#define CHIP_9195 5
+#define CHIP_9196 6
+#define CHIP_91100 7
+#define CHIP_91100FD 8
+#define CHIP_91111FD 9
+
+STATIC CHAR16 CONST * CONST ChipIds[ 16 ] = {
+ NULL, NULL, NULL,
+ /* 3 */ L"SMC91C90/91C92",
+ /* 4 */ L"SMC91C94",
+ /* 5 */ L"SMC91C95",
+ /* 6 */ L"SMC91C96",
+ /* 7 */ L"SMC91C100",
+ /* 8 */ L"SMC91C100FD",
+ /* 9 */ L"SMC91C11xFD",
+ NULL, NULL, NULL,
+ NULL, NULL, NULL
+};
+
+
+/* ------------------ TxBuffer Queue functions ------------------- */
+
+#define TxQueNext(off) ((((off) + 1) >= TX_QUEUE_DEPTH) ? 0 : ((off) + 1))
+
+STATIC
+BOOLEAN
+TxQueInsert (
+ IN LAN91X_DRIVER *LanDriver,
+ IN VOID *Buffer
+ )
+{
+
+ if (TxQueNext (LanDriver->TxQueTail) == LanDriver->TxQueHead) {
+ return FALSE;
+ }
+
+ LanDriver->TxQueue[LanDriver->TxQueTail] = Buffer;
+ LanDriver->TxQueTail = TxQueNext (LanDriver->TxQueTail);
+
+ return TRUE;
+}
+
+STATIC
+VOID
+*TxQueRemove (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ VOID *Buffer;
+
+ if (LanDriver->TxQueTail == LanDriver->TxQueHead) {
+ return NULL;
+ }
+
+ Buffer = LanDriver->TxQueue[LanDriver->TxQueHead];
+ LanDriver->TxQueue[LanDriver->TxQueHead] = NULL;
+ LanDriver->TxQueHead = TxQueNext (LanDriver->TxQueHead);
+
+ return Buffer;
+}
+
+/* ------------------ MAC Address Hash Calculations ------------------- */
+
+/*
+** Generate a hash value from a multicast address
+**
+** This uses the Ethernet standard CRC32 algorithm
+**
+** 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
+*/
+STATIC
+UINT32
+MulticastHash (
+ IN EFI_MAC_ADDRESS *Mac,
+ IN UINT32 AddrLen
+ )
+{
+ UINT32 Iter;
+ UINT32 Remainder;
+ UINT32 Crc32;
+ UINT8 *Addr;
+
+ // 0xFFFFFFFF is standard seed for Ethernet
+ Remainder = 0xFFFFFFFF;
+
+ // Generate the remainder byte-by-byte (LSB first)
+ Addr = &Mac->Addr[0];
+ while (AddrLen-- > 0) {
+ Remainder ^= *Addr++;
+ for (Iter = 0; Iter < 8; ++Iter) {
+ // Check if exponent is set
+ if ((Remainder & 1) != 0) {
+ Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL;
+ } else {
+ Remainder = (Remainder >> 1) ^ 0;
+ }
+ }
+ }
+
+ // Reverse the bits of the remainder
+ Crc32 = 0;
+ for (Iter = 0; Iter < 32; ++Iter) {
+ Crc32 <<= 1;
+ Crc32 |= Remainder & 1;
+ Remainder >>= 1;
+ }
+ return Crc32;
+}
+
+
+/* ---------------- Banked Register Operations ------------------ */
+
+// Select the proper I/O bank
+STATIC
+VOID
+SelectIoBank (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Register
+ )
+{
+ UINT8 Bank;
+
+ Bank = RegisterToBank (Register);
+
+ // Select the proper I/O bank
+ if (LanDriver->BankSel != Bank) {
+ MmioWrite16 (LanDriver->IoBase + LAN91X_BANK_OFFSET, Bank);
+ LanDriver->BankSel = Bank;
+ }
+}
+
+// Read a 16-bit I/O-space register
+STATIC
+UINT16
+ReadIoReg16 (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Register
+ )
+{
+ UINT8 Offset;
+
+ // Select the proper I/O bank
+ SelectIoBank (LanDriver, Register);
+
+ // Read the requested register
+ Offset = RegisterToOffset (Register);
+ return MmioRead16 (LanDriver->IoBase + Offset);
+}
+
+// Write a 16-bit I/O-space register
+STATIC
+UINT16
+WriteIoReg16 (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Register,
+ UINT16 Value
+ )
+{
+ UINT8 Offset;
+
+ // Select the proper I/O bank
+ SelectIoBank (LanDriver, Register);
+
+ // Write the requested register
+ Offset = RegisterToOffset (Register);
+ return MmioWrite16 (LanDriver->IoBase + Offset, Value);
+}
+
+// Read an 8-bit I/O-space register
+STATIC
+UINT8
+ReadIoReg8 (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Register
+ )
+{
+ UINT8 Offset;
+
+ // Select the proper I/O bank
+ SelectIoBank (LanDriver, Register);
+
+ // Read the requested register
+ Offset = RegisterToOffset (Register);
+ return MmioRead8 (LanDriver->IoBase + Offset);
+}
+
+// Write an 8-bit I/O-space register
+STATIC
+UINT8
+WriteIoReg8 (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Register,
+ UINT8 Value
+ )
+{
+ UINT8 Offset;
+
+ // Select the proper I/O bank
+ SelectIoBank (LanDriver, Register);
+
+ // Write the requested register
+ Offset = RegisterToOffset (Register);
+ return MmioWrite8 (LanDriver->IoBase + Offset, Value);
+}
+
+
+/* ---------------- MII/PHY Access Operations ------------------ */
+
+#define LAN91X_MDIO_STALL 1
+
+STATIC
+VOID
+MdioOutput (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Bits,
+ UINT32 Value
+ )
+{
+ UINT16 MgmtReg;
+ UINT32 Mask;
+
+ MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);
+ MgmtReg &= ~MGMT_MCLK;
+ MgmtReg |= MGMT_MDOE;
+
+ for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) {
+ if ((Value & Mask) != 0) {
+ MgmtReg |= MGMT_MDO;
+ } else {
+ MgmtReg &= ~MGMT_MDO;
+ }
+
+ WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
+ gBS->Stall (LAN91X_MDIO_STALL);
+ WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK);
+ gBS->Stall (LAN91X_MDIO_STALL);
+ }
+}
+#define PHY_OUTPUT_TIME (2 * LAN91X_MDIO_STALL)
+
+STATIC
+UINT32
+MdioInput (
+ LAN91X_DRIVER *LanDriver,
+ UINTN Bits
+ )
+{
+ UINT16 MgmtReg;
+ UINT32 Mask;
+ UINT32 Value;
+
+ MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);
+ MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO);
+ WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
+
+ Value = 0;
+ for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) {
+ if ((ReadIoReg16 (LanDriver, LAN91X_MGMT) & MGMT_MDI) != 0) {
+ Value |= Mask;
+ }
+
+ WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
+ gBS->Stall (LAN91X_MDIO_STALL);
+ WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK);
+ gBS->Stall (LAN91X_MDIO_STALL);
+ }
+
+ return Value;
+}
+#define PHY_INPUT_TIME (2 * LAN91X_MDIO_STALL)
+
+STATIC
+VOID
+MdioIdle (
+ LAN91X_DRIVER *LanDriver
+ )
+{
+ UINT16 MgmtReg;
+
+ MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);
+ MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO);
+ WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
+}
+
+// Write to a PHY register
+STATIC
+VOID
+WritePhyReg16 (
+ LAN91X_DRIVER *LanDriver,
+ UINTN RegAd,
+ UINT16 Value
+ )
+{
+ // Bit-bang the MII Serial Frame write operation
+ MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble
+ MdioOutput (LanDriver, 2, 0x01); // Send Start (01)
+ MdioOutput (LanDriver, 2, 0x01); // Send Write (01)
+ MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0]
+ MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0]
+ MdioOutput (LanDriver, 2, 0x02); // Send TurnAround (10)
+ MdioOutput (LanDriver, 16, Value); // Write 16 data bits
+
+ // Idle the MDIO bus
+ MdioIdle (LanDriver);
+}
+// Calculate approximate time to write a PHY register in microseconds
+#define PHY_WRITE_TIME ((32 + 2 + 2 + 5 + 5 + 2 + 16) * PHY_OUTPUT_TIME)
+
+// Read from a PHY register
+STATIC
+UINT16
+ReadPhyReg16 (
+ LAN91X_DRIVER *LanDriver,
+ UINTN RegAd
+ )
+{
+ UINT32 Value;
+
+ // Bit-bang the MII Serial Frame read operation
+ MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble
+ MdioOutput (LanDriver, 2, 0x01); // Send Start (01)
+ MdioOutput (LanDriver, 2, 0x02); // Send Read (10)
+ MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0]
+ MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0]
+
+ (VOID) MdioInput (LanDriver, 2); // Discard TurnAround bits
+ Value = MdioInput (LanDriver, 16); // Read 16 data bits
+
+ // Idle the MDIO bus
+ MdioIdle (LanDriver);
+
+ return (Value & 0xffff);
+}
+// Calculate approximate time to read a PHY register in microseconds
+#define PHY_READ_TIME (((32 + 2 + 2 + 5 + 5) * PHY_OUTPUT_TIME) + \
+ ((2 + 16) * PHY_INPUT_TIME))
+
+
+/* ---------------- Debug Functions ------------------ */
+
+#ifdef LAN91X_PRINT_REGISTERS
+STATIC
+VOID
+PrintIoRegisters (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINTN Bank;
+ UINTN Offset;
+ UINT16 Value;
+
+ DEBUG((EFI_D_ERROR, "\nLAN91x I/O Register Dump:\n"));
+
+ // Print currrent bank select register
+ Value = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);
+ DEBUG((EFI_D_ERROR, " BankSel: %d Bank Register %04x (%d)\n",
+ LanDriver->BankSel, Value, Value & 0x0007));
+
+ // Print all I/O registers
+ for (Offset = 0; Offset < 0x0e; Offset += 2) {
+ DEBUG((EFI_D_ERROR, " %02x:", Offset));
+ for (Bank = 0; Bank <= 3; ++Bank) {
+ DEBUG((EFI_D_ERROR, " %04x", ReadIoReg16 (LanDriver, MakeRegister (Bank, Offset))));
+ }
+ DEBUG((EFI_D_ERROR, "\n"));
+ }
+}
+
+STATIC
+VOID
+PrintPhyRegisters (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINTN RegNum;
+
+ DEBUG((EFI_D_ERROR, "\nLAN91x Phy %d Register Dump:\n", LanDriver->PhyAd));
+
+ // Print all Phy registers
+ for (RegNum = 0; RegNum <= 5; ++RegNum) {
+ DEBUG((EFI_D_ERROR, " %2d: %04x\n",
+ RegNum,
+ ReadPhyReg16 (LanDriver, RegNum)
+ ));
+ }
+ for (RegNum = 16; RegNum <= 20; ++RegNum) {
+ DEBUG((EFI_D_ERROR, " %2d: %04x\n",
+ RegNum,
+ ReadPhyReg16 (LanDriver, RegNum)
+ ));
+ }
+}
+#endif
+
+#if LAN91X_PRINT_PACKET_HEADERS
+STATIC
+VOID
+PrintIpDgram (
+ IN CONST VOID *DstMac,
+ IN CONST VOID *SrcMac,
+ IN CONST VOID *Proto,
+ IN CONST VOID *IpDgram
+ )
+{
+ CONST UINT8 *Ptr;
+ UINT16 SrcPort;
+ UINT16 DstPort;
+
+ Ptr = DstMac;
+ DEBUG((EFI_D_ERROR, " Dst: %02x-%02x-%02x",
+ Ptr[0], Ptr[1], Ptr[2]));
+ DEBUG((EFI_D_ERROR, "-%02x-%02x-%02x",
+ Ptr[3], Ptr[4], Ptr[5]));
+
+ Ptr = SrcMac;
+ DEBUG((EFI_D_ERROR, " Src: %02x-%02x-%02x",
+ Ptr[0], Ptr[1], Ptr[2]));
+ DEBUG((EFI_D_ERROR, "-%02x-%02x-%02x",
+ Ptr[3], Ptr[4], Ptr[5]));
+
+ Ptr = Proto;
+ DEBUG((EFI_D_ERROR, " Proto: %02x%02x\n",
+ Ptr[0], Ptr[1]));
+
+ Ptr = IpDgram;
+ switch (Ptr[9]) {
+ case EFI_IP_PROTO_ICMP:
+ DEBUG((EFI_D_ERROR, " ICMP"));
+ break;
+ case EFI_IP_PROTO_TCP:
+ DEBUG((EFI_D_ERROR, " TCP"));
+ break;
+ case EFI_IP_PROTO_UDP:
+ DEBUG((EFI_D_ERROR, " UDP"));
+ break;
+ default:
+ DEBUG((EFI_D_ERROR, " IpProto %d\n", Ptr[9]));
+ return;
+ }
+
+ DEBUG((EFI_D_ERROR, " SrcIp: %d.%d.%d.%d",
+ Ptr[12], Ptr[13], Ptr[14], Ptr[15]));
+ DEBUG((EFI_D_ERROR, " DstIp: %d.%d.%d.%d",
+ Ptr[16], Ptr[17], Ptr[18], Ptr[19]));
+
+ SrcPort = (Ptr[20] << 8) | Ptr[21];
+ DstPort = (Ptr[22] << 8) | Ptr[23];
+ DEBUG((EFI_D_ERROR, " SrcPort: %d DstPort: %d\n", SrcPort, DstPort));
+}
+#endif
+
+
+/* ---------------- PHY Management Operations ----------------- */
+
+STATIC
+EFI_STATUS
+PhyDetect (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINT16 PhyId1;
+ UINT16 PhyId2;
+
+ for (LanDriver->PhyAd = 0x1f; LanDriver->PhyAd >= 0 ; --LanDriver->PhyAd) {
+ PhyId1 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID1);
+ PhyId2 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID2);
+
+ if ((PhyId1 != 0x0000) && (PhyId1 != 0xffff) &&
+ (PhyId2 != 0x0000) && (PhyId2 != 0xffff)) {
+ if ((PhyId1 == 0x0016) && ((PhyId2 & 0xfff0) == 0xf840)) {
+ DEBUG((EFI_D_ERROR, "LAN91x: PHY type LAN83C183 (LAN91C111 Internal)\n"));
+ } else if ((PhyId1 == 0x0282) && ((PhyId2 & 0xfff0) == 0x1c50)) {
+ DEBUG((EFI_D_ERROR, "LAN91x: PHY type LAN83C180\n"));
+ } else {
+ DEBUG((EFI_D_ERROR, "LAN91x: PHY id %04x:%04x\n", PhyId1, PhyId2));
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ DEBUG((EFI_D_ERROR, "LAN91x: PHY detection failed\n"));
+ return EFI_NO_MEDIA;
+}
+
+
+// Check the Link Status and take appropriate action
+STATIC
+BOOLEAN
+CheckLinkStatus (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINT16 PhyStatus;
+
+ // Get the PHY Status
+ PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS);
+
+ return (PhyStatus & PHYSTS_LINK_STS) != 0;
+}
+
+
+// Do auto-negotiation
+STATIC
+EFI_STATUS
+PhyAutoNegotiate (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINTN Retries;
+ UINT16 PhyControl;
+ UINT16 PhyStatus;
+ UINT16 PhyAdvert;
+
+ // If there isn't a PHY, don't try to reset it
+ if (LanDriver->PhyAd == LAN91X_NO_PHY) {
+ return EFI_SUCCESS;
+ }
+
+ // Next check that auto-negotiation is supported
+ PhyStatus = ReadPhyReg16 (LanDriver, 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;
+ }
+
+ // Set the capabilities to advertise
+ WritePhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert);
+ (VOID) ReadPhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT);
+
+ // Restart Auto-Negotiation
+ PhyControl = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL);
+ PhyControl &= ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE);
+ PhyControl |= PHYCR_AUTO_EN | PHYCR_RST_AUTO;
+ WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PhyControl);
+
+ // Wait up to 2 seconds for the process to complete
+ Retries = 2000000 / (PHY_READ_TIME + 100);
+ while ((ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0) {
+ if (--Retries == 0) {
+ DEBUG((EFI_D_ERROR, "LAN91x: PHY auto-negotiation timed-out\n"));
+ return EFI_TIMEOUT;
+ }
+ gBS->Stall (100);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+// Perform PHY software reset
+STATIC
+EFI_STATUS
+PhySoftReset (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINTN Retries;
+
+ // If there isn't a PHY, don't try to reset it
+ if (LanDriver->PhyAd == LAN91X_NO_PHY) {
+ return EFI_SUCCESS;
+ }
+
+ // Request a PHY reset
+ WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PHYCR_RESET);
+
+ // The internal PHY will reset within 50ms. Allow 100ms.
+ Retries = 100000 / (PHY_READ_TIME + 100);
+ while (ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) {
+ if (--Retries == 0) {
+ DEBUG((EFI_D_ERROR, "LAN91x: PHY reset timed-out\n"));
+ return EFI_TIMEOUT;
+ }
+ gBS->Stall (100);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/* ---------------- General Operations ----------------- */
+
+STATIC
+EFI_MAC_ADDRESS
+GetCurrentMacAddress (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINTN RegNum;
+ UINT8 *Addr;
+ EFI_MAC_ADDRESS MacAddress;
+
+ SetMem (&MacAddress, sizeof(MacAddress), 0);
+
+ Addr = &MacAddress.Addr[0];
+ for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) {
+ *Addr = ReadIoReg8 (LanDriver, RegNum);
+ ++Addr;
+ }
+
+ return MacAddress;
+}
+
+STATIC
+EFI_STATUS
+SetCurrentMacAddress (
+ IN LAN91X_DRIVER *LanDriver,
+ IN EFI_MAC_ADDRESS *MacAddress
+ )
+{
+ UINTN RegNum;
+ UINT8 *Addr;
+
+ Addr = &MacAddress->Addr[0];
+ for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) {
+ WriteIoReg8 (LanDriver, RegNum, *Addr);
+ ++Addr;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MmuOperation (
+ IN LAN91X_DRIVER *LanDriver,
+ IN UINTN MmuOp
+ )
+{
+ UINTN Polls;
+
+ WriteIoReg16 (LanDriver, LAN91X_MMUCR, MmuOp);
+ Polls = 100;
+ while ((ReadIoReg16 (LanDriver, LAN91X_MMUCR) & MMUCR_BUSY) != 0) {
+ if (--Polls == 0) {
+ DEBUG((EFI_D_ERROR, "LAN91x: MMU operation %04x timed-out\n", MmuOp));
+ return EFI_TIMEOUT;
+ }
+ gBS->Stall (LAN91X_STALL);
+ }
+
+ return EFI_SUCCESS;
+}
+
+// Read bytes from the DATA register
+STATIC
+EFI_STATUS
+ReadIoData (
+ IN LAN91X_DRIVER *LanDriver,
+ IN VOID *Buffer,
+ IN UINTN BufLen
+ )
+{
+ UINT8 *Ptr;
+
+ Ptr = Buffer;
+ for (; BufLen > 0; --BufLen) {
+ *Ptr = ReadIoReg8 (LanDriver, LAN91X_DATA0);
+ ++Ptr;
+ }
+
+ return EFI_SUCCESS;
+}
+
+// Write bytes to the DATA register
+STATIC
+EFI_STATUS
+WriteIoData (
+ IN LAN91X_DRIVER *LanDriver,
+ IN VOID *Buffer,
+ IN UINTN BufLen
+ )
+{
+ UINT8 *Ptr;
+
+ Ptr = Buffer;
+ for (; BufLen > 0; --BufLen) {
+ WriteIoReg8 (LanDriver, LAN91X_DATA0, *Ptr);
+ ++Ptr;
+ }
+
+ return EFI_SUCCESS;
+}
+
+// Disable the interface
+STATIC
+EFI_STATUS
+ChipDisable (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+#ifdef LAN91X_POWER_DOWN
+ UINT16 Val16;
+#endif
+
+ // Stop Rx and Tx operations
+ WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);
+ WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR);
+
+#ifdef LAN91X_POWER_DOWN
+ // Power-down the chip
+ Val16 = ReadIoReg16 (LanDriver, LAN91X_CR);
+ Val16 &= ~CR_EPH_POWER_EN;
+ WriteIoReg16 (LanDriver, LAN91X_CR, Val16);
+#endif
+
+ return EFI_SUCCESS;
+}
+
+// Enable the interface
+STATIC
+EFI_STATUS
+ChipEnable (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+#ifdef LAN91X_POWER_DOWN
+ UINT16 Val16;
+
+ // Power-up the chip
+ Val16 = ReadIoReg16 (LanDriver, LAN91X_CR);
+ Val16 |= CR_EPH_POWER_EN;
+ WriteIoReg16 (LanDriver, LAN91X_CR, Val16);
+ gBS->Stall (LAN91X_STALL);
+#endif
+
+ // Start Rx and Tx operations
+ WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_DEFAULT);
+ WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_DEFAULT);
+
+ return EFI_SUCCESS;
+}
+
+
+// Perform software reset on the LAN91x
+STATIC
+EFI_STATUS
+SoftReset (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINT16 Val16;
+
+ // Issue the reset
+ WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_SOFT_RST);
+ gBS->Stall (LAN91X_STALL);
+ WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);
+
+ // Set the configuration register
+ WriteIoReg16 (LanDriver, LAN91X_CR, CR_DEFAULT);
+ gBS->Stall (LAN91X_STALL);
+
+ // Stop Rx and Tx
+ WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);
+ WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR);
+
+ // Initialize the Control Register
+ Val16 = ReadIoReg16 (LanDriver, LAN91X_CTR);
+ Val16 |= CTR_AUTO_REL;
+ WriteIoReg16 (LanDriver, LAN91X_CTR, Val16);
+
+ // Reset the MMU
+ MmuOperation (LanDriver, MMUCR_OP_RESET_MMU);
+
+ return EFI_SUCCESS;
+}
+
+/*
+** Probe()
+**
+** Validate that there is a LAN91x device.
+**
+*/
+STATIC
+EFI_STATUS
+Probe (
+ IN LAN91X_DRIVER *LanDriver
+ )
+{
+ UINT16 Bank;
+ UINT16 Val16;
+ CHAR16 CONST *ChipId;
+ UINTN ResetTime;
+
+ // First check that the Bank Select register is valid
+ Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);
+ if ((Bank & 0xff00) != 0x3300) {
+ DEBUG((EFI_D_ERROR, "LAN91x: signature error: expecting 33xx, read %04x\n", Bank));
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Try reading the revision register next
+ LanDriver->BankSel = 0xff;
+ Val16 = ReadIoReg16 (LanDriver, LAN91X_REV);
+
+ Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);
+ if ((Bank & 0xff03) != 0x3303) {
+ DEBUG((EFI_D_ERROR, "LAN91x: signature error: expecting 33x3, read %04x\n", Bank));
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Validate the revision register
+ if ((Val16 & 0xff00) != 0x3300) {
+ DEBUG((EFI_D_ERROR, "LAN91x: revision error: expecting 33xx, read %04x\n", Val16));
+ return EFI_DEVICE_ERROR;
+ }
+
+ ChipId = ChipIds[(Val16 >> 4) & 0x0f];
+ if (ChipId == NULL) {
+ DEBUG((EFI_D_ERROR, "LAN91x: unrecognized revision: %04x\n", Val16));
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG((EFI_D_ERROR, "LAN91x: detected chip %s rev %d\n", ChipId, Val16 & 0xf));
+ LanDriver->Revision = Val16 & 0xff;
+
+ // Reload from EEPROM to get the hardware MAC address
+ WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED | CTR_RELOAD);
+ ResetTime = 1000;
+ while ((ReadIoReg16 (LanDriver, LAN91X_CTR) & CTR_RELOAD) != 0) {
+ if (--ResetTime == 0) {
+ DEBUG((EFI_D_ERROR, "LAN91x: reload from EEPROM timed-out\n"));
+ WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED);
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall (LAN91X_STALL);
+ }
+
+ // Read and save the Permanent MAC Address
+ LanDriver->SnpMode.PermanentAddress = GetCurrentMacAddress (LanDriver);
+ DEBUG((EFI_D_ERROR, //EFI_D_NET | EFI_D_INFO,
+ "LAN91x: HW MAC Address: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ LanDriver->SnpMode.PermanentAddress.Addr[0],
+ LanDriver->SnpMode.PermanentAddress.Addr[1],
+ LanDriver->SnpMode.PermanentAddress.Addr[2],
+ LanDriver->SnpMode.PermanentAddress.Addr[3],
+ LanDriver->SnpMode.PermanentAddress.Addr[4],
+ LanDriver->SnpMode.PermanentAddress.Addr[5]
+ ));
+
+ // Reset the device
+ SoftReset (LanDriver);
+
+ // Try to detect a PHY
+ if (LanDriver->Revision > (CHIP_91100 << 4)) {
+ PhyDetect (LanDriver);
+ } else {
+ LanDriver->PhyAd = LAN91X_NO_PHY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/*------------------ Simple Network Driver entry point functions ------------------*/
+
+// Refer to the Simple Network Protocol section (21.1)
+// in the UEFI 2.3.1 Specification for documentation.
+
+#define ReturnUnlock(s) do { Status = (s); goto exit_unlock; } while(0)
+
+
+/*
+** UEFI Start() function
+**
+*/
+EFI_STATUS
+EFIAPI
+SnpStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+ )
+{
+ EFI_SIMPLE_NETWORK_MODE *Mode;
+ 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 (LAN91X_TPL);
+ Mode = Snp->Mode;
+
+ // Check state of the driver
+ switch (Mode->State) {
+ case EfiSimpleNetworkStopped:
+ break;
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver already started\n"));
+ ReturnUnlock (EFI_ALREADY_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Set the Current MAC address
+ Mode->CurrentAddress = Mode->PermanentAddress;
+
+ // Change state
+ 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
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ 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 (LAN91X_TPL);
+
+ // Check state of the driver
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Stop the Tx and Rx
+ ChipDisable (LanDriver);
+
+ // Change the state
+ Snp->Mode->State = EfiSimpleNetworkStopped;
+ Status = EFI_SUCCESS;
+
+ // Restore TPL and return
+exit_unlock:
+ gBS->RestoreTPL (SavedTpl);
+ return Status;
+}
+
+/*
+** UEFI Initialize() function
+**
+*/
+EFI_STATUS
+EFIAPI
+SnpInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
+ IN UINTN RxBufferSize OPTIONAL,
+ IN UINTN TxBufferSize OPTIONAL
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ 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 (LAN91X_TPL);
+
+ // Check that driver was started but not initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkStarted:
+ break;
+ case EfiSimpleNetworkInitialized:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver already initialized\n"));
+ ReturnUnlock (EFI_SUCCESS);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Initiate a software reset
+ Status = SoftReset (LanDriver);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_WARN, "LAN91x: Soft reset failed\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Initiate a PHY reset
+ if (PhySoftReset (LanDriver) < 0) {
+ Snp->Mode->State = EfiSimpleNetworkStopped;
+ DEBUG((EFI_D_WARN, "LAN91x: PHY soft reset timeout\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ }
+
+ // Do auto-negotiation
+ Status = PhyAutoNegotiate (LanDriver);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_WARN, "LAN91x: PHY auto-negotiation failed\n"));
+ }
+
+ // Enable the receiver and transmitter
+ ChipEnable (LanDriver);
+
+ // Now acknowledge all interrupts
+ WriteIoReg8 (LanDriver, LAN91X_IST, 0xFF);
+
+ // Declare the driver as initialized
+ Snp->Mode->State = EfiSimpleNetworkInitialized;
+ Status = EFI_SUCCESS;
+
+ // 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
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ 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 (LAN91X_TPL);
+
+ // Check that driver was started and initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Initiate a software reset
+ if (EFI_ERROR (SoftReset (LanDriver))) {
+ DEBUG((EFI_D_WARN, "LAN91x: Soft reset failed\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Initiate a PHY reset
+ if (EFI_ERROR (PhySoftReset (LanDriver))) {
+ DEBUG((EFI_D_WARN, "LAN91x: PHY soft reset failed\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Enable the receiver and transmitter
+ Status = ChipEnable (LanDriver);
+
+ // Restore TPL and return
+exit_unlock:
+ gBS->RestoreTPL (SavedTpl);
+ return Status;
+}
+
+/*
+** UEFI Shutdown () function
+**
+*/
+EFI_STATUS
+EFIAPI
+SnpShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ 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 (LAN91X_TPL);
+
+ // First check that driver has already been initialized
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver in stopped state\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Disable the interface
+ Status = ChipDisable (LanDriver);
+
+ // 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
+ )
+{
+#define MCAST_HASH_BYTES 8
+
+ LAN91X_DRIVER *LanDriver;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ EFI_TPL SavedTpl;
+ EFI_STATUS Status;
+ UINTN i;
+ UINT32 Crc;
+ UINT16 RcvCtrl;
+ UINT8 McastHash[MCAST_HASH_BYTES];
+
+ // Check Snp Instance
+ if (Snp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Serialize access to data and registers
+ SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
+
+ // First check that driver has already been initialized
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+ SnpMode = Snp->Mode;
+
+#ifdef LAN91X_PRINT_RECEIVE_FILTERS
+ DEBUG((EFI_D_ERROR, "LAN91x:SnpReceiveFilters()\n"));
+ DEBUG((EFI_D_ERROR, " Enable = %08x\n", Enable));
+ DEBUG((EFI_D_ERROR, " Disable = %08x\n", Disable));
+ DEBUG((EFI_D_ERROR, " Reset = %d\n", Reset));
+ DEBUG((EFI_D_ERROR, " NumMfilter = %d\n", NumMfilter));
+ for (i = 0; i < NumMfilter; ++i) {
+ DEBUG((EFI_D_ERROR,
+ " [%2d] = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ i,
+ Mfilter[i].Addr[0],
+ Mfilter[i].Addr[1],
+ Mfilter[i].Addr[2],
+ Mfilter[i].Addr[3],
+ Mfilter[i].Addr[4],
+ Mfilter[i].Addr[5]));
+ }
+#endif
+
+ // Update the Multicast Hash registers
+ if (Reset) {
+ // Clear the hash table
+ SetMem (McastHash, MCAST_HASH_BYTES, 0);
+ SnpMode->MCastFilterCount = 0;
+ } else {
+ // Read the current hash table
+ for (i = 0; i < MCAST_HASH_BYTES; ++i) {
+ McastHash[i] = ReadIoReg8 (LanDriver, LAN91X_MT0 + i);
+ }
+ // Set the new additions
+ for (i = 0; i < NumMfilter; ++i) {
+ Crc = MulticastHash (&Mfilter[i], NET_ETHER_ADDR_LEN);
+ McastHash[(Crc >> 29) & 0x3] |= 1 << ((Crc >> 26) & 0x3);
+ }
+ SnpMode->MCastFilterCount = NumMfilter;
+ }
+ // If the hash registers need updating, write them
+ if (Reset || NumMfilter > 0) {
+ for (i = 0; i < MCAST_HASH_BYTES; ++i) {
+ WriteIoReg8 (LanDriver, LAN91X_MT0 + i, McastHash[i]);
+ }
+ }
+
+ RcvCtrl = ReadIoReg16 (LanDriver, LAN91X_RCR);
+ if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ RcvCtrl |= RCR_PRMS;
+ SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ }
+ if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ RcvCtrl &= ~RCR_PRMS;
+ SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ }
+
+ if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ RcvCtrl |= RCR_ALMUL;
+ SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ }
+ if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ RcvCtrl &= ~RCR_ALMUL;
+ SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ }
+ WriteIoReg16 (LanDriver, LAN91X_RCR, RcvCtrl);
+
+ Status = SetCurrentMacAddress (LanDriver, &SnpMode->CurrentAddress);
+
+ // 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
+)
+{
+ LAN91X_DRIVER *LanDriver;
+ 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 (LAN91X_TPL);
+
+ // Check that driver was started and initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ if (Reset) {
+ Snp->Mode->CurrentAddress = Snp->Mode->PermanentAddress;
+ } else {
+ if (NewMac == NULL) {
+ ReturnUnlock (EFI_INVALID_PARAMETER);
+ }
+ Snp->Mode->CurrentAddress = *NewMac;
+ }
+
+ Status = SetCurrentMacAddress (LanDriver, &Snp->Mode->CurrentAddress);
+
+ // 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
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ EFI_TPL SavedTpl;
+ EFI_STATUS Status;
+
+ // 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 (LAN91X_TPL);
+
+ // Check that driver was started and initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // 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);
+ goto exit_unlock;
+ }
+
+ // 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
+ )
+{
+ // 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((EFI_D_ERROR, "LAN91x: Non-volatile storage not supported\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
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ EFI_TPL SavedTpl;
+ EFI_STATUS Status;
+ BOOLEAN MediaPresent;
+ UINT8 IstReg;
+
+ // Check preliminaries
+ if (Snp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Serialize access to data and registers
+ SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
+
+ // Check that driver was started and initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Arbitrarily set the interrupt status to 0
+ if (IrqStat != NULL) {
+ *IrqStat = 0;
+ IstReg = ReadIoReg8 (LanDriver, LAN91X_IST);
+ if ((IstReg & IST_RCV) != 0) {
+ *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ }
+ if ((IstReg & IST_TX) != 0) {
+ *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+ }
+
+ // Pass back the completed buffer address
+ if (TxBuff != NULL) {
+ *TxBuff = TxQueRemove (LanDriver);
+ }
+
+ // Update the media status
+ MediaPresent = CheckLinkStatus (LanDriver);
+ if (MediaPresent != Snp->Mode->MediaPresent) {
+ DEBUG((EFI_D_WARN, "LAN91x: 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 BufSize,
+ IN VOID *BufAddr,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ LAN91X_DRIVER *LanDriver;
+ EFI_TPL SavedTpl;
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINTN Len;
+ UINTN MmuPages;
+ UINTN Retries;
+ UINT16 Proto;
+ UINT8 PktNum;
+
+ // Check preliminaries
+ if ((Snp == NULL) || (BufAddr == NULL)) {
+ DEBUG((EFI_D_ERROR, "LAN91x: SnpTransmit(): NULL Snp (%p) or BufAddr (%p)\n",
+ Snp, BufAddr));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Serialize access to data and registers
+ SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
+
+ // Check that driver was started and initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Ensure header is correct size if non-zero
+ if (HdrSize != 0) {
+ if (HdrSize != Snp->Mode->MediaHeaderSize) {
+ DEBUG((EFI_D_ERROR, "LAN91x: SnpTransmit(): Invalid HdrSize %d\n", HdrSize));
+ ReturnUnlock (EFI_INVALID_PARAMETER);
+ }
+
+ if ((DstAddr == NULL) || (Protocol == NULL)) {
+ DEBUG((EFI_D_ERROR, "LAN91x: SnpTransmit(): NULL DstAddr %p or Protocol %p\n",
+ DstAddr, Protocol));
+ ReturnUnlock (EFI_INVALID_PARAMETER);
+ }
+ }
+
+ // Before transmitting check the link status
+ if (!Snp->Mode->MediaPresent) {
+ DEBUG((EFI_D_WARN, "LAN91x: SnpTransmit(): Link not ready\n"));
+ ReturnUnlock (EFI_NOT_READY);
+ }
+
+ // Calculate the request size in 256-byte "pages" minus 1
+ // The 91C111 ignores this, but some older devices need it.
+ MmuPages = ((BufSize & ~1) + LAN91X_PKT_OVERHEAD - 1) >> 8;
+ if (MmuPages > 7) {
+ DEBUG((EFI_D_WARN, "LAN91x: Tx buffer too large (%d bytes)\n", BufSize));
+ LanDriver->Stats.TxOversizeFrames += 1;
+ LanDriver->Stats.TxDroppedFrames += 1;
+ ReturnUnlock (EFI_BAD_BUFFER_SIZE);
+ }
+
+ // Request allocation of a transmit buffer
+ Status = MmuOperation (LanDriver, MMUCR_OP_TX_ALLOC | MmuPages);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer request failure: %d\n", Status));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Wait for allocation request completion
+ Retries = LAN91X_MEMORY_ALLOC_POLLS;
+ while ((ReadIoReg8 (LanDriver, LAN91X_IST) & IST_ALLOC) == 0) {
+ if (--Retries == 0) {
+ DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer allocation timeout\n"));
+ ReturnUnlock (EFI_TIMEOUT);
+ }
+ }
+
+ // Check for successful allocation
+ PktNum = ReadIoReg8 (LanDriver, LAN91X_ARR);
+ if ((PktNum & ARR_FAILED) != 0) {
+ DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer allocation failure: %02x\n", PktNum));
+ ReturnUnlock (EFI_NOT_READY);
+ }
+ PktNum &= ARR_PACKET;
+
+ // Check for the nature of the frame
+ if (DstAddr->Addr[0] == 0xFF) {
+ LanDriver->Stats.TxBroadcastFrames += 1;
+ } else if ((DstAddr->Addr[0] & 0x1) == 1) {
+ LanDriver->Stats.TxMulticastFrames += 1;
+ } else {
+ LanDriver->Stats.TxUnicastFrames += 1;
+ }
+
+ // Set the Packet Number and Pointer registers
+ WriteIoReg8 (LanDriver, LAN91X_PNR, PktNum);
+ WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_AUTO_INCR);
+
+ // Set up mutable buffer information variables
+ Ptr = BufAddr;
+ Len = BufSize;
+
+ // Write Status and Byte Count first
+ WriteIoReg16 (LanDriver, LAN91X_DATA0, 0);
+ WriteIoReg16 (LanDriver, LAN91X_DATA0, (Len + LAN91X_PKT_OVERHEAD) & BCW_COUNT);
+
+ // This packet may come with a preconfigured Ethernet header.
+ // If not, we need to construct one from optional parameters.
+ if (HdrSize) {
+
+ // Write the destination address
+ WriteIoData (LanDriver, DstAddr, NET_ETHER_ADDR_LEN);
+
+ // Write the Source Address
+ if (SrcAddr != NULL) {
+ WriteIoData (LanDriver, SrcAddr, NET_ETHER_ADDR_LEN);
+ } else {
+ WriteIoData (LanDriver, &LanDriver->SnpMode.CurrentAddress, NET_ETHER_ADDR_LEN);
+ }
+
+ // Write the Protocol word
+ Proto = HTONS (*Protocol);
+ WriteIoReg16 (LanDriver, LAN91X_DATA0, Proto);
+
+ // Adjust the data start and length
+ Ptr += sizeof(ETHER_HEAD);
+ Len -= sizeof(ETHER_HEAD);
+ }
+
+ // Copy the remainder data buffer, except the odd byte
+ WriteIoData (LanDriver, Ptr, Len & ~1);
+ Ptr += Len & ~1;
+ Len &= 1;
+
+ // Write the Packet Control Word and odd byte
+ WriteIoReg16 (LanDriver, LAN91X_DATA0,
+ (Len != 0) ? (PCW_ODD | PCW_CRC | *Ptr) : PCW_CRC);
+
+ // Release the packet for transmission
+ Status = MmuOperation (LanDriver, MMUCR_OP_TX_PUSH);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "LAN91x: Tx buffer release failure: %d\n", Status));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Update the Rx statistics
+ LanDriver->Stats.TxTotalBytes += BufSize;
+ LanDriver->Stats.TxGoodFrames += 1;
+
+ // Update the Tx Buffer cache
+ if (!TxQueInsert (LanDriver, BufAddr)) {
+ DEBUG((EFI_D_WARN, "LAN91x: SnpTransmit(): TxQueue insert failure.\n"));
+ }
+ Status = EFI_SUCCESS;
+
+ // Dump the packet header
+#if LAN91X_PRINT_PACKET_HEADERS
+ Ptr = BufAddr;
+ DEBUG((EFI_D_ERROR, "LAN91X:SnpTransmit()\n"));
+ DEBUG((EFI_D_ERROR, " HdrSize: %d, SrcAddr: %p, Length: %d, Last byte: %02x\n",
+ HdrSize, SrcAddr, BufSize, Ptr[BufSize - 1]));
+ PrintIpDgram (
+ (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[0] : DstAddr,
+ (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[6] : (SrcAddr != NULL) ? SrcAddr : &LanDriver->SnpMode.CurrentAddress,
+ (HdrSize == 0) ? (UINT16 *)&Ptr[12] : &Proto,
+ &Ptr[14]
+ );
+#endif
+
+ // Restore TPL and return
+exit_unlock:
+ 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;
+ LAN91X_DRIVER *LanDriver;
+ UINT8 *DataPtr;
+ UINT16 PktStatus;
+ UINT16 PktLength;
+ UINT16 PktControl;
+ UINT8 IstReg;
+
+ // Check preliminaries
+ if ((Snp == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Serialize access to data and registers
+ SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
+
+ // Check that driver was started and initialised
+ switch (Snp->Mode->State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+ case EfiSimpleNetworkStarted:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not yet initialized\n"));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ case EfiSimpleNetworkStopped:
+ DEBUG((EFI_D_WARN, "LAN91x: Driver not started\n"));
+ ReturnUnlock (EFI_NOT_STARTED);
+ default:
+ DEBUG((EFI_D_ERROR, "LAN91x: Driver in an invalid state: %u\n",
+ (UINTN)Snp->Mode->State));
+ ReturnUnlock (EFI_DEVICE_ERROR);
+ }
+
+ // Find the LanDriver structure
+ LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
+
+ // Check for Rx Overrun
+ IstReg = ReadIoReg8 (LanDriver, LAN91X_IST);
+ if ((IstReg & IST_RX_OVRN) != 0) {
+ LanDriver->Stats.RxTotalFrames += 1;
+ LanDriver->Stats.RxDroppedFrames += 1;
+ WriteIoReg8 (LanDriver, LAN91X_IST, IST_RX_OVRN);
+ DEBUG((EFI_D_WARN, "LAN91x: Receiver overrun\n"));
+ }
+
+ // Check for Rx data available
+ if ((IstReg & IST_RCV) == 0) {
+ ReturnUnlock (EFI_NOT_READY);
+ }
+
+ // Configure the PTR register for reading
+ WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_RCV | PTR_AUTO_INCR | PTR_READ);
+
+ // Read the Packet Status and Packet Length words
+ PktStatus = ReadIoReg16 (LanDriver, LAN91X_DATA0);
+ PktLength = ReadIoReg16 (LanDriver, LAN91X_DATA0) & BCW_COUNT;
+
+ // Check for valid received packet
+ if ((PktStatus == 0) && (PktLength == 0)) {
+ DEBUG((EFI_D_WARN, "LAN91x: Received zero-length packet. IST=%04x\n", IstReg));
+ ReturnUnlock (EFI_NOT_READY);
+ }
+ LanDriver->Stats.RxTotalFrames += 1;
+
+ // Check if we got a CRC error
+ if ((PktStatus & RX_BAD_CRC) != 0) {
+ DEBUG((EFI_D_WARN, "LAN91x: Received frame CRC error\n"));
+ LanDriver->Stats.RxCrcErrorFrames += 1;
+ LanDriver->Stats.RxDroppedFrames += 1;
+ Status = EFI_DEVICE_ERROR;
+ goto exit_release;
+ }
+
+ // Check if we got a too-short frame
+ if ((PktStatus & RX_TOO_SHORT) != 0) {
+ DEBUG((EFI_D_WARN, "LAN91x: Received frame too short (%d bytes)\n", PktLength));
+ LanDriver->Stats.RxUndersizeFrames += 1;
+ LanDriver->Stats.RxDroppedFrames += 1;
+ Status = EFI_DEVICE_ERROR;
+ goto exit_release;
+ }
+
+ // Check if we got a too-long frame
+ if ((PktStatus & RX_TOO_LONG) != 0) {
+ DEBUG((EFI_D_WARN, "LAN91x: Received frame too long (%d bytes)\n", PktLength));
+ LanDriver->Stats.RxOversizeFrames += 1;
+ LanDriver->Stats.RxDroppedFrames += 1;
+ Status = EFI_DEVICE_ERROR;
+ goto exit_release;
+ }
+
+ // Check if we got an alignment error
+ if ((PktStatus & RX_ALGN_ERR) != 0) {
+ DEBUG((EFI_D_WARN, "LAN91x: Received frame alignment error\n"));
+ // Don't seem to keep track of these specifically
+ LanDriver->Stats.RxDroppedFrames += 1;
+ Status = EFI_DEVICE_ERROR;
+ goto exit_release;
+ }
+
+ // Classify the received fram
+ if ((PktStatus & RX_MULTICAST) != 0) {
+ LanDriver->Stats.RxMulticastFrames += 1;
+ } else if ((PktStatus & RX_BROADCAST) != 0) {
+ LanDriver->Stats.RxBroadcastFrames += 1;
+ } else {
+ LanDriver->Stats.RxUnicastFrames += 1;
+ }
+
+ // Calculate the received packet data length
+ PktLength -= LAN91X_PKT_OVERHEAD;
+ if ((PktStatus & RX_ODD_FRAME) != 0) {
+ PktLength += 1;
+ }
+
+ // Check buffer size
+ if (*BuffSize < PktLength) {
+ DEBUG((EFI_D_WARN, "LAN91x: Receive buffer too small for packet (%d < %d)\n",
+ *BuffSize, PktLength));
+ *BuffSize = PktLength;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto exit_release;
+ }
+
+ // Transfer the data bytes
+ DataPtr = Data;
+ ReadIoData (LanDriver, DataPtr, PktLength & ~0x0001);
+
+ // Read the PktControl and Odd Byte from the FIFO
+ PktControl = ReadIoReg16 (LanDriver, LAN91X_DATA0);
+ if ((PktControl & PCW_ODD) != 0) {
+ DataPtr[PktLength - 1] = PktControl & PCW_ODD_BYTE;
+ }
+
+ // Update buffer size
+ *BuffSize = PktLength;
+
+ if (HdrSize != NULL) {
+ *HdrSize = LanDriver->SnpMode.MediaHeaderSize;
+ }
+
+ // Extract the destination address
+ if (DstAddr != NULL) {
+ CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN);
+ }
+
+ // Get the source address
+ if (SrcAddr != NULL) {
+ CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN);
+ }
+
+ // Get the protocol
+ if (Protocol != NULL) {
+ *Protocol = NTOHS (*(UINT16*)(&DataPtr[12]));
+ }
+
+ // Update the Rx statistics
+ LanDriver->Stats.RxTotalBytes += PktLength;
+ LanDriver->Stats.RxGoodFrames += 1;
+ Status = EFI_SUCCESS;
+
+#if LAN91X_PRINT_PACKET_HEADERS
+ // Dump the packet header
+ DEBUG((EFI_D_ERROR, "LAN91X:SnpReceive()\n"));
+ DEBUG((EFI_D_ERROR, " HdrSize: %p, SrcAddr: %p, DstAddr: %p, Protocol: %p\n",
+ HdrSize, SrcAddr, DstAddr, Protocol));
+ DEBUG((EFI_D_ERROR, " Length: %d, Last byte: %02x\n", PktLength, DataPtr[PktLength - 1]));
+ PrintIpDgram (&DataPtr[0], &DataPtr[6], &DataPtr[12], &DataPtr[14]);
+#endif
+
+ // Release the FIFO buffer
+exit_release:
+ MmuOperation (LanDriver, MMUCR_OP_RX_POP_REL);
+
+ // Restore TPL and return
+exit_unlock:
+ gBS->RestoreTPL (SavedTpl);
+ return Status;
+}
+
+
+/*------------------ Driver Execution Environment main entry point ------------------*/
+
+/*
+** Entry point for the LAN91x driver
+**
+*/
+EFI_STATUS
+Lan91xDxeEntry (
+ IN EFI_HANDLE Handle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LAN91X_DRIVER *LanDriver;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ LAN91X_DEVICE_PATH *Lan91xPath;
+
+ // The PcdLan91xDxeBaseAddress PCD must be defined
+ ASSERT(PcdGet32 (PcdLan91xDxeBaseAddress) != 0);
+
+ // Allocate Resources
+ LanDriver = AllocateZeroPool (sizeof(LAN91X_DRIVER));
+ Lan91xPath = AllocateCopyPool (sizeof(LAN91X_DEVICE_PATH), &Lan91xPathTemplate);
+
+ // Initialize I/O Space access info
+ LanDriver->IoBase = PcdGet32 (PcdLan91xDxeBaseAddress);
+ LanDriver->PhyAd = LAN91X_NO_PHY;
+ LanDriver->BankSel = 0xff;
+
+ // Initialize pointers
+ Snp = &(LanDriver->Snp);
+ SnpMode = &(LanDriver->SnpMode);
+ Snp->Mode = SnpMode;
+
+ // Set the signature of the LAN Driver structure
+ LanDriver->Signature = LAN91X_SIGNATURE;
+
+ // Probe the device
+ Status = Probe (LanDriver);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR, "LAN91x:Lan91xDxeEntry(): Probe failed with status %d\n", Status));
+ return Status;
+ }
+
+#ifdef LAN91X_PRINT_REGISTERS
+ PrintIoRegisters (LanDriver);
+ PrintPhyRegisters (LanDriver);
+#endif
+
+ // 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;
+
+ // Fill in simple network mode structure
+ SnpMode->State = EfiSimpleNetworkStopped;
+ SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes
+ SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Size of an Ethernet header
+ SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Ethernet Frame (with VLAN tag +4 bytes)
+
+ // Supported receive filters
+ 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;
+
+ // Initially-enabled receive filters
+ SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ // LAN91x has 64bit hash table. We can filter an infinite MACs, but
+ // higher-level software must filter out any hash collisions.
+ 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
+ SnpMode->MacAddressChangeable = TRUE;
+
+ // We 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
+ Lan91xPath->Lan91x.MacAddress = SnpMode->PermanentAddress;
+ Lan91xPath->Lan91x.IfType = SnpMode->IfType;
+
+ // Initialise the protocol
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &LanDriver->ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid, Snp,
+ &gEfiDevicePathProtocolGuid, Lan91xPath,
+ NULL
+ );
+
+ // Say what the status of loading the protocol structure is
+ if (EFI_ERROR(Status)) {
+ FreePool (LanDriver);
+ }
+
+ return Status;
+}
diff --git a/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf
new file mode 100644
index 000000000..c7ef43ba2
--- /dev/null
+++ b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxe.inf
@@ -0,0 +1,58 @@
+#/** @file
+# INF file for the SMSC LAN91x series Network Controller Driver.
+#
+# Copyright (c) 2013 Linaro.org
+#
+# Derived from the LAN9118 driver. Original sources
+# 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 = LAN91xDxe
+ FILE_GUID = 5c12ea2f-9897-48af-8138-25f4ce6ff8d6
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = Lan91xDxeEntry
+
+[Sources.common]
+ LAN91xDxe.c
+ LAN91xDxeHw.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.PcdLan91xDxeBaseAddress
+
+[Depex]
+ TRUE
diff --git a/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h
new file mode 100644
index 000000000..9274ba072
--- /dev/null
+++ b/ArmPlatformPkg/Drivers/LAN91xDxe/LAN91xDxeHw.h
@@ -0,0 +1,278 @@
+/** @file
+* SMSC LAN91x series Network Controller Driver.
+*
+* Copyright (c) 2013 Linaro.org
+*
+* 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 __LAN91XDXEHW_H__
+#define __LAN91XDXEHW_H__
+
+#include <Base.h>
+
+#define MakeRegister(Bank, Offset) (((Bank) << 8) | (Offset))
+#define RegisterToBank(Register) (((Register) >> 8) & 0x07)
+#define RegisterToOffset(Register) ((Register) & 0x0f)
+
+/*---------------------------------------------------------------------------------------------------------------------
+
+ SMSC LAN91x Registers
+
+---------------------------------------------------------------------------------------------------------------------*/
+#define LAN91X_BANK_OFFSET 0xe // Bank Select Register (all banks)
+
+#define LAN91X_TCR MakeRegister (0, 0x0) // Transmit Control Register
+#define LAN91X_EPHSR MakeRegister (0, 0x2) // EPH Status Register
+#define LAN91X_RCR MakeRegister (0, 0x4) // Receive Control Register
+#define LAN91X_ECR MakeRegister (0, 0x6) // Counter Register
+#define LAN91X_MIR MakeRegister (0, 0x8) // Memory Information Register
+#define LAN91X_RPCR MakeRegister (0, 0xa) // Receive/Phy Control Register
+
+#define LAN91X_CR MakeRegister (1, 0x0) // Configuration Register
+#define LAN91X_BAR MakeRegister (1, 0x2) // Base Address Register
+#define LAN91X_IAR0 MakeRegister (1, 0x4) // Individual Address Register 0
+#define LAN91X_IAR1 MakeRegister (1, 0x5) // Individual Address Register 1
+#define LAN91X_IAR2 MakeRegister (1, 0x6) // Individual Address Register 2
+#define LAN91X_IAR3 MakeRegister (1, 0x7) // Individual Address Register 3
+#define LAN91X_IAR4 MakeRegister (1, 0x8) // Individual Address Register 4
+#define LAN91X_IAR5 MakeRegister (1, 0x9) // Individual Address Register 5
+#define LAN91X_GPR MakeRegister (1, 0xa) // General Purpose Register
+#define LAN91X_CTR MakeRegister (1, 0xc) // Control Register
+
+#define LAN91X_MMUCR MakeRegister (2, 0x0) // MMU Command Register
+#define LAN91X_PNR MakeRegister (2, 0x2) // Packet Number Register
+#define LAN91X_ARR MakeRegister (2, 0x3) // Allocation Result Register
+#define LAN91X_FIFO MakeRegister (2, 0x4) // FIFO Ports Register
+#define LAN91X_PTR MakeRegister (2, 0x6) // Pointer Register
+#define LAN91X_DATA0 MakeRegister (2, 0x8) // Data Register 0
+#define LAN91X_DATA1 MakeRegister (2, 0x9) // Data Register 1
+#define LAN91X_DATA2 MakeRegister (2, 0xa) // Data Register 2
+#define LAN91X_DATA3 MakeRegister (2, 0xb) // Data Register 3
+#define LAN91X_IST MakeRegister (2, 0xc) // Interrupt Status Register
+#define LAN91X_MSK MakeRegister (2, 0xd) // Interrupt Mask Register
+
+#define LAN91X_MT0 MakeRegister (3, 0x0) // Multicast Table Register 0
+#define LAN91X_MT1 MakeRegister (3, 0x1) // Multicast Table Register 1
+#define LAN91X_MT2 MakeRegister (3, 0x2) // Multicast Table Register 2
+#define LAN91X_MT3 MakeRegister (3, 0x3) // Multicast Table Register 3
+#define LAN91X_MT4 MakeRegister (3, 0x4) // Multicast Table Register 4
+#define LAN91X_MT5 MakeRegister (3, 0x5) // Multicast Table Register 5
+#define LAN91X_MT6 MakeRegister (3, 0x6) // Multicast Table Register 6
+#define LAN91X_MT7 MakeRegister (3, 0x7) // Multicast Table Register 7
+#define LAN91X_MGMT MakeRegister (3, 0x8) // Management Interface Register
+#define LAN91X_REV MakeRegister (3, 0xa) // Revision Register
+#define LAN91X_RCV MakeRegister (3, 0xc) // RCV Register
+
+// Transmit Control Register Bits
+#define TCR_TXENA BIT0
+#define TCR_LOOP BIT1
+#define TCR_FORCOL BIT2
+#define TCR_PAD_EN BIT7
+#define TCR_NOCRC BIT8
+#define TCR_MON_CSN BIT10
+#define TCR_FDUPLX BIT11
+#define TCR_STP_SQET BIT12
+#define TCR_EPH_LOOP BIT13
+#define TCR_SWFDUP BIT15
+
+#define TCR_DEFAULT (TCR_TXENA | TCR_PAD_EN)
+#define TCR_CLEAR 0x0
+
+// EPH Status Register Bits
+#define EPHSR_TX_SUC BIT0
+#define EPHSR_SNGLCOL BIT1
+#define EPHSR_MULCOL BIT2
+#define EPHSR_LTX_MULT BIT3
+#define EPHSR_16COL BIT4
+#define EPHSR_SQET BIT5
+#define EPHSR_LTX_BRD BIT6
+#define EPHSR_TX_DEFR BIT7
+#define EPHSR_LATCOL BIT9
+#define EPHSR_LOST_CARR BIT10
+#define EPHSR_EXC_DEF BIT11
+#define EPHSR_CTR_ROL BIT12
+#define EPHSR_LINK_OK BIT14
+
+// Receive Control Register Bits
+#define RCR_RX_ABORT BIT0
+#define RCR_PRMS BIT1
+#define RCR_ALMUL BIT2
+#define RCR_RXEN BIT8
+#define RCR_STRIP_CRC BIT9
+#define RCR_ABORT_ENB BIT13
+#define RCR_FILT_CAR BIT14
+#define RCR_SOFT_RST BIT15
+
+#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN)
+#define RCR_CLEAR 0x0
+
+// Receive/Phy Control Register Bits
+#define RPCR_LS0B BIT2
+#define RPCR_LS1B BIT3
+#define RPCR_LS2B BIT4
+#define RPCR_LS0A BIT5
+#define RPCR_LS1A BIT6
+#define RPCR_LS2A BIT7
+#define RPCR_ANEG BIT11
+#define RPCR_DPLX BIT12
+#define RPCR_SPEED BIT13
+
+// Configuration Register Bits
+#define CR_EXT_PHY BIT9
+#define CR_GPCNTRL BIT10
+#define CR_NO_WAIT BIT12
+#define CR_EPH_POWER_EN BIT15
+
+#define CR_DEFAULT (CR_EPH_POWER_EN | CR_NO_WAIT)
+
+// Control Register Bits
+#define CTR_STORE BIT0
+#define CTR_RELOAD BIT1
+#define CTR_EEPROM_SEL BIT2
+#define CTR_TE_ENABLE BIT5
+#define CTR_CR_ENABLE BIT6
+#define CTR_LE_ENABLE BIT7
+#define CTR_AUTO_REL BIT11
+#define CTR_RCV_BAD BIT14
+
+#define CTR_RESERVED (BIT12 | BIT9 | BIT4)
+#define CTR_DEFAULT (CTR_RESERVED | CTR_AUTO_REL)
+
+// MMU Command Register Bits
+#define MMUCR_BUSY BIT0
+
+// MMU Command Register Operaction Codes
+#define MMUCR_OP_NOOP (0 << 5) // No operation
+#define MMUCR_OP_TX_ALLOC (1 << 5) // Allocate memory for TX
+#define MMUCR_OP_RESET_MMU (2 << 5) // Reset MMU to initial state
+#define MMUCR_OP_RX_POP (3 << 5) // Remove frame from top of RX FIFO
+#define MMUCR_OP_RX_POP_REL (4 << 5) // Remove and release frame from top of RX FIFO
+#define MMUCR_OP_RX_REL (5 << 5) // Release specific RX frame
+#define MMUCR_OP_TX_PUSH (6 << 5) // Enqueue packet number into TX FIFO
+#define MMUCR_OP_TX_RESET (7 << 5) // Reset TX FIFOs
+
+// Packet Number Register Bits
+#define PNR_PACKET (0x3f)
+
+// Allocation Result Register Bits
+#define ARR_PACKET (0x3f)
+#define ARR_FAILED BIT7
+
+// FIFO Ports Register Bits
+#define FIFO_TX_PACKET (0x003f)
+#define FIFO_TEMPTY BIT7
+#define FIFO_RX_PACKET (0x3f00)
+#define FIFO_REMPTY BIT15
+
+// Pointer Register Bits
+#define PTR_POINTER (0x07ff)
+#define PTR_NOT_EMPTY BIT11
+#define PTR_READ BIT13
+#define PTR_AUTO_INCR BIT14
+#define PTR_RCV BIT15
+
+// Interupt Status and Mask Register Bits
+#define IST_RCV BIT0
+#define IST_TX BIT1
+#define IST_TX_EMPTY BIT2
+#define IST_ALLOC BIT3
+#define IST_RX_OVRN BIT4
+#define IST_EPH BIT5
+#define IST_MD BIT7
+
+// Management Interface
+#define MGMT_MDO BIT0
+#define MGMT_MDI BIT1
+#define MGMT_MCLK BIT2
+#define MGMT_MDOE BIT3
+#define MGMT_MSK_CRS100 BIT14
+
+// RCV Register
+#define RCV_MBO (0x1f)
+#define RCV_RCV_DISCRD BIT7
+
+// Packet RX Status word bits
+#define RX_MULTICAST BIT0
+#define RX_HASH (0x7e)
+#define RX_TOO_SHORT BIT10
+#define RX_TOO_LONG BIT11
+#define RX_ODD_FRAME BIT12
+#define RX_BAD_CRC BIT13
+#define RX_BROADCAST BIT14
+#define RX_ALGN_ERR BIT15
+
+// Packet Byte Count word bits
+#define BCW_COUNT (0x7fe)
+
+// Packet Control Word bits
+#define PCW_ODD_BYTE (0x00ff)
+#define PCW_CRC BIT12
+#define PCW_ODD BIT13
+
+/*---------------------------------------------------------------------------------------------------------------------
+
+ SMSC PHY Registers
+
+ Most of these should be common, as there is
+ documented STANDARD for PHY registers!
+
+---------------------------------------------------------------------------------------------------------------------*/
+//
+// PHY Register Numbers
+//
+#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_CONFIG1 16
+#define PHY_INDEX_CONFIG2 17
+#define PHY_INDEX_STATUS_OUTPUT 18
+#define PHY_INDEX_MASK 19
+
+
+// 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
+
+#endif /* __LAN91XDXEHW_H__ */
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c b/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c
index 81ddd6263..5cf717f94 100644..100755
--- a/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c
+++ b/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c
@@ -103,22 +103,6 @@ ArpCreateService (
}
//
- // Get the underlayer Snp mode data.
- //
- Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode);
- if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) {
- goto ERROR_EXIT;
- }
-
- if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) {
- //
- // Only support the ethernet.
- //
- Status = EFI_UNSUPPORTED;
- goto ERROR_EXIT;
- }
-
- //
// Set the Mnp config parameters.
//
ArpService->MnpConfigData.ReceivedQueueTimeoutValue = 0;
@@ -141,6 +125,23 @@ ArpCreateService (
}
//
+ // Get the underlayer Snp mode data. Must do this after MNP configuration else some parameters
+ // (e.g. current address) may not be set
+ //
+ Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode);
+ if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) {
+ goto ERROR_EXIT;
+ }
+
+ if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) {
+ //
+ // Only support the ethernet.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto ERROR_EXIT;
+ }
+
+ //
// Create the event used in the RxToken.
//
Status = gBS->CreateEvent (
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c
index 4c0f3ddd9..9cdbb432e 100644
--- a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c
+++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c
@@ -79,8 +79,10 @@ MnpGetModeData (
// Upon successful return of GetStatus(), the Snp->Mode->MediaPresent
// will be updated to reflect any change of media status
//
- Snp->GetStatus (Snp, &InterruptStatus, NULL);
- CopyMem (SnpModeData, Snp->Mode, sizeof (*SnpModeData));
+ Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (SnpModeData, Snp->Mode, sizeof (*SnpModeData));
+ }
}
if (!Instance->Configured) {