]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.9
authorSasha Levin <sashal@kernel.org>
Sat, 18 Jul 2020 19:15:44 +0000 (15:15 -0400)
committerSasha Levin <sashal@kernel.org>
Sat, 18 Jul 2020 19:15:44 +0000 (15:15 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.9/efi-arm-defer-probe-of-pcie-backed-efifb-on-dt-syste.patch [new file with mode: 0644]
queue-4.9/series

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 (file)
index 0000000..bad19ae
--- /dev/null
@@ -0,0 +1,168 @@
+From cff5a08a72f64cc9fb3191a87903955fa0e2cf7f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2020 18:22:40 +0100
+Subject: efi/arm: Defer probe of PCIe backed efifb on DT systems
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+[ 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 <saravanak@google.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Saravana Kannan <saravanak@google.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Link: https://lore.kernel.org/r/20200113172245.27925-9-ardb@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 <linux/efi.h>
++#include <linux/fwnode.h>
+ #include <linux/init.h>
+ #include <linux/memblock.h>
+ #include <linux/mm_types.h>
+ #include <linux/of.h>
++#include <linux/of_address.h>
+ #include <linux/of_fdt.h>
+ #include <linux/platform_device.h>
+ #include <linux/screen_info.h>
+@@ -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
+
index 5e8741e62efacced524a9b930628c0b811679e76..036ef8b39124af7060046d2dd8b3e375a3febaf3 100644 (file)
@@ -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