diff options
author | Chen, Gong <gong.chen@linux.intel.com> | 2013-10-18 17:29:25 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2013-10-23 13:10:12 -0400 |
commit | dd6dad4288cb93e79bd7abfa6c6a338c47454d1a (patch) | |
tree | 0e50552871a2ae86513d1a3cce21282f5002241a | |
parent | 4b3db708b114fc35ff1e0cd28a2bfb1490dbb5d3 (diff) |
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>
-rw-r--r-- | arch/ia64/kernel/setup.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 1 | ||||
-rw-r--r-- | drivers/firmware/dmi_scan.c | 60 | ||||
-rw-r--r-- | include/linux/dmi.h | 5 |
4 files changed, 67 insertions, 0 deletions
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 4fc2e9569bb2..d86669bcdfb2 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
@@ -1063,6 +1063,7 @@ check_bugs (void) | |||
1063 | static int __init run_dmi_scan(void) | 1063 | static int __init run_dmi_scan(void) |
1064 | { | 1064 | { |
1065 | dmi_scan_machine(); | 1065 | dmi_scan_machine(); |
1066 | dmi_memdev_walk(); | ||
1066 | dmi_set_dump_stack_arch_desc(); | 1067 | dmi_set_dump_stack_arch_desc(); |
1067 | return 0; | 1068 | return 0; |
1068 | } | 1069 | } |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index f0de6294b955..918d489fa53d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -993,6 +993,7 @@ void __init setup_arch(char **cmdline_p) | |||
993 | efi_init(); | 993 | efi_init(); |
994 | 994 | ||
995 | dmi_scan_machine(); | 995 | dmi_scan_machine(); |
996 | dmi_memdev_walk(); | ||
996 | dmi_set_dump_stack_arch_desc(); | 997 | dmi_set_dump_stack_arch_desc(); |
997 | 998 | ||
998 | /* | 999 | /* |
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index fa0affb699b4..59579a744d58 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
@@ -25,6 +25,13 @@ static int dmi_initialized; | |||
25 | /* DMI system identification string used during boot */ | 25 | /* DMI system identification string used during boot */ |
26 | static char dmi_ids_string[128] __initdata; | 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 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) | 35 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) |
29 | { | 36 | { |
30 | const u8 *bp = ((u8 *) dm) + dm->length; | 37 | const u8 *bp = ((u8 *) dm) + dm->length; |
@@ -322,6 +329,42 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm) | |||
322 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); | 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 | * Process a DMI table entry. Right now all we care about are the BIOS | 369 | * Process a DMI table entry. Right now all we care about are the BIOS |
327 | * and machine entries. For 2.5 we should pull the smbus controller info | 370 | * and machine entries. For 2.5 we should pull the smbus controller info |
@@ -815,3 +858,20 @@ bool dmi_match(enum dmi_field f, const char *str) | |||
815 | return !strcmp(info, str); | 858 | return !strcmp(info, str); |
816 | } | 859 | } |
817 | EXPORT_SYMBOL_GPL(dmi_match); | 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); | ||
diff --git a/include/linux/dmi.h b/include/linux/dmi.h index b6eb7a05d58e..f820f0a336c9 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h | |||
@@ -99,6 +99,7 @@ extern const char * dmi_get_system_info(int field); | |||
99 | extern const struct dmi_device * dmi_find_device(int type, const char *name, | 99 | extern const struct dmi_device * dmi_find_device(int type, const char *name, |
100 | const struct dmi_device *from); | 100 | const struct dmi_device *from); |
101 | extern void dmi_scan_machine(void); | 101 | extern void dmi_scan_machine(void); |
102 | extern void dmi_memdev_walk(void); | ||
102 | extern void dmi_set_dump_stack_arch_desc(void); | 103 | extern void dmi_set_dump_stack_arch_desc(void); |
103 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); | 104 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); |
104 | extern int dmi_name_in_vendors(const char *str); | 105 | extern int dmi_name_in_vendors(const char *str); |
@@ -107,6 +108,7 @@ extern int dmi_available; | |||
107 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), | 108 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
108 | void *private_data); | 109 | void *private_data); |
109 | extern bool dmi_match(enum dmi_field f, const char *str); | 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 | #else | 113 | #else |
112 | 114 | ||
@@ -115,6 +117,7 @@ static inline const char * dmi_get_system_info(int field) { return NULL; } | |||
115 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, | 117 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, |
116 | const struct dmi_device *from) { return NULL; } | 118 | const struct dmi_device *from) { return NULL; } |
117 | static inline void dmi_scan_machine(void) { return; } | 119 | static inline void dmi_scan_machine(void) { return; } |
120 | static inline void dmi_memdev_walk(void) { } | ||
118 | static inline void dmi_set_dump_stack_arch_desc(void) { } | 121 | static inline void dmi_set_dump_stack_arch_desc(void) { } |
119 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) | 122 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) |
120 | { | 123 | { |
@@ -133,6 +136,8 @@ static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *), | |||
133 | void *private_data) { return -1; } | 136 | void *private_data) { return -1; } |
134 | static inline bool dmi_match(enum dmi_field f, const char *str) | 137 | static inline bool dmi_match(enum dmi_field f, const char *str) |
135 | { return false; } | 138 | { return false; } |
139 | static inline void dmi_memdev_name(u16 handle, const char **bank, | ||
140 | const char **device) { } | ||
136 | static inline const struct dmi_system_id * | 141 | static inline const struct dmi_system_id * |
137 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } | 142 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } |
138 | 143 | ||