Kyle McMartin bc9e072
commit 85a00d9bbfb4704fbf368944b1cb9fed8f1598c5
Kyle McMartin bc9e072
Author: Peter Jones <pjones@redhat.com>
Kyle McMartin bc9e072
Date:   Wed Sep 22 13:05:04 2010 -0700
Kyle McMartin bc9e072
Kyle McMartin bc9e072
    efifb: check that the base address is plausible on pci systems
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    Some Apple machines have identical DMI data but different memory
Kyle McMartin bc9e072
    configurations for the video.  Given that, check that the address in our
Kyle McMartin bc9e072
    table is actually within the range of a PCI BAR on a VGA device in the
Kyle McMartin bc9e072
    machine.
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    This also fixes up the return value from set_system(), which has always
Kyle McMartin bc9e072
    been wrong, but never resulted in bad behavior since there's only ever
Kyle McMartin bc9e072
    been one matching entry in the dmi table.
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    The patch
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    1) stops people's machines from crashing when we get their display wrong,
Kyle McMartin bc9e072
       which seems to be unfortunately inevitable,
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    2) allows us to support identical dmi data with differing video memory
Kyle McMartin bc9e072
       configurations
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    This also adds me as the efifb maintainer, since I've effectively been
Kyle McMartin bc9e072
    acting as such for quite some time.
Kyle McMartin bc9e072
    
Kyle McMartin bc9e072
    Signed-off-by: Peter Jones <pjones@redhat.com>
Kyle McMartin bc9e072
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Kyle McMartin bc9e072
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Kyle McMartin bc9e072
Kyle McMartin bc9e072
diff --git a/MAINTAINERS b/MAINTAINERS
Kyle McMartin bc9e072
index 726433a..4d4881d 100644
Kyle McMartin bc9e072
--- a/MAINTAINERS
Kyle McMartin bc9e072
+++ b/MAINTAINERS
Kyle McMartin bc9e072
@@ -2199,6 +2199,12 @@ W:	http://acpi4asus.sf.net
Kyle McMartin bc9e072
 S:	Maintained
Kyle McMartin bc9e072
 F:	drivers/platform/x86/eeepc-laptop.c
Kyle McMartin bc9e072
 
Kyle McMartin bc9e072
+EFIFB FRAMEBUFFER DRIVER
Kyle McMartin bc9e072
+L:	linux-fbdev@vger.kernel.org
Kyle McMartin bc9e072
+M:	Peter Jones <pjones@redhat.com>
Kyle McMartin bc9e072
+S:	Maintained
Kyle McMartin bc9e072
+F:	drivers/video/efifb.c
Kyle McMartin bc9e072
+
Kyle McMartin bc9e072
 EFS FILESYSTEM
Kyle McMartin bc9e072
 W:	http://aeschi.ch.eu.org/efs/
Kyle McMartin bc9e072
 S:	Orphan
Kyle McMartin bc9e072
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
Kyle McMartin bc9e072
index 815f84b..c082b61 100644
Kyle McMartin bc9e072
--- a/drivers/video/efifb.c
Kyle McMartin bc9e072
+++ b/drivers/video/efifb.c
Kyle McMartin bc9e072
@@ -13,7 +13,7 @@
Kyle McMartin bc9e072
 #include <linux/platform_device.h>
Kyle McMartin bc9e072
 #include <linux/screen_info.h>
Kyle McMartin bc9e072
 #include <linux/dmi.h>
Kyle McMartin bc9e072
-
Kyle McMartin bc9e072
+#include <linux/pci.h>
Kyle McMartin bc9e072
 #include <video/vga.h>
Kyle McMartin bc9e072
 
Kyle McMartin bc9e072
 static struct fb_var_screeninfo efifb_defined __devinitdata = {
Kyle McMartin bc9e072
@@ -116,7 +116,7 @@ static int set_system(const struct dmi_system_id *id)
Kyle McMartin bc9e072
 {
Kyle McMartin bc9e072
 	struct efifb_dmi_info *info = id->driver_data;
Kyle McMartin bc9e072
 	if (info->base == 0)
Kyle McMartin bc9e072
-		return -ENODEV;
Kyle McMartin bc9e072
+		return 0;
Kyle McMartin bc9e072
 
Kyle McMartin bc9e072
 	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
Kyle McMartin bc9e072
 			 "(%dx%d, stride %d)\n", id->ident,
Kyle McMartin bc9e072
@@ -124,18 +124,55 @@ static int set_system(const struct dmi_system_id *id)
Kyle McMartin bc9e072
 			 info->stride);
Kyle McMartin bc9e072
 
Kyle McMartin bc9e072
 	/* Trust the bootloader over the DMI tables */
Kyle McMartin bc9e072
-	if (screen_info.lfb_base == 0)
Kyle McMartin bc9e072
+	if (screen_info.lfb_base == 0) {
Kyle McMartin bc9e072
+#if defined(CONFIG_PCI)
Kyle McMartin bc9e072
+		struct pci_dev *dev = NULL;
Kyle McMartin bc9e072
+		int found_bar = 0;
Kyle McMartin bc9e072
+#endif
Kyle McMartin bc9e072
 		screen_info.lfb_base = info->base;
Kyle McMartin bc9e072
-	if (screen_info.lfb_linelength == 0)
Kyle McMartin bc9e072
-		screen_info.lfb_linelength = info->stride;
Kyle McMartin bc9e072
-	if (screen_info.lfb_width == 0)
Kyle McMartin bc9e072
-		screen_info.lfb_width = info->width;
Kyle McMartin bc9e072
-	if (screen_info.lfb_height == 0)
Kyle McMartin bc9e072
-		screen_info.lfb_height = info->height;
Kyle McMartin bc9e072
-	if (screen_info.orig_video_isVGA == 0)
Kyle McMartin bc9e072
-		screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
Kyle McMartin bc9e072
 
Kyle McMartin bc9e072
-	return 0;
Kyle McMartin bc9e072
+#if defined(CONFIG_PCI)
Kyle McMartin bc9e072
+		/* make sure that the address in the table is actually on a
Kyle McMartin bc9e072
+		 * VGA device's PCI BAR */
Kyle McMartin bc9e072
+
Kyle McMartin bc9e072
+		for_each_pci_dev(dev) {
Kyle McMartin bc9e072
+			int i;
Kyle McMartin bc9e072
+			if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
Kyle McMartin bc9e072
+				continue;
Kyle McMartin bc9e072
+			for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
Kyle McMartin bc9e072
+				resource_size_t start, end;
Kyle McMartin bc9e072
+
Kyle McMartin bc9e072
+				start = pci_resource_start(dev, i);
Kyle McMartin bc9e072
+				if (start == 0)
Kyle McMartin bc9e072
+					break;
Kyle McMartin bc9e072
+				end = pci_resource_end(dev, i);
Kyle McMartin bc9e072
+				if (screen_info.lfb_base >= start &&
Kyle McMartin bc9e072
+						screen_info.lfb_base < end) {
Kyle McMartin bc9e072
+					found_bar = 1;
Kyle McMartin bc9e072
+				}
Kyle McMartin bc9e072
+			}
Kyle McMartin bc9e072
+		}
Kyle McMartin bc9e072
+		if (!found_bar)
Kyle McMartin bc9e072
+			screen_info.lfb_base = 0;
Kyle McMartin bc9e072
+#endif
Kyle McMartin bc9e072
+	}
Kyle McMartin bc9e072
+	if (screen_info.lfb_base) {
Kyle McMartin bc9e072
+		if (screen_info.lfb_linelength == 0)
Kyle McMartin bc9e072
+			screen_info.lfb_linelength = info->stride;
Kyle McMartin bc9e072
+		if (screen_info.lfb_width == 0)
Kyle McMartin bc9e072
+			screen_info.lfb_width = info->width;
Kyle McMartin bc9e072
+		if (screen_info.lfb_height == 0)
Kyle McMartin bc9e072
+			screen_info.lfb_height = info->height;
Kyle McMartin bc9e072
+		if (screen_info.orig_video_isVGA == 0)
Kyle McMartin bc9e072
+			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
Kyle McMartin bc9e072
+	} else {
Kyle McMartin bc9e072
+		screen_info.lfb_linelength = 0;
Kyle McMartin bc9e072
+		screen_info.lfb_width = 0;
Kyle McMartin bc9e072
+		screen_info.lfb_height = 0;
Kyle McMartin bc9e072
+		screen_info.orig_video_isVGA = 0;
Kyle McMartin bc9e072
+		return 0;
Kyle McMartin bc9e072
+	}
Kyle McMartin bc9e072
+	return 1;
Kyle McMartin bc9e072
 }
Kyle McMartin bc9e072
 
Kyle McMartin bc9e072
 static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,