aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPeter Jones <pjones@redhat.com>2010-09-22 16:05:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-09-22 20:22:39 -0400
commit85a00d9bbfb4704fbf368944b1cb9fed8f1598c5 (patch)
treeb9d5f22610675f4d8bbdeba2ccdcb4c232140499 /drivers
parenta0c42bac79731276c9b2f28d54f9e658fcf843a2 (diff)
efifb: check that the base address is plausible on pci systems
Some Apple machines have identical DMI data but different memory configurations for the video. Given that, check that the address in our table is actually within the range of a PCI BAR on a VGA device in the machine. This also fixes up the return value from set_system(), which has always been wrong, but never resulted in bad behavior since there's only ever been one matching entry in the dmi table. The patch 1) stops people's machines from crashing when we get their display wrong, which seems to be unfortunately inevitable, 2) allows us to support identical dmi data with differing video memory configurations This also adds me as the efifb maintainer, since I've effectively been acting as such for quite some time. Signed-off-by: Peter Jones <pjones@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/efifb.c61
1 files changed, 49 insertions, 12 deletions
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 815f84b07933..c082b616f390 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -13,7 +13,7 @@
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14#include <linux/screen_info.h> 14#include <linux/screen_info.h>
15#include <linux/dmi.h> 15#include <linux/dmi.h>
16 16#include <linux/pci.h>
17#include <video/vga.h> 17#include <video/vga.h>
18 18
19static struct fb_var_screeninfo efifb_defined __devinitdata = { 19static struct fb_var_screeninfo efifb_defined __devinitdata = {
@@ -116,7 +116,7 @@ static int set_system(const struct dmi_system_id *id)
116{ 116{
117 struct efifb_dmi_info *info = id->driver_data; 117 struct efifb_dmi_info *info = id->driver_data;
118 if (info->base == 0) 118 if (info->base == 0)
119 return -ENODEV; 119 return 0;
120 120
121 printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " 121 printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
122 "(%dx%d, stride %d)\n", id->ident, 122 "(%dx%d, stride %d)\n", id->ident,
@@ -124,18 +124,55 @@ static int set_system(const struct dmi_system_id *id)
124 info->stride); 124 info->stride);
125 125
126 /* Trust the bootloader over the DMI tables */ 126 /* Trust the bootloader over the DMI tables */
127 if (screen_info.lfb_base == 0) 127 if (screen_info.lfb_base == 0) {
128#if defined(CONFIG_PCI)
129 struct pci_dev *dev = NULL;
130 int found_bar = 0;
131#endif
128 screen_info.lfb_base = info->base; 132 screen_info.lfb_base = info->base;
129 if (screen_info.lfb_linelength == 0)
130 screen_info.lfb_linelength = info->stride;
131 if (screen_info.lfb_width == 0)
132 screen_info.lfb_width = info->width;
133 if (screen_info.lfb_height == 0)
134 screen_info.lfb_height = info->height;
135 if (screen_info.orig_video_isVGA == 0)
136 screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
137 133
138 return 0; 134#if defined(CONFIG_PCI)
135 /* make sure that the address in the table is actually on a
136 * VGA device's PCI BAR */
137
138 for_each_pci_dev(dev) {
139 int i;
140 if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
141 continue;
142 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
143 resource_size_t start, end;
144
145 start = pci_resource_start(dev, i);
146 if (start == 0)
147 break;
148 end = pci_resource_end(dev, i);
149 if (screen_info.lfb_base >= start &&
150 screen_info.lfb_base < end) {
151 found_bar = 1;
152 }
153 }
154 }
155 if (!found_bar)
156 screen_info.lfb_base = 0;
157#endif
158 }
159 if (screen_info.lfb_base) {
160 if (screen_info.lfb_linelength == 0)
161 screen_info.lfb_linelength = info->stride;
162 if (screen_info.lfb_width == 0)
163 screen_info.lfb_width = info->width;
164 if (screen_info.lfb_height == 0)
165 screen_info.lfb_height = info->height;
166 if (screen_info.orig_video_isVGA == 0)
167 screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
168 } else {
169 screen_info.lfb_linelength = 0;
170 screen_info.lfb_width = 0;
171 screen_info.lfb_height = 0;
172 screen_info.orig_video_isVGA = 0;
173 return 0;
174 }
175 return 1;
139} 176}
140 177
141static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, 178static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,