new file mode 100644
@@ -0,0 +1,263 @@
+/** @file
+ Realtek 8169 MAC override driver
+
+Copyright (c) 2017, Linaro 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 <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#include <Protocol/PciIo.h>
+
+#define PCI_VENDOR_ID_REALTEK 0x10EC
+#define PCI_DEVICE_ID_REALTEK_8169 0x8168
+
+STATIC CONST UINT8 *mMacOverride;
+
+#define MAC 0x0
+#define CFG9346 0x50
+
+STATIC CONST UINT8 Cfg9346_Unlock = 0xc0;
+STATIC CONST UINT8 Cfg9346_Lock = 0x0;
+
+STATIC BOOLEAN Done;
+
+/**
+ Test to see if this driver supports ControllerHandle. This service
+ is called by the EFI boot service ConnectController(). In
+ order to make drivers as small as possible, there are a few calling
+ restrictions for this service. ConnectController() must
+ follow these calling restrictions. If any other agent wishes to call
+ Supported() it must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Realtek8169MacOverrideDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 PciID;
+ UINT64 Supports;
+ UINT32 MacWord;
+
+ //
+ // Execute only once
+ //
+ if (Done) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check for the PCI IO Protocol
+ //
+ Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo, This->DriverBindingHandle, Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, PCI_VENDOR_ID_OFFSET,
+ 1, &PciID);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Pci->Pci.Read() of vendor/device id failed (Status == %r)\n",
+ __FUNCTION__, Status));
+ goto CloseProtocol;
+ }
+
+ if ((PciID & 0xffff) != PCI_VENDOR_ID_REALTEK ||
+ (PciID >> 16) != PCI_DEVICE_ID_REALTEK_8169) {
+ DEBUG ((DEBUG_INFO, "%a: ignoring unsupported PCI device 0x%04x:0x%04x\n",
+ __FUNCTION__, PciID & 0xffff, PciID >> 16));
+ goto CloseProtocol;
+ }
+
+ //
+ // Enable the device so we can poke at its MMIO registers
+ //
+ Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSupported,
+ 0, &Supports);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: failed to get PCI attributes, aborting (Status == %r)...\n",
+ __FUNCTION__, Status));
+ goto CloseProtocol;
+ }
+
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
+ Supports, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: failed to set PCI attributes, aborting (Status == %r)...\n",
+ __FUNCTION__, Status));
+ goto CloseProtocol;
+ }
+
+ //
+ // Program the MAC address
+ //
+ Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, 2, CFG9346, 0x1,
+ (VOID *)&Cfg9346_Unlock);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: unlock failed, aborting (Status == %r)...\n", __FUNCTION__, Status));
+ goto CloseProtocol;
+ }
+
+ CopyMem (&MacWord, (UINT8 *)mMacOverride + 4, sizeof MacWord);
+ Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 2, MAC + 4, 0x1, &MacWord);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: failed to set MAC address (#1) ...\n", __FUNCTION__));
+ }
+
+ CopyMem (&MacWord, (UINT8 *)mMacOverride, sizeof MacWord);
+ Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 2, MAC, 0x1, &MacWord);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: failed to set MAC address (#2) ...\n", __FUNCTION__));
+ }
+
+ Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, 2, CFG9346, 0x1,
+ (VOID *)&Cfg9346_Lock);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: relock failed ...\n", __FUNCTION__));
+ goto CloseProtocol;
+ }
+
+ Done = TRUE;
+
+ PciIo->Attributes (PciIo, EfiPciIoAttributeOperationDisable, Supports, NULL);
+
+CloseProtocol:
+ gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle, Controller);
+
+ //
+ // Always return unsupported: we are not interested in driving the device,
+ // only in having the opportunity to updating the MAC address before the real
+ // driver attaches to it.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Start this driver on Controller. Not used.
+
+ @param [in] This Protocol instance pointer.
+ @param [in] Controller Handle of device to work with.
+ @param [in] RemainingDevicePath Not used, always produce all possible children.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval other This driver does not support this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Realtek8169MacOverrideDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ //
+ // We are not interested in driving the device, we only poke the firmware
+ // in the .Supported() callback.
+ //
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Stop this driver on Controller. Not used.
+
+ @param [in] This Protocol instance pointer.
+ @param [in] Controller Handle of device to stop driver on.
+ @param [in] NumberOfChildren How many children need to be stopped.
+ @param [in] ChildHandleBuffer Not used.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval other This driver was not removed from this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Realtek8169MacOverrideDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+}
+
+//
+// UEFI Driver Model entry point
+//
+STATIC EFI_DRIVER_BINDING_PROTOCOL Realtek8169MacOverrideDriverBinding = {
+ Realtek8169MacOverrideDriverSupported,
+ Realtek8169MacOverrideDriverStart,
+ Realtek8169MacOverrideDriverStop,
+
+ // Version values of 0xfffffff0-0xffffffff are reserved for platform/OEM
+ // specific drivers. Protocol instances with higher 'Version' properties
+ // will be used before lower 'Version' ones. XhciDxe uses version 0x30,
+ // so this driver will be called in preference, and XhciDxe will be invoked
+ // after Realtek8169MacOverrideDriverSupported returns EFI_UNSUPPORTED.
+ 0xfffffff0,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+InitializeRealtek8169MacOverride (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mMacOverride = PcdGetPtr (PcdMacOverride);
+
+ DEBUG ((DEBUG_WARN, "%a: using MAC override value %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, mMacOverride[0], mMacOverride[1], mMacOverride[2],
+ mMacOverride[3], mMacOverride[4], mMacOverride[5]
+ ));
+
+ return EfiLibInstallDriverBinding (ImageHandle, SystemTable,
+ &Realtek8169MacOverrideDriverBinding, NULL);
+}
new file mode 100644
@@ -0,0 +1,44 @@
+## <at> file
+# Component description file for Realtek 8169 MAC override driver
+#
+# Copyright (c) 2017, Linaro Ltd. 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 = Realtek8169MacOverride
+ FILE_GUID = 8d97e056-777c-4850-ab61-8166b1777f2d
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeRealtek8169MacOverride
+
+[Sources]
+ Realtek8169MacOverride.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OpenPlatformPkg/OpenPlatformPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiPciIoProtocolGuid
+
+[Pcd]
+ gOpenPlatformTokenSpaceGuid.PcdMacOverride
@@ -41,3 +41,6 @@
gOpenPlatformTokenSpaceGuid.PcdRamDiskMaxSize|0|UINT32|0x00000001
[PcdsFeatureFlag]
+
+[PcdsFixedAtBuild,PcdsDynamic]
+ gOpenPlatformTokenSpaceGuid.PcdMacOverride|{0x0,0x0,0x0,0x0,0x0,0x0}|VOID*|0x00000002