These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / firmware / dmi_scan.c
index bba843c..0e08e66 100644 (file)
@@ -10,6 +10,9 @@
 #include <asm/dmi.h>
 #include <asm/unaligned.h>
 
+struct kobject *dmi_kobj;
+EXPORT_SYMBOL_GPL(dmi_kobj);
+
 /*
  * DMI stands for "Desktop Management Interface".  It is part
  * of and an antecedent to, SMBIOS, which stands for System
@@ -20,6 +23,9 @@ static const char dmi_empty_string[] = "        ";
 static u32 dmi_ver __initdata;
 static u32 dmi_len;
 static u16 dmi_num;
+static u8 smbios_entry_point[32];
+static int smbios_entry_point_size;
+
 /*
  * Catch too early calls to dmi_check_system():
  */
@@ -80,9 +86,9 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
  *     We have to be cautious here. We have seen BIOSes with DMI pointers
  *     pointing to completely the wrong place for example
  */
-static void dmi_table(u8 *buf,
-                     void (*decode)(const struct dmi_header *, void *),
-                     void *private_data)
+static void dmi_decode_table(u8 *buf,
+                            void (*decode)(const struct dmi_header *, void *),
+                            void *private_data)
 {
        u8 *data = buf;
        int i = 0;
@@ -108,6 +114,9 @@ static void dmi_table(u8 *buf,
                if (data - buf < dmi_len - 1)
                        decode(dm, private_data);
 
+               data += 2;
+               i++;
+
                /*
                 * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
                 * For tables behind a 64-bit entry point, we have no item
@@ -118,10 +127,11 @@ static void dmi_table(u8 *buf,
                 */
                if (!dmi_num && dm->type == DMI_ENTRY_END_OF_TABLE)
                        break;
-
-               data += 2;
-               i++;
        }
+
+       /* Trim DMI table length if needed */
+       if (dmi_len > data - buf)
+               dmi_len = data - buf;
 }
 
 static phys_addr_t dmi_base;
@@ -130,16 +140,17 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
                void *))
 {
        u8 *buf;
+       u32 orig_dmi_len = dmi_len;
 
-       buf = dmi_early_remap(dmi_base, dmi_len);
+       buf = dmi_early_remap(dmi_base, orig_dmi_len);
        if (buf == NULL)
                return -1;
 
-       dmi_table(buf, decode, NULL);
+       dmi_decode_table(buf, decode, NULL);
 
        add_device_randomness(buf, dmi_len);
 
-       dmi_early_unmap(buf, dmi_len);
+       dmi_early_unmap(buf, orig_dmi_len);
        return 0;
 }
 
@@ -483,17 +494,19 @@ static int __init dmi_present(const u8 *buf)
        if (memcmp(buf, "_SM_", 4) == 0 &&
            buf[5] < 32 && dmi_checksum(buf, buf[5])) {
                smbios_ver = get_unaligned_be16(buf + 6);
+               smbios_entry_point_size = buf[5];
+               memcpy(smbios_entry_point, buf, smbios_entry_point_size);
 
                /* Some BIOS report weird SMBIOS version, fix that up */
                switch (smbios_ver) {
                case 0x021F:
                case 0x0221:
-                       pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
+                       pr_debug("SMBIOS version fixup (2.%d->2.%d)\n",
                                 smbios_ver & 0xFF, 3);
                        smbios_ver = 0x0203;
                        break;
                case 0x0233:
-                       pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
+                       pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", 51, 6);
                        smbios_ver = 0x0206;
                        break;
                }
@@ -508,6 +521,7 @@ static int __init dmi_present(const u8 *buf)
                        dmi_ver = smbios_ver;
                else
                        dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F);
+               dmi_ver <<= 8;
                dmi_num = get_unaligned_le16(buf + 12);
                dmi_len = get_unaligned_le16(buf + 6);
                dmi_base = get_unaligned_le32(buf + 8);
@@ -515,12 +529,14 @@ static int __init dmi_present(const u8 *buf)
                if (dmi_walk_early(dmi_decode) == 0) {
                        if (smbios_ver) {
                                pr_info("SMBIOS %d.%d present.\n",
-                                      dmi_ver >> 8, dmi_ver & 0xFF);
+                                       dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
                        } else {
+                               smbios_entry_point_size = 15;
+                               memcpy(smbios_entry_point, buf,
+                                      smbios_entry_point_size);
                                pr_info("Legacy DMI %d.%d present.\n",
-                                      dmi_ver >> 8, dmi_ver & 0xFF);
+                                       dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
                        }
-                       dmi_ver <<= 8;
                        dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
                        printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
                        return 0;
@@ -538,11 +554,12 @@ static int __init dmi_smbios3_present(const u8 *buf)
 {
        if (memcmp(buf, "_SM3_", 5) == 0 &&
            buf[6] < 32 && dmi_checksum(buf, buf[6])) {
-               dmi_ver = get_unaligned_be32(buf + 6);
-               dmi_ver &= 0xFFFFFF;
+               dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF;
                dmi_num = 0;                    /* No longer specified */
                dmi_len = get_unaligned_le32(buf + 12);
                dmi_base = get_unaligned_le64(buf + 16);
+               smbios_entry_point_size = buf[6];
+               memcpy(smbios_entry_point, buf, smbios_entry_point_size);
 
                if (dmi_walk_early(dmi_decode) == 0) {
                        pr_info("SMBIOS %d.%d.%d present.\n",
@@ -634,6 +651,71 @@ void __init dmi_scan_machine(void)
        dmi_initialized = 1;
 }
 
+static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
+                             struct bin_attribute *attr, char *buf,
+                             loff_t pos, size_t count)
+{
+       memcpy(buf, attr->private + pos, count);
+       return count;
+}
+
+static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
+static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);
+
+static int __init dmi_init(void)
+{
+       struct kobject *tables_kobj;
+       u8 *dmi_table;
+       int ret = -ENOMEM;
+
+       if (!dmi_available) {
+               ret = -ENODATA;
+               goto err;
+       }
+
+       /*
+        * Set up dmi directory at /sys/firmware/dmi. This entry should stay
+        * even after farther error, as it can be used by other modules like
+        * dmi-sysfs.
+        */
+       dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
+       if (!dmi_kobj)
+               goto err;
+
+       tables_kobj = kobject_create_and_add("tables", dmi_kobj);
+       if (!tables_kobj)
+               goto err;
+
+       dmi_table = dmi_remap(dmi_base, dmi_len);
+       if (!dmi_table)
+               goto err_tables;
+
+       bin_attr_smbios_entry_point.size = smbios_entry_point_size;
+       bin_attr_smbios_entry_point.private = smbios_entry_point;
+       ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
+       if (ret)
+               goto err_unmap;
+
+       bin_attr_DMI.size = dmi_len;
+       bin_attr_DMI.private = dmi_table;
+       ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
+       if (!ret)
+               return 0;
+
+       sysfs_remove_bin_file(tables_kobj,
+                             &bin_attr_smbios_entry_point);
+ err_unmap:
+       dmi_unmap(dmi_table);
+ err_tables:
+       kobject_del(tables_kobj);
+       kobject_put(tables_kobj);
+ err:
+       pr_err("dmi: Firmware registration failed.\n");
+
+       return ret;
+}
+subsys_initcall(dmi_init);
+
 /**
  * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
  *
@@ -902,7 +984,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
        if (buf == NULL)
                return -1;
 
-       dmi_table(buf, decode, private_data);
+       dmi_decode_table(buf, decode, private_data);
 
        dmi_unmap(buf);
        return 0;