aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-04-04 11:27:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-21 03:31:20 -0400
commiteff58f9084a099fd7afe54b0bdcb68d4fbdbdd89 (patch)
tree43360af2e101ea40777aeb86ea3e2c827b82332d
parent60174fb3eaa6c84273f282125c4cccdc701549a8 (diff)
efi/fb: Avoid reconfiguration of BAR that covers the framebuffer
commit 55d728a40d368ba80443be85c02e641fc9082a3f upstream. On UEFI systems, the PCI subsystem is enumerated by the firmware, and if a graphical framebuffer is exposed via a PCI device, its base address and size are exposed to the OS via the Graphics Output Protocol (GOP). On arm64 PCI systems, the entire PCI hierarchy is reconfigured from scratch at boot. This may result in the GOP framebuffer address to become stale, if the BAR covering the framebuffer is modified. This will cause the framebuffer to become unresponsive, and may in some cases result in unpredictable behavior if the range is reassigned to another device. So add a non-x86 quirk to the EFI fb driver to find the BAR associated with the GOP base address, and claim the BAR resource so that the PCI core will not move it. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Matt Fleming <matt@codeblueprint.co.uk> Cc: Peter Jones <pjones@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: leif.lindholm@linaro.org Cc: linux-efi@vger.kernel.org Cc: lorenzo.pieralisi@arm.com Fixes: 9822504c1fa5 ("efifb: Enable the efi-framebuffer platform driver ...") Link: http://lkml.kernel.org/r/20170404152744.26687-3-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/video/fbdev/efifb.c66
1 files changed, 65 insertions, 1 deletions
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 37a37c4d04cb..6f2e729a308f 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -10,6 +10,7 @@
10#include <linux/efi.h> 10#include <linux/efi.h>
11#include <linux/errno.h> 11#include <linux/errno.h>
12#include <linux/fb.h> 12#include <linux/fb.h>
13#include <linux/pci.h>
13#include <linux/platform_device.h> 14#include <linux/platform_device.h>
14#include <linux/screen_info.h> 15#include <linux/screen_info.h>
15#include <video/vga.h> 16#include <video/vga.h>
@@ -118,6 +119,8 @@ static inline bool fb_base_is_valid(void)
118 return false; 119 return false;
119} 120}
120 121
122static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */
123
121static int efifb_probe(struct platform_device *dev) 124static int efifb_probe(struct platform_device *dev)
122{ 125{
123 struct fb_info *info; 126 struct fb_info *info;
@@ -127,7 +130,7 @@ static int efifb_probe(struct platform_device *dev)
127 unsigned int size_total; 130 unsigned int size_total;
128 char *option = NULL; 131 char *option = NULL;
129 132
130 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) 133 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
131 return -ENODEV; 134 return -ENODEV;
132 135
133 if (fb_get_options("efifb", &option)) 136 if (fb_get_options("efifb", &option))
@@ -327,3 +330,64 @@ static struct platform_driver efifb_driver = {
327}; 330};
328 331
329builtin_platform_driver(efifb_driver); 332builtin_platform_driver(efifb_driver);
333
334#if defined(CONFIG_PCI) && !defined(CONFIG_X86)
335
336static bool pci_bar_found; /* did we find a BAR matching the efifb base? */
337
338static void claim_efifb_bar(struct pci_dev *dev, int idx)
339{
340 u16 word;
341
342 pci_bar_found = true;
343
344 pci_read_config_word(dev, PCI_COMMAND, &word);
345 if (!(word & PCI_COMMAND_MEMORY)) {
346 pci_dev_disabled = true;
347 dev_err(&dev->dev,
348 "BAR %d: assigned to efifb but device is disabled!\n",
349 idx);
350 return;
351 }
352
353 if (pci_claim_resource(dev, idx)) {
354 pci_dev_disabled = true;
355 dev_err(&dev->dev,
356 "BAR %d: failed to claim resource for efifb!\n", idx);
357 return;
358 }
359
360 dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
361}
362
363static void efifb_fixup_resources(struct pci_dev *dev)
364{
365 u64 base = screen_info.lfb_base;
366 u64 size = screen_info.lfb_size;
367 int i;
368
369 if (pci_bar_found || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
370 return;
371
372 if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
373 base |= (u64)screen_info.ext_lfb_base << 32;
374
375 if (!base)
376 return;
377
378 for (i = 0; i < PCI_STD_RESOURCE_END; i++) {
379 struct resource *res = &dev->resource[i];
380
381 if (!(res->flags & IORESOURCE_MEM))
382 continue;
383
384 if (res->start <= base && res->end >= base + size - 1) {
385 claim_efifb_bar(dev, i);
386 break;
387 }
388 }
389}
390DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY,
391 16, efifb_fixup_resources);
392
393#endif