Commit dd6dad4288cb93e79bd7abfa6c6a338c47454d1a

Authored by Chen, Gong
Committed by Tony Luck
1 parent 4b3db708b1

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
... ... @@ -1063,6 +1063,7 @@
1063 1063 static int __init run_dmi_scan(void)
1064 1064 {
1065 1065 dmi_scan_machine();
  1066 + dmi_memdev_walk();
1066 1067 dmi_set_dump_stack_arch_desc();
1067 1068 return 0;
1068 1069 }
arch/x86/kernel/setup.c
... ... @@ -993,6 +993,7 @@
993 993 efi_init();
994 994  
995 995 dmi_scan_machine();
  996 + dmi_memdev_walk();
996 997 dmi_set_dump_stack_arch_desc();
997 998  
998 999 /*
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);
... ... @@ -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