]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/firmware/dmi_scan.c
Merge branch 'akpm-current/current'
[karo-tx-linux.git] / drivers / firmware / dmi_scan.c
index fa0affb699b42f51a070fb336d2f66df38b9dce6..17afc51f3054402c22a2a8d2fd50c1c809edd160 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/bootmem.h>
 #include <linux/random.h>
 #include <asm/dmi.h>
+#include <asm/unaligned.h>
 
 /*
  * DMI stands for "Desktop Management Interface".  It is part
@@ -25,6 +26,13 @@ static int dmi_initialized;
 /* DMI system identification string used during boot */
 static char dmi_ids_string[128] __initdata;
 
+static struct dmi_memdev_info {
+       const char *device;
+       const char *bank;
+       u16 handle;
+} *dmi_memdev;
+static int dmi_memdev_nr;
+
 static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
 {
        const u8 *bp = ((u8 *) dm) + dm->length;
@@ -108,7 +116,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
 {
        u8 *buf;
 
-       buf = dmi_ioremap(dmi_base, dmi_len);
+       buf = dmi_early_remap(dmi_base, dmi_len);
        if (buf == NULL)
                return -1;
 
@@ -116,7 +124,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
 
        add_device_randomness(buf, dmi_len);
 
-       dmi_iounmap(buf, dmi_len);
+       dmi_early_unmap(buf, dmi_len);
        return 0;
 }
 
@@ -322,6 +330,42 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
        dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
 }
 
+static void __init count_mem_devices(const struct dmi_header *dm, void *v)
+{
+       if (dm->type != DMI_ENTRY_MEM_DEVICE)
+               return;
+       dmi_memdev_nr++;
+}
+
+static void __init save_mem_devices(const struct dmi_header *dm, void *v)
+{
+       const char *d = (const char *)dm;
+       static int nr;
+
+       if (dm->type != DMI_ENTRY_MEM_DEVICE)
+               return;
+       if (nr >= dmi_memdev_nr) {
+               pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n");
+               return;
+       }
+       dmi_memdev[nr].handle = get_unaligned(&dm->handle);
+       dmi_memdev[nr].device = dmi_string(dm, d[0x10]);
+       dmi_memdev[nr].bank = dmi_string(dm, d[0x11]);
+       nr++;
+}
+
+void __init dmi_memdev_walk(void)
+{
+       if (!dmi_available)
+               return;
+
+       if (dmi_walk_early(count_mem_devices) == 0 && dmi_memdev_nr) {
+               dmi_memdev = dmi_alloc(sizeof(*dmi_memdev) * dmi_memdev_nr);
+               if (dmi_memdev)
+                       dmi_walk_early(save_mem_devices);
+       }
+}
+
 /*
  *     Process a DMI table entry. Right now all we care about are the BIOS
  *     and machine entries. For 2.5 we should pull the smbus controller info
@@ -483,18 +527,18 @@ void __init dmi_scan_machine(void)
                 * needed during early boot.  This also means we can
                 * iounmap the space when we're done with it.
                 */
-               p = dmi_ioremap(efi.smbios, 32);
+               p = dmi_early_remap(efi.smbios, 32);
                if (p == NULL)
                        goto error;
                memcpy_fromio(buf, p, 32);
-               dmi_iounmap(p, 32);
+               dmi_early_unmap(p, 32);
 
                if (!dmi_present(buf)) {
                        dmi_available = 1;
                        goto out;
                }
-       } else {
-               p = dmi_ioremap(0xF0000, 0x10000);
+       } else if (IS_ENABLED(CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK)) {
+               p = dmi_early_remap(0xF0000, 0x10000);
                if (p == NULL)
                        goto error;
 
@@ -510,12 +554,12 @@ void __init dmi_scan_machine(void)
                        memcpy_fromio(buf + 16, q, 16);
                        if (!dmi_present(buf)) {
                                dmi_available = 1;
-                               dmi_iounmap(p, 0x10000);
+                               dmi_early_unmap(p, 0x10000);
                                goto out;
                        }
                        memcpy(buf, buf + 16, 16);
                }
-               dmi_iounmap(p, 0x10000);
+               dmi_early_unmap(p, 0x10000);
        }
  error:
        pr_info("DMI not present or invalid.\n");
@@ -787,13 +831,13 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
        if (!dmi_available)
                return -1;
 
-       buf = ioremap(dmi_base, dmi_len);
+       buf = dmi_remap(dmi_base, dmi_len);
        if (buf == NULL)
                return -1;
 
        dmi_table(buf, dmi_len, dmi_num, decode, private_data);
 
-       iounmap(buf);
+       dmi_unmap(buf);
        return 0;
 }
 EXPORT_SYMBOL_GPL(dmi_walk);
@@ -815,3 +859,20 @@ bool dmi_match(enum dmi_field f, const char *str)
        return !strcmp(info, str);
 }
 EXPORT_SYMBOL_GPL(dmi_match);
+
+void dmi_memdev_name(u16 handle, const char **bank, const char **device)
+{
+       int n;
+
+       if (dmi_memdev == NULL)
+               return;
+
+       for (n = 0; n < dmi_memdev_nr; n++) {
+               if (handle == dmi_memdev[n].handle) {
+                       *bank = dmi_memdev[n].bank;
+                       *device = dmi_memdev[n].device;
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(dmi_memdev_name);