aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/dmi_scan.c
diff options
context:
space:
mode:
authorParag Warudkar <parag.warudkar@gmail.com>2008-01-30 07:31:59 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:59 -0500
commit79da4721117fcf188b4b007b775738a530f574da (patch)
tree114fcff65bbed673c6ec809c71892829116eaa8f /drivers/firmware/dmi_scan.c
parentaca46ba29298810b329518b96f97ace985027b59 (diff)
x86: fix DMI out of memory problems
People with HP Desktops (including me) encounter couple of DMI errors during boot - dmi_save_oem_strings_devices: out of memory and dmi_string: out of memory. On some HP desktops the DMI data include OEM strings (type 11) out of which only few are meaningful and most other are empty. DMI code religiously creates copies of these 27 strings (65 bytes each in my case) and goes OOM in dmi_string(). If DMI_MAX_DATA is bumped up a little then it goes and fails in dmi_save_oem_strings while allocating dmi_devices of sizeof(struct dmi_device) corresponding to these strings. On x86_64 since we cannot use alloc_bootmem this early, the code uses a static array of 2048 bytes (DMI_MAX_DATA) for allocating the memory DMI needs. It does not survive the creation of empty strings and devices. Fix this by detecting and not newly allocating empty strings and instead using a one statically defined dmi_empty_string. Also do not create a new struct dmi_device for each empty string - use one statically define dmi_device with .name=dmi_empty_string and add that to the dmi_devices list. On x64 this should stop the OOM with same current size of DMI_MAX_DATA and on x86 this should save a good amount of (27*65 bytes + 27*sizeof(struct dmi_device) bootmem. Compile and boot tested on both 32-bit and 64-bit x86. Signed-off-by: Parag Warudkar <parag.warudkar@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
-rw-r--r--drivers/firmware/dmi_scan.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 5e596a7e3601..0b24a1141009 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -8,6 +8,8 @@
8#include <linux/slab.h> 8#include <linux/slab.h>
9#include <asm/dmi.h> 9#include <asm/dmi.h>
10 10
11static char dmi_empty_string[] = " ";
12
11static char * __init dmi_string(const struct dmi_header *dm, u8 s) 13static char * __init dmi_string(const struct dmi_header *dm, u8 s)
12{ 14{
13 const u8 *bp = ((u8 *) dm) + dm->length; 15 const u8 *bp = ((u8 *) dm) + dm->length;
@@ -21,11 +23,16 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
21 } 23 }
22 24
23 if (*bp != 0) { 25 if (*bp != 0) {
24 str = dmi_alloc(strlen(bp) + 1); 26 size_t len = strlen(bp)+1;
27 size_t cmp_len = len > 8 ? 8 : len;
28
29 if (!memcmp(bp, dmi_empty_string, cmp_len))
30 return dmi_empty_string;
31 str = dmi_alloc(len);
25 if (str != NULL) 32 if (str != NULL)
26 strcpy(str, bp); 33 strcpy(str, bp);
27 else 34 else
28 printk(KERN_ERR "dmi_string: out of memory.\n"); 35 printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len);
29 } 36 }
30 } 37 }
31 38
@@ -175,12 +182,23 @@ static void __init dmi_save_devices(const struct dmi_header *dm)
175 } 182 }
176} 183}
177 184
185static struct dmi_device empty_oem_string_dev = {
186 .name = dmi_empty_string,
187};
188
178static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) 189static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
179{ 190{
180 int i, count = *(u8 *)(dm + 1); 191 int i, count = *(u8 *)(dm + 1);
181 struct dmi_device *dev; 192 struct dmi_device *dev;
182 193
183 for (i = 1; i <= count; i++) { 194 for (i = 1; i <= count; i++) {
195 char *devname = dmi_string(dm, i);
196
197 if (!strcmp(devname, dmi_empty_string)) {
198 list_add(&empty_oem_string_dev.list, &dmi_devices);
199 continue;
200 }
201
184 dev = dmi_alloc(sizeof(*dev)); 202 dev = dmi_alloc(sizeof(*dev));
185 if (!dev) { 203 if (!dev) {
186 printk(KERN_ERR 204 printk(KERN_ERR
@@ -189,7 +207,7 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
189 } 207 }
190 208
191 dev->type = DMI_DEV_TYPE_OEM_STRING; 209 dev->type = DMI_DEV_TYPE_OEM_STRING;
192 dev->name = dmi_string(dm, i); 210 dev->name = devname;
193 dev->device_data = NULL; 211 dev->device_data = NULL;
194 212
195 list_add(&dev->list, &dmi_devices); 213 list_add(&dev->list, &dmi_devices);