Commit dd6dad4288cb93e79bd7abfa6c6a338c47454d1a
Committed by
Tony Luck
1 parent
4b3db708b1
Exists in
master
and in
16 other branches
DMI: Parse memory device (type 17) in SMBIOS
This patch adds a new interface to decode memory device (type 17) to help error reporting on DIMMs. Original-author: Tony Luck <tony.luck@intel.com> Signed-off-by: Chen, Gong <gong.chen@linux.intel.com> Acked-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Acked-by: Borislav Petkov <bp@suse.de> Reviewed-by: Mauro Carvalho Chehab <m.chehab@samsung.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Showing 4 changed files with 67 additions and 0 deletions Side-by-side Diff
arch/ia64/kernel/setup.c
arch/x86/kernel/setup.c
drivers/firmware/dmi_scan.c
... | ... | @@ -25,6 +25,13 @@ |
25 | 25 | /* DMI system identification string used during boot */ |
26 | 26 | static char dmi_ids_string[128] __initdata; |
27 | 27 | |
28 | +static struct dmi_memdev_info { | |
29 | + const char *device; | |
30 | + const char *bank; | |
31 | + u16 handle; | |
32 | +} *dmi_memdev; | |
33 | +static int dmi_memdev_nr; | |
34 | + | |
28 | 35 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) |
29 | 36 | { |
30 | 37 | const u8 *bp = ((u8 *) dm) + dm->length; |
... | ... | @@ -322,6 +329,42 @@ |
322 | 329 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); |
323 | 330 | } |
324 | 331 | |
332 | +static void __init count_mem_devices(const struct dmi_header *dm, void *v) | |
333 | +{ | |
334 | + if (dm->type != DMI_ENTRY_MEM_DEVICE) | |
335 | + return; | |
336 | + dmi_memdev_nr++; | |
337 | +} | |
338 | + | |
339 | +static void __init save_mem_devices(const struct dmi_header *dm, void *v) | |
340 | +{ | |
341 | + const char *d = (const char *)dm; | |
342 | + static int nr; | |
343 | + | |
344 | + if (dm->type != DMI_ENTRY_MEM_DEVICE) | |
345 | + return; | |
346 | + if (nr >= dmi_memdev_nr) { | |
347 | + pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n"); | |
348 | + return; | |
349 | + } | |
350 | + dmi_memdev[nr].handle = dm->handle; | |
351 | + dmi_memdev[nr].device = dmi_string(dm, d[0x10]); | |
352 | + dmi_memdev[nr].bank = dmi_string(dm, d[0x11]); | |
353 | + nr++; | |
354 | +} | |
355 | + | |
356 | +void __init dmi_memdev_walk(void) | |
357 | +{ | |
358 | + if (!dmi_available) | |
359 | + return; | |
360 | + | |
361 | + if (dmi_walk_early(count_mem_devices) == 0 && dmi_memdev_nr) { | |
362 | + dmi_memdev = dmi_alloc(sizeof(*dmi_memdev) * dmi_memdev_nr); | |
363 | + if (dmi_memdev) | |
364 | + dmi_walk_early(save_mem_devices); | |
365 | + } | |
366 | +} | |
367 | + | |
325 | 368 | /* |
326 | 369 | * Process a DMI table entry. Right now all we care about are the BIOS |
327 | 370 | * and machine entries. For 2.5 we should pull the smbus controller info |
... | ... | @@ -815,4 +858,21 @@ |
815 | 858 | return !strcmp(info, str); |
816 | 859 | } |
817 | 860 | EXPORT_SYMBOL_GPL(dmi_match); |
861 | + | |
862 | +void dmi_memdev_name(u16 handle, const char **bank, const char **device) | |
863 | +{ | |
864 | + int n; | |
865 | + | |
866 | + if (dmi_memdev == NULL) | |
867 | + return; | |
868 | + | |
869 | + for (n = 0; n < dmi_memdev_nr; n++) { | |
870 | + if (handle == dmi_memdev[n].handle) { | |
871 | + *bank = dmi_memdev[n].bank; | |
872 | + *device = dmi_memdev[n].device; | |
873 | + break; | |
874 | + } | |
875 | + } | |
876 | +} | |
877 | +EXPORT_SYMBOL_GPL(dmi_memdev_name); |
include/linux/dmi.h
... | ... | @@ -99,6 +99,7 @@ |
99 | 99 | extern const struct dmi_device * dmi_find_device(int type, const char *name, |
100 | 100 | const struct dmi_device *from); |
101 | 101 | extern void dmi_scan_machine(void); |
102 | +extern void dmi_memdev_walk(void); | |
102 | 103 | extern void dmi_set_dump_stack_arch_desc(void); |
103 | 104 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); |
104 | 105 | extern int dmi_name_in_vendors(const char *str); |
... | ... | @@ -107,6 +108,7 @@ |
107 | 108 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
108 | 109 | void *private_data); |
109 | 110 | extern bool dmi_match(enum dmi_field f, const char *str); |
111 | +extern void dmi_memdev_name(u16 handle, const char **bank, const char **device); | |
110 | 112 | |
111 | 113 | #else |
112 | 114 | |
... | ... | @@ -115,6 +117,7 @@ |
115 | 117 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, |
116 | 118 | const struct dmi_device *from) { return NULL; } |
117 | 119 | static inline void dmi_scan_machine(void) { return; } |
120 | +static inline void dmi_memdev_walk(void) { } | |
118 | 121 | static inline void dmi_set_dump_stack_arch_desc(void) { } |
119 | 122 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) |
120 | 123 | { |
... | ... | @@ -133,6 +136,8 @@ |
133 | 136 | void *private_data) { return -1; } |
134 | 137 | static inline bool dmi_match(enum dmi_field f, const char *str) |
135 | 138 | { return false; } |
139 | +static inline void dmi_memdev_name(u16 handle, const char **bank, | |
140 | + const char **device) { } | |
136 | 141 | static inline const struct dmi_system_id * |
137 | 142 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } |
138 | 143 |