From: Sasha Levin Date: Sat, 18 Jul 2020 19:15:44 +0000 (-0400) Subject: Fixes for 4.9 X-Git-Tag: v4.4.231~53 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a34897e6e10265c98e9397547473596abe3b4e8f;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 4.9 Signed-off-by: Sasha Levin --- diff --git a/queue-4.9/efi-arm-defer-probe-of-pcie-backed-efifb-on-dt-syste.patch b/queue-4.9/efi-arm-defer-probe-of-pcie-backed-efifb-on-dt-syste.patch new file mode 100644 index 00000000000..bad19aef6e2 --- /dev/null +++ b/queue-4.9/efi-arm-defer-probe-of-pcie-backed-efifb-on-dt-syste.patch @@ -0,0 +1,168 @@ +From cff5a08a72f64cc9fb3191a87903955fa0e2cf7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jan 2020 18:22:40 +0100 +Subject: efi/arm: Defer probe of PCIe backed efifb on DT systems + +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 8ee91777abce7..e4ddd6e6edb31 100644 +--- a/drivers/firmware/efi/arm-init.c ++++ b/drivers/firmware/efi/arm-init.c +@@ -14,10 +14,12 @@ + #define pr_fmt(fmt) "efi: " fmt + + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -262,15 +264,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 + diff --git a/queue-4.9/series b/queue-4.9/series index 5e8741e62ef..036ef8b3912 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -49,3 +49,4 @@ net-dsa-bcm_sf2-fix-node-reference-count.patch revert-usb-ehci-platform-set-pm-runtime-as-active-on.patch revert-usb-xhci-plat-set-pm-runtime-as-active-on-res.patch revert-usb-ohci-platform-fix-a-warning-when-hibernat.patch +efi-arm-defer-probe-of-pcie-backed-efifb-on-dt-syste.patch