From patchwork Tue Jun 27 18:56:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 106475 Delivered-To: patch@linaro.org Received: by 10.182.135.102 with SMTP id pr6csp2712330obb; Tue, 27 Jun 2017 11:57:29 -0700 (PDT) X-Received: by 10.200.33.235 with SMTP id 40mr9129484qtz.189.1498589849090; Tue, 27 Jun 2017 11:57:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1498589849; cv=none; d=google.com; s=arc-20160816; b=ua3DKZPDIB5uxBAyjcTnLBGsM7IZgYdYXPks1K3hauqsRagd8bZRrgJ1ig/KsSDgBQ wWEErv1JBuHX8BqictY9H/Mw6uuRbU74bLOWCbCGzIS+/aXe5/YttHcSzzHGlmxg907d WONDaQTqM4Exl34M7d7Xzccp+cYqvuEsWnIRl8v/mBYxoGRVvP1ieQ24R4l2Dc6xHnZx +Ug0Jfg5DF0JT2qYrU6yv3mmEacYtI2CXNelP3Xn0s7ynQwnbbHQalXEStRbImNs4KaN jf41ndKUEsmTtWvzZbMbf5Jlv2OzlPF8UYaUJOIRocixTNw/9ek6YPrptPi2PaKAuIGa k+ow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:delivered-to:arc-authentication-results; bh=vfenV4LghFuNb2u5HGfFWeMiEz4SiKCOhBVdB7l13PI=; b=h5+seK7BnfVg+wTZU4CR/1zM2tTr86n1aCcU6m9wspwCcLT3hl244geaFOWp4e9hsI ptqcZRg2jMtWnycK2SLxUsY0if/QIwOAzpHyIPi4Kc/6RiOpoY4InKEoBGtsIk37iCqP VYE7/sSmCFuxpLGeX/SPLqsA94fIOmdZoV4YJZ2wxM2zO7/87JrPbQS6Lz3l/DG42+Uz /Chb0IAdJFgZHKQ+CZNKKrrRAA56mBnyb7s+tDjtjmSqTSZmQkK/ORHeYh1FaAIoYwuT m8BzfId1cydXb4m+iBIMWZvUI02+zsk79yGb5mK3iX4lBfYy0qKTWLpD5EAceg8Zahf2 JgJg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linaro-uefi-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=linaro-uefi-bounces@lists.linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id b11si12795qte.178.2017.06.27.11.57.28; Tue, 27 Jun 2017 11:57:29 -0700 (PDT) Received-SPF: pass (google.com: domain of linaro-uefi-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linaro-uefi-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=linaro-uefi-bounces@lists.linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 9EA0460D44; Tue, 27 Jun 2017 18:57:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id D522F60D3D; Tue, 27 Jun 2017 18:57:13 +0000 (UTC) X-Original-To: linaro-uefi@lists.linaro.org Delivered-To: linaro-uefi@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 9E99160AD1; Tue, 27 Jun 2017 18:57:07 +0000 (UTC) Received: from mail-wm0-f53.google.com (mail-wm0-f53.google.com [74.125.82.53]) by lists.linaro.org (Postfix) with ESMTPS id 0267560AD1 for ; Tue, 27 Jun 2017 18:57:05 +0000 (UTC) Received: by mail-wm0-f53.google.com with SMTP id w126so32998707wme.0 for ; Tue, 27 Jun 2017 11:57:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=+uJJXhWPlKTIuJF3+zBz98y6QLFpzLNcf6td1lrGz/4=; b=N2SzfNI4r2eUpxzBeqI+4hvbY1u7o2O0pY5cBDunofexTaM8r9a24Suvi98FyCJzRv s2tCwvGlQcyb7jnp2+6J9r4/8UnEbOz7eyNJwi5lhjpYrz3nfXcegvMP5NYrle6mcQUk 2tp8CHCb9ppx4YXs+RnJd3yQPLe3+9qsjhq8ejZIPc1NzGO++vc94KeOqropQVRVPzU6 g4Y6WkMRzRDlGM2/v6KYPm7rPlYOkOtXagYP8lCCpcWX07aSXtz18u2f9l14ysJRmtB6 ondVDGEj5wesjsJbibOg2OuhXtyFknRqeVlFCKyLBpezX7MLx90ND/6so5tQSLjfNj77 hwYw== X-Gm-Message-State: AKS2vOzRbZ271Xvx4A3NjgfAEGKhpS9Y75J6QqN+4nMBaIYCJ7z5UVQc 0p0Iid3TuXgsBI6SVzM+8P1i X-Received: by 10.28.156.17 with SMTP id f17mr4252326wme.17.1498589823637; Tue, 27 Jun 2017 11:57:03 -0700 (PDT) Received: from localhost.localdomain ([105.133.250.69]) by smtp.gmail.com with ESMTPSA id h16sm5399744wma.14.2017.06.27.11.57.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 27 Jun 2017 11:57:02 -0700 (PDT) From: Ard Biesheuvel To: linaro-uefi@lists.linaro.org Date: Tue, 27 Jun 2017 18:56:18 +0000 Message-Id: <20170627185619.21847-2-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170627185619.21847-1-ard.biesheuvel@linaro.org> References: <20170627185619.21847-1-ard.biesheuvel@linaro.org> Cc: rfranz@cavium.com Subject: [Linaro-uefi] [PATCH 1/2] Drivers/Net: add MAC override driver for Realtek 8169 X-BeenThere: linaro-uefi@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "For discussions about Linaro-related UEFI development. Not a substitute for edk2-devel." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: linaro-uefi-bounces@lists.linaro.org Sender: "Linaro-uefi" Sadly, the Cellos have been delivered with a Realtek NIC that lacks a MAC address in its OTP. This can be worked around from the OS, but this confuses some installers, and it is much better to deal with this in the firmware. Since network boot using the full Realtek 8169 driver is impossible anyway in this case, for the same reason, let's provide a driver that programs a MAC into the volatile NIC registers in a way that allows the OS to run unmodified. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel --- Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.c | 262 ++++++++++++++++++++ Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.inf | 44 ++++ OpenPlatformPkg.dec | 3 + 3 files changed, 309 insertions(+) diff --git a/Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.c b/Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.c new file mode 100644 index 000000000000..9b2925ba35d1 --- /dev/null +++ b/Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.c @@ -0,0 +1,262 @@ +/** @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 + +#include +#include +#include +#include + +#include + +#include + +#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; + + // + // 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; + } + + Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 2, MAC + 4, 0x1, + (UINT8 *)mMacOverride + 4); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: failed to set MAC address (#1) ...\n", __FUNCTION__)); + } + + Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 2, MAC, 0x1, + (UINT8 *)mMacOverride); + 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 install the firmware 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); +} diff --git a/Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.inf b/Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.inf new file mode 100644 index 000000000000..baf333562ca1 --- /dev/null +++ b/Drivers/Net/Realtek8169MacOverride/Realtek8169MacOverride.inf @@ -0,0 +1,44 @@ +## file +# Component description file for Realtek 8169 MAC override driver +# +# Copyright (c) 2017, Linaro Ltd. 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 = 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] + DebugLib + DxeServicesLib + PcdLib + UefiBootServicesTableLib + UefiLib + UefiDriverEntryPoint + +[Protocols] + gEfiPciIoProtocolGuid + +[Pcd] + gOpenPlatformTokenSpaceGuid.PcdMacOverride diff --git a/OpenPlatformPkg.dec b/OpenPlatformPkg.dec index 2db143d637b3..34323bc90b9a 100644 --- a/OpenPlatformPkg.dec +++ b/OpenPlatformPkg.dec @@ -41,3 +41,6 @@ gOpenPlatformTokenSpaceGuid.PcdRamDiskMaxSize|0|UINT32|0x00000001 [PcdsFeatureFlag] + +[PcdsFixedAtBuild,PcdsDynamic] + gOpenPlatformTokenSpaceGuid.PcdMacOverride|{0x0,0x0,0x0,0x0,0x0,0x0}|VOID*|0x00000002