From patchwork Tue Apr 12 13:47:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 65620 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp1930733qge; Tue, 12 Apr 2016 06:47:23 -0700 (PDT) X-Received: by 10.98.19.82 with SMTP id b79mr4776131pfj.17.1460468843578; Tue, 12 Apr 2016 06:47:23 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id y26si10076450pfa.187.2016.04.12.06.47.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 12 Apr 2016 06:47:23 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 90B0A1A213E; Tue, 12 Apr 2016 06:47:22 -0700 (PDT) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-wm0-x22d.google.com (mail-wm0-x22d.google.com [IPv6:2a00:1450:400c:c09::22d]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id B8C7D1A213E for ; Tue, 12 Apr 2016 06:47:20 -0700 (PDT) Received: by mail-wm0-x22d.google.com with SMTP id u206so28966967wme.1 for ; Tue, 12 Apr 2016 06:47:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wCHRIRecFq0tbD+RNpp0FcYjWkocJD2CEgbXyH5Skyw=; b=BYmVT2Gw/bFXWA9XHw2hXwlQ/9JPhHfs7OdF1mBwkcpHFOFHqHIyQZJ/vr8CQLIdlm 0TcNB7zL1xjCbuYXbnlb7yxmI1zQRcPhTbfAQEteQPG8L5UeZdop9ZEoL2heMIhVV3F1 LOh+l3DkJNk8ouMqW4YcfO1iXgxds3uhAb1Tw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=wCHRIRecFq0tbD+RNpp0FcYjWkocJD2CEgbXyH5Skyw=; b=Uilg4Tr7TZLsxes9qEk21aG/7cVyshjHA9l/GUkIRtkvEIZhgMHXZLq1RjbJIbwLDz cwmXw5OzUMrHUTq6d4z7rD7k2cgr6WxaBvcca9y6Q6G1en3uWD3KWLg1UIR/1nkcqqmp hhRmyy861gN63ytlVJq085KRI0idThPZblzIA8+kgd+yeiPLDatyQzpa7KcjSnjV/ExR ZkEOUSrPo+Urd+QrxpziMzejTSIB0d6VaMgUDur4VCJZqLXn5Jek0gCMpdDUSbFS5UR/ gB8bPSml/yE/sb+9AUeNgFdG4W+xVW7ZbxirIw7g9qwtAuwc+6EKEPPiiloJVjIthMJJ jWFQ== X-Gm-Message-State: AOPr4FV0zyWe+jMuzK1dYkA+elgGvD3Dh0Hzcy4TGtAIc3q1FmRUo3qqu74T1IyfgkDoARSO X-Received: by 10.194.125.201 with SMTP id ms9mr3787746wjb.71.1460468839318; Tue, 12 Apr 2016 06:47:19 -0700 (PDT) Received: from localhost.localdomain ([195.55.142.58]) by smtp.gmail.com with ESMTPSA id w75sm22970685wmw.4.2016.04.12.06.47.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 12 Apr 2016 06:47:18 -0700 (PDT) From: Ard Biesheuvel To: edk2-devel@lists.01.org, lersek@redhat.com Date: Tue, 12 Apr 2016 15:47:08 +0200 Message-Id: <1460468829-13982-4-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1460468829-13982-1-git-send-email-ard.biesheuvel@linaro.org> References: <1460468829-13982-1-git-send-email-ard.biesheuvel@linaro.org> Subject: [edk2] [PATCH 3/4] ArmVirtPkg/PciHostBridgeDxe: move to FDT client protocol X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" Instead of relying on VirtFdtDxe to populate various dynamic PCDs with information retrieved from the host-provided device tree, perform the PCI ECAM related DT node parsing directly in PciHostBridgeDxe. Since we expect PcdPciExpressBaseAddress to have already been assigned by the time this module's entry point is called, add a dependency on PciPcdProducerLib as well. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel --- ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.c | 261 ++++++++++++++++++-- ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.h | 1 + ArmVirtPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf | 14 +- 3 files changed, 253 insertions(+), 23 deletions(-) -- 2.5.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel Reviewed-by: Laszlo Ersek diff --git a/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.c b/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.c index 735c7f216318..eba6a7c47882 100644 --- a/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.c +++ b/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.c @@ -79,6 +79,230 @@ PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = { // Implementation // +STATIC +VOID +SetLinuxPciProbeOnlyProperty ( + IN FDT_CLIENT_PROTOCOL *FdtClient + ) +{ + INT32 Node, Tmp; + EFI_STATUS Status; + + if (!FeaturePcdGet (PcdPureAcpiBoot)) { + // + // Set the /chosen/linux,pci-probe-only property to 1, so that the PCI + // setup we will perform in the firmware is honored by the Linux OS, + // rather than torn down and done from scratch. This is generally a more + // sensible approach, and aligns with what ACPI based OSes do typically. + // + // In case we are exposing an emulated VGA PCI device to the guest, which + // may subsequently get exposed via the Graphics Output protocol and + // driven as an efifb by Linux, we need this setting to prevent the + // framebuffer from becoming unresponsive. + // + Status = FdtClient->GetOrInsertChosenNode (FdtClient, &Node); + + if (Status == EFI_SUCCESS) { + Tmp = SwapBytes32 (1); + Status = FdtClient->SetNodeProperty (FdtClient, Node, + "linux,pci-probe-only", &Tmp, sizeof (Tmp)); + } + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, + "Failed to set /chosen/linux,pci-probe-only property\n")); + } + } +} + +// +// We expect the "ranges" property of "pci-host-ecam-generic" to consist of +// records like this. +// +#pragma pack (1) +typedef struct { + UINT32 Type; + UINT64 ChildBase; + UINT64 CpuBase; + UINT64 Size; +} DTB_PCI_HOST_RANGE_RECORD; +#pragma pack () + +#define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31 +#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30 +#define DTB_PCI_HOST_RANGE_ALIASED BIT29 +#define DTB_PCI_HOST_RANGE_MMIO32 BIT25 +#define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24) +#define DTB_PCI_HOST_RANGE_IO BIT24 +#define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24) + +STATIC +EFI_STATUS +EFIAPI +ProcessPciHost ( + OUT UINT64 *IoBase, + OUT UINT64 *IoSize, + OUT UINT64 *IoTranslation, + OUT UINT64 *MmioBase, + OUT UINT64 *MmioSize, + OUT UINT64 *MmioTranslation, + OUT UINT32 *BusMin, + OUT UINT32 *BusMax + ) +{ + FDT_CLIENT_PROTOCOL *FdtClient; + INT32 Node; + UINT64 ConfigBase, ConfigSize; + CONST VOID *Prop; + UINT32 Len; + UINT32 RecordIdx; + EFI_STATUS Status; + + // + // The following output arguments are initialized only in + // order to suppress '-Werror=maybe-uninitialized' warnings + // *incorrectly* emitted by some gcc versions. + // + *IoBase = 0; + *IoTranslation = 0; + *MmioBase = 0; + *MmioTranslation = 0; + *BusMin = 0; + *BusMax = 0; + + // + // *IoSize and *MmioSize are initialized to zero because the logic below + // requires it. However, since they are also affected by the issue reported + // above, they are initialized early. + // + *IoSize = 0; + *MmioSize = 0; + + Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, + (VOID **)&FdtClient); + ASSERT_EFI_ERROR (Status); + + Status = FdtClient->FindCompatibleNode (FdtClient, "pci-host-ecam-generic", + &Node); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, + "%a: No 'pci-host-ecam-generic' compatible DT node found\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + DEBUG_CODE ( + INT32 Tmp; + + // + // A DT can legally describe multiple PCI host bridges, but we are not + // equipped to deal with that. So assert that there is only one. + // + Status = FdtClient->FindNextCompatibleNode (FdtClient, + "pci-host-ecam-generic", Node, &Tmp); + ASSERT (Status == EFI_NOT_FOUND); + ); + + Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg", &Prop, &Len); + if (EFI_ERROR (Status) || Len != 2 * sizeof(UINT64)) { + DEBUG ((EFI_D_ERROR, "%a: 'reg' property not found or invalid\n", + __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + // + // Fetch the ECAM window. + // + ConfigBase = SwapBytes64 (((CONST UINT64 *)Prop)[0]); + ConfigSize = SwapBytes64 (((CONST UINT64 *)Prop)[1]); + + // + // Fetch the bus range (note: inclusive). + // + Status = FdtClient->GetNodeProperty (FdtClient, Node, "bus-range", &Prop, + &Len); + if (EFI_ERROR (Status) || Len != 2 * sizeof(UINT32)) { + DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n", + __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + *BusMin = SwapBytes32 (((CONST UINT32 *)Prop)[0]); + *BusMax = SwapBytes32 (((CONST UINT32 *)Prop)[1]); + + // + // Sanity check: the config space must accommodate all 4K register bytes of + // all 8 functions of all 32 devices of all buses. + // + if (*BusMax < *BusMin || *BusMax - *BusMin == MAX_UINT32 || + DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < *BusMax - *BusMin + 1) { + DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n", + __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + // + // Iterate over "ranges". + // + Status = FdtClient->GetNodeProperty (FdtClient, Node, "ranges", &Prop, &Len); + if (EFI_ERROR (Status) || Len == 0 || + Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) { + DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD); + ++RecordIdx) { + CONST DTB_PCI_HOST_RANGE_RECORD *Record; + + Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx; + switch (SwapBytes32 (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) { + case DTB_PCI_HOST_RANGE_IO: + *IoBase = SwapBytes64 (Record->ChildBase); + *IoSize = SwapBytes64 (Record->Size); + *IoTranslation = SwapBytes64 (Record->CpuBase) - *IoBase; + break; + + case DTB_PCI_HOST_RANGE_MMIO32: + *MmioBase = SwapBytes64 (Record->ChildBase); + *MmioSize = SwapBytes64 (Record->Size); + *MmioTranslation = SwapBytes64 (Record->CpuBase) - *MmioBase; + + if (*MmioBase > MAX_UINT32 || *MmioSize > MAX_UINT32 || + *MmioBase + *MmioSize > SIZE_4GB) { + DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__)); + return EFI_PROTOCOL_ERROR; + } + + if (*MmioTranslation != 0) { + DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation " + "0x%Lx\n", __FUNCTION__, *MmioTranslation)); + return EFI_UNSUPPORTED; + } + + break; + } + } + if (*IoSize == 0 || *MmioSize == 0) { + DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__, + (*IoSize == 0) ? "IO" : "MMIO32")); + return EFI_PROTOCOL_ERROR; + } + + // + // The dynamic PCD PcdPciExpressBaseAddress should have already been set, + // and should match the value we found in the DT node. + // + ASSERT (PcdGet64 (PcdPciExpressBaseAddress) == ConfigBase); + + SetLinuxPciProbeOnlyProperty (FdtClient); + + DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] " + "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase, + ConfigSize, *BusMin, *BusMax, *IoBase, *IoSize, *IoTranslation, *MmioBase, + *MmioSize, *MmioTranslation)); + return EFI_SUCCESS; +} + + /** Entry point of this driver @@ -103,25 +327,32 @@ InitializePciHostBridge ( UINTN Loop2; PCI_HOST_BRIDGE_INSTANCE *HostBridge; PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINT64 IoBase, IoSize, IoTranslation; + UINT64 MmioBase, MmioSize, MmioTranslation; + UINT32 BusMin, BusMax; if (PcdGet64 (PcdPciExpressBaseAddress) == 0) { DEBUG ((EFI_D_INFO, "%a: PCI host bridge not present\n", __FUNCTION__)); return EFI_ABORTED; } + Status = ProcessPciHost (&IoBase, &IoSize, &IoTranslation, &MmioBase, + &MmioSize, &MmioTranslation, &BusMin, &BusMax); + if (EFI_ERROR (Status)) { + return Status; + } + mDriverImageHandle = ImageHandle; - mResAperture[0][0].BusBase = PcdGet32 (PcdPciBusMin); - mResAperture[0][0].BusLimit = PcdGet32 (PcdPciBusMax); + mResAperture[0][0].BusBase = BusMin; + mResAperture[0][0].BusLimit = BusMax; - mResAperture[0][0].MemBase = PcdGet32 (PcdPciMmio32Base); - mResAperture[0][0].MemLimit = (UINT64)PcdGet32 (PcdPciMmio32Base) + - PcdGet32 (PcdPciMmio32Size) - 1; + mResAperture[0][0].MemBase = MmioBase; + mResAperture[0][0].MemLimit = MmioBase + MmioSize - 1; - mResAperture[0][0].IoBase = PcdGet64 (PcdPciIoBase); - mResAperture[0][0].IoLimit = PcdGet64 (PcdPciIoBase) + - PcdGet64 (PcdPciIoSize) - 1; - mResAperture[0][0].IoTranslation = PcdGet64 (PcdPciIoTranslation); + mResAperture[0][0].IoBase = IoBase; + mResAperture[0][0].IoLimit = IoBase + IoSize - 1; + mResAperture[0][0].IoTranslation = IoTranslation; // // Add IO and MMIO memory space, so that resources can be allocated in the @@ -129,8 +360,8 @@ InitializePciHostBridge ( // Status = gDS->AddIoSpace ( EfiGcdIoTypeIo, - PcdGet64 (PcdPciIoBase), - PcdGet64 (PcdPciIoSize) + IoBase, + IoSize ); ASSERT_EFI_ERROR (Status); @@ -139,8 +370,8 @@ InitializePciHostBridge ( Status = gDS->AddMemorySpace ( EfiGcdMemoryTypeMemoryMappedIo, - PcdGet32 (PcdPciMmio32Base), - PcdGet32 (PcdPciMmio32Size), + MmioBase, + MmioSize, MmioAttributes ); if (EFI_ERROR (Status)) { @@ -149,8 +380,8 @@ InitializePciHostBridge ( } Status = gDS->SetMemorySpaceAttributes ( - PcdGet32 (PcdPciMmio32Base), - PcdGet32 (PcdPciMmio32Size), + MmioBase, + MmioSize, MmioAttributes ); if (EFI_ERROR (Status)) { diff --git a/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.h b/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.h index 8161b546ff87..647fe1a52a7d 100644 --- a/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.h +++ b/ArmVirtPkg/PciHostBridgeDxe/PciHostBridge.h @@ -24,6 +24,7 @@ #include #include #include +#include #include diff --git a/ArmVirtPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf b/ArmVirtPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf index 6d782582e02d..e58a45ff0e2f 100644 --- a/ArmVirtPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf +++ b/ArmVirtPkg/PciHostBridgeDxe/PciHostBridgeDxe.inf @@ -22,6 +22,7 @@ [Defines] ENTRY_POINT = InitializePciHostBridge [Packages] + MdeModulePkg/MdeModulePkg.dec MdePkg/MdePkg.dec ArmPlatformPkg/ArmPlatformPkg.dec ArmVirtPkg/ArmVirtPkg.dec @@ -39,6 +40,7 @@ [LibraryClasses] IoLib PciLib PcdLib + PciPcdProducerLib [Sources] PciHostBridge.c @@ -50,20 +52,16 @@ [Protocols] gEfiPciRootBridgeIoProtocolGuid ## PRODUCES gEfiMetronomeArchProtocolGuid ## CONSUMES gEfiDevicePathProtocolGuid ## PRODUCES + gFdtClientProtocolGuid ## CONSUMES [Pcd] - gArmPlatformTokenSpaceGuid.PcdPciBusMin - gArmPlatformTokenSpaceGuid.PcdPciBusMax - gArmPlatformTokenSpaceGuid.PcdPciIoBase - gArmPlatformTokenSpaceGuid.PcdPciIoSize - gArmPlatformTokenSpaceGuid.PcdPciIoTranslation - gArmPlatformTokenSpaceGuid.PcdPciMmio32Base - gArmPlatformTokenSpaceGuid.PcdPciMmio32Size gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress [FeaturePcd] gArmVirtTokenSpaceGuid.PcdKludgeMapPciMmioAsCached + gArmVirtTokenSpaceGuid.PcdPureAcpiBoot [depex] gEfiMetronomeArchProtocolGuid AND - gEfiCpuArchProtocolGuid + gEfiCpuArchProtocolGuid AND + gFdtClientProtocolGuid