Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp881825pxk; Thu, 17 Sep 2020 20:13:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzGu338rV6JV0yuWHeyA+/o3njt5dWQe/qGa6GoSkFIMVLqkAj3WlXH582IXoV87tmVW3QT X-Received: by 2002:aa7:dd01:: with SMTP id i1mr36747668edv.121.1600398815243; Thu, 17 Sep 2020 20:13:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1600398815; cv=none; d=google.com; s=arc-20160816; b=ihkNNUcTmC/VmvOdG94XlQl6sni9NuxDAQVDvPQjMHxQX63gwiFWFRH9hQj+2XgaQq 4htQQdpNiqMsknkR6H8Y+C49YUfFMUAuVMr3xj0aWUfYfy6D+lh2BITTI+a0UwTn62RN IySCQsNVHwF7SN4LKInp3jF+vDz68ysmv2fHn8Cju5ZrnIBwceFZz7DdjI7hGt3j3BWu LFJTfbpfj3WukOnfazVgVwqGEqP7hSbROcbe6Ll6OLEwifehJUg5M/mGQe3EVbeP8W0m /ftifdLdYyz1JaM0aBSoEGA1BAx2h2QWvltN2z3d+D94HkWnfTpyKFBALtqnN5rqWkA0 4dyA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=GHvBjM36UCfE3k0fhxGgcJMuTejx6JEF9Q9EG8DXRPg=; b=eCc8ER+td6SOM4QaLAN5YPTE5FYRMwEdX2+befQ3B7IYx9pH8lAKq5z7kFRY07OqtY zgSWipAv2KreruY5T6Xry/Z50SUReTRQfr+ZB/U+mCfWV+XFHCsyV0AsIp0qYTF+R53j r8euvYWqkGfnf4XiZAg+AZOYEH21BgrLVqj7ng1M50/388vS+F7ABLepq+tOILsFSakq c7zNB6oTC8oiReGDesQkLFoRKVCH8gN4rWcxJE15BHj4JeOGTL/x/pyopNBUudUaf5DE Nn2YfSvRMXB26K7wcbxihnJ9Jy7jyeQF8Tt39BQMWUqsdL8X3vFwPj1yRXgTFdp2Xk2Y 4hww== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=cFQQILCZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id i11si1187536edl.230.2020.09.17.20.13.11; Thu, 17 Sep 2020 20:13:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=cFQQILCZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729877AbgIRDJJ (ORCPT + 99 others); Thu, 17 Sep 2020 23:09:09 -0400 Received: from mail.kernel.org ([198.145.29.99]:49086 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726973AbgIRCDK (ORCPT ); Thu, 17 Sep 2020 22:03:10 -0400 Received: from sasha-vm.mshome.net (c-73-47-72-35.hsd1.nh.comcast.net [73.47.72.35]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B98D0221EC; Fri, 18 Sep 2020 02:03:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600394587; bh=U9M+zpFCNePno53yzOpfFRwLAW3GwH5HlPJWAMAnOPI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cFQQILCZxrcqQ98kYeYKOFV6cZsa3rwkCH4+aIj1hOjEkfymcpnjY7Q/UxXopPzy2 zHKHJbE5kVE/0ZmKA6rwptQMPLAfasFV9p+qnE682GydMv3BM21s/BWL+xgVdiaLDF tvHAoZbSS8OK+0MrIWKi7iRR/wEwCEmw8lYSpVMg= From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Ard Biesheuvel , Saravana Kannan , Ingo Molnar , Sasha Levin , linux-efi@vger.kernel.org Subject: [PATCH AUTOSEL 5.4 096/330] efi/arm: Defer probe of PCIe backed efifb on DT systems Date: Thu, 17 Sep 2020 21:57:16 -0400 Message-Id: <20200918020110.2063155-96-sashal@kernel.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200918020110.2063155-1-sashal@kernel.org> References: <20200918020110.2063155-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Ard Biesheuvel [ Upstream commit 64c8a0cd0a535891d5905c3a1651150f0f141439 ] The new of_devlink support breaks PCIe probing on ARM platforms booting via UEFI if the firmware exposes a EFI framebuffer that is backed by a PCI device. The reason is that the probing order gets reversed, resulting in a resource conflict on the framebuffer memory window when the PCIe probes last, causing it to give up entirely. Given that we rely on PCI quirks to deal with EFI framebuffers that get moved around in memory, we cannot simply drop the memory reservation, so instead, let's use the device link infrastructure to register this dependency, and force the probing to occur in the expected order. Co-developed-by: Saravana Kannan Signed-off-by: Ard Biesheuvel Signed-off-by: Saravana Kannan Signed-off-by: Ard Biesheuvel Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200113172245.27925-9-ardb@kernel.org Signed-off-by: Sasha Levin --- drivers/firmware/efi/arm-init.c | 107 ++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 311cd349a8628..f136b77e13d98 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -10,10 +10,12 @@ #define pr_fmt(fmt) "efi: " fmt #include +#include #include #include #include #include +#include #include #include #include @@ -267,15 +269,112 @@ void __init efi_init(void) efi_memmap_unmap(); } +static bool efifb_overlaps_pci_range(const struct of_pci_range *range) +{ + u64 fb_base = screen_info.lfb_base; + + if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) + fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32; + + return fb_base >= range->cpu_addr && + fb_base < (range->cpu_addr + range->size); +} + +static struct device_node *find_pci_overlap_node(void) +{ + struct device_node *np; + + for_each_node_by_type(np, "pci") { + struct of_pci_range_parser parser; + struct of_pci_range range; + int err; + + err = of_pci_range_parser_init(&parser, np); + if (err) { + pr_warn("of_pci_range_parser_init() failed: %d\n", err); + continue; + } + + for_each_of_pci_range(&parser, &range) + if (efifb_overlaps_pci_range(&range)) + return np; + } + return NULL; +} + +/* + * If the efifb framebuffer is backed by a PCI graphics controller, we have + * to ensure that this relation is expressed using a device link when + * running in DT mode, or the probe order may be reversed, resulting in a + * resource reservation conflict on the memory window that the efifb + * framebuffer steals from the PCIe host bridge. + */ +static int efifb_add_links(const struct fwnode_handle *fwnode, + struct device *dev) +{ + struct device_node *sup_np; + struct device *sup_dev; + + sup_np = find_pci_overlap_node(); + + /* + * If there's no PCI graphics controller backing the efifb, we are + * done here. + */ + if (!sup_np) + return 0; + + sup_dev = get_dev_from_fwnode(&sup_np->fwnode); + of_node_put(sup_np); + + /* + * Return -ENODEV if the PCI graphics controller device hasn't been + * registered yet. This ensures that efifb isn't allowed to probe + * and this function is retried again when new devices are + * registered. + */ + if (!sup_dev) + return -ENODEV; + + /* + * If this fails, retrying this function at a later point won't + * change anything. So, don't return an error after this. + */ + if (!device_link_add(dev, sup_dev, 0)) + dev_warn(dev, "device_link_add() failed\n"); + + put_device(sup_dev); + + return 0; +} + +static const struct fwnode_operations efifb_fwnode_ops = { + .add_links = efifb_add_links, +}; + +static struct fwnode_handle efifb_fwnode = { + .ops = &efifb_fwnode_ops, +}; + static int __init register_gop_device(void) { - void *pd; + struct platform_device *pd; + int err; if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) return 0; - pd = platform_device_register_data(NULL, "efi-framebuffer", 0, - &screen_info, sizeof(screen_info)); - return PTR_ERR_OR_ZERO(pd); + pd = platform_device_alloc("efi-framebuffer", 0); + if (!pd) + return -ENOMEM; + + if (IS_ENABLED(CONFIG_PCI)) + pd->dev.fwnode = &efifb_fwnode; + + err = platform_device_add_data(pd, &screen_info, sizeof(screen_info)); + if (err) + return err; + + return platform_device_add(pd); } subsys_initcall(register_gop_device); -- 2.25.1