aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-dmi-entries (renamed from Documentation/ABI/testing/sysfs-firmware-dmi)2
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-dmi-tables22
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/firmware/dmi-sysfs.c17
-rw-r--r--drivers/firmware/dmi_scan.c123
-rw-r--r--include/linux/dmi.h4
6 files changed, 141 insertions, 29 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi b/Documentation/ABI/testing/sysfs-firmware-dmi-entries
index c78f9ab01e56..210ad44b95a5 100644
--- a/Documentation/ABI/testing/sysfs-firmware-dmi
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi-entries
@@ -1,4 +1,4 @@
1What: /sys/firmware/dmi/ 1What: /sys/firmware/dmi/entries/
2Date: February 2011 2Date: February 2011
3Contact: Mike Waychison <mikew@google.com> 3Contact: Mike Waychison <mikew@google.com>
4Description: 4Description:
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi-tables b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
new file mode 100644
index 000000000000..ff3cac8ed0bd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
@@ -0,0 +1,22 @@
1What: /sys/firmware/dmi/tables/
2Date: April 2015
3Contact: Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
4Description:
5 The firmware provides DMI structures as a packed list of
6 data referenced by a SMBIOS table entry point. The SMBIOS
7 entry point contains general information, like SMBIOS
8 version, DMI table size, etc. The structure, content and
9 size of SMBIOS entry point is dependent on SMBIOS version.
10 The format of SMBIOS entry point and DMI structures
11 can be read in SMBIOS specification.
12
13 The dmi/tables provides raw SMBIOS entry point and DMI tables
14 through sysfs as an alternative to utilities reading them
15 from /dev/mem. The raw SMBIOS entry point and DMI table are
16 presented as binary attributes and are accessible via:
17
18 /sys/firmware/dmi/tables/smbios_entry_point
19 /sys/firmware/dmi/tables/DMI
20
21 The complete DMI information can be obtained using these two
22 tables.
diff --git a/MAINTAINERS b/MAINTAINERS
index 73cfd4b0f539..25916c00d7a3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3337,6 +3337,8 @@ F: drivers/hwmon/dme1737.c
3337DMI/SMBIOS SUPPORT 3337DMI/SMBIOS SUPPORT
3338M: Jean Delvare <jdelvare@suse.de> 3338M: Jean Delvare <jdelvare@suse.de>
3339S: Maintained 3339S: Maintained
3340T: quilt http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/
3341F: Documentation/ABI/testing/sysfs-firmware-dmi-tables
3340F: drivers/firmware/dmi-id.c 3342F: drivers/firmware/dmi-id.c
3341F: drivers/firmware/dmi_scan.c 3343F: drivers/firmware/dmi_scan.c
3342F: include/linux/dmi.h 3344F: include/linux/dmi.h
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
index e0f1cb3d3598..ef76e5eecf0b 100644
--- a/drivers/firmware/dmi-sysfs.c
+++ b/drivers/firmware/dmi-sysfs.c
@@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
566 .default_attrs = dmi_sysfs_entry_attrs, 566 .default_attrs = dmi_sysfs_entry_attrs,
567}; 567};
568 568
569static struct kobject *dmi_kobj;
570static struct kset *dmi_kset; 569static struct kset *dmi_kset;
571 570
572/* Global count of all instances seen. Only for setup */ 571/* Global count of all instances seen. Only for setup */
@@ -648,17 +647,20 @@ static void cleanup_entry_list(void)
648 647
649static int __init dmi_sysfs_init(void) 648static int __init dmi_sysfs_init(void)
650{ 649{
651 int error = -ENOMEM; 650 int error;
652 int val; 651 int val;
653 652
654 /* Set up our directory */ 653 if (!dmi_kobj) {
655 dmi_kobj = kobject_create_and_add("dmi", firmware_kobj); 654 pr_err("dmi-sysfs: dmi entry is absent.\n");
656 if (!dmi_kobj) 655 error = -ENODATA;
657 goto err; 656 goto err;
657 }
658 658
659 dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj); 659 dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
660 if (!dmi_kset) 660 if (!dmi_kset) {
661 error = -ENOMEM;
661 goto err; 662 goto err;
663 }
662 664
663 val = 0; 665 val = 0;
664 error = dmi_walk(dmi_sysfs_register_handle, &val); 666 error = dmi_walk(dmi_sysfs_register_handle, &val);
@@ -675,7 +677,6 @@ static int __init dmi_sysfs_init(void)
675err: 677err:
676 cleanup_entry_list(); 678 cleanup_entry_list();
677 kset_unregister(dmi_kset); 679 kset_unregister(dmi_kset);
678 kobject_put(dmi_kobj);
679 return error; 680 return error;
680} 681}
681 682
@@ -685,8 +686,6 @@ static void __exit dmi_sysfs_exit(void)
685 pr_debug("dmi-sysfs: unloading.\n"); 686 pr_debug("dmi-sysfs: unloading.\n");
686 cleanup_entry_list(); 687 cleanup_entry_list();
687 kset_unregister(dmi_kset); 688 kset_unregister(dmi_kset);
688 kobject_del(dmi_kobj);
689 kobject_put(dmi_kobj);
690} 689}
691 690
692module_init(dmi_sysfs_init); 691module_init(dmi_sysfs_init);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 97b1616aa391..ac1ce4a73edf 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -10,6 +10,9 @@
10#include <asm/dmi.h> 10#include <asm/dmi.h>
11#include <asm/unaligned.h> 11#include <asm/unaligned.h>
12 12
13struct kobject *dmi_kobj;
14EXPORT_SYMBOL_GPL(dmi_kobj);
15
13/* 16/*
14 * DMI stands for "Desktop Management Interface". It is part 17 * DMI stands for "Desktop Management Interface". It is part
15 * of and an antecedent to, SMBIOS, which stands for System 18 * of and an antecedent to, SMBIOS, which stands for System
@@ -20,6 +23,9 @@ static const char dmi_empty_string[] = " ";
20static u32 dmi_ver __initdata; 23static u32 dmi_ver __initdata;
21static u32 dmi_len; 24static u32 dmi_len;
22static u16 dmi_num; 25static u16 dmi_num;
26static u8 smbios_entry_point[32];
27static int smbios_entry_point_size;
28
23/* 29/*
24 * Catch too early calls to dmi_check_system(): 30 * Catch too early calls to dmi_check_system():
25 */ 31 */
@@ -80,18 +86,18 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
80 * We have to be cautious here. We have seen BIOSes with DMI pointers 86 * We have to be cautious here. We have seen BIOSes with DMI pointers
81 * pointing to completely the wrong place for example 87 * pointing to completely the wrong place for example
82 */ 88 */
83static void dmi_table(u8 *buf, 89static void dmi_decode_table(u8 *buf,
84 void (*decode)(const struct dmi_header *, void *), 90 void (*decode)(const struct dmi_header *, void *),
85 void *private_data) 91 void *private_data)
86{ 92{
87 u8 *data = buf; 93 u8 *data = buf;
88 int i = 0; 94 int i = 0;
89 95
90 /* 96 /*
91 * Stop when we have seen all the items the table claimed to have 97 * Stop when we have seen all the items the table claimed to have
92 * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run 98 * (SMBIOS < 3.0 only) OR we reach an end-of-table marker (SMBIOS
93 * off the end of the table (should never happen but sometimes does 99 * >= 3.0 only) OR we run off the end of the table (should never
94 * on bogus implementations.) 100 * happen but sometimes does on bogus implementations.)
95 */ 101 */
96 while ((!dmi_num || i < dmi_num) && 102 while ((!dmi_num || i < dmi_num) &&
97 (data - buf + sizeof(struct dmi_header)) <= dmi_len) { 103 (data - buf + sizeof(struct dmi_header)) <= dmi_len) {
@@ -108,15 +114,24 @@ static void dmi_table(u8 *buf,
108 if (data - buf < dmi_len - 1) 114 if (data - buf < dmi_len - 1)
109 decode(dm, private_data); 115 decode(dm, private_data);
110 116
117 data += 2;
118 i++;
119
111 /* 120 /*
112 * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0] 121 * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
122 * For tables behind a 64-bit entry point, we have no item
123 * count and no exact table length, so stop on end-of-table
124 * marker. For tables behind a 32-bit entry point, we have
125 * seen OEM structures behind the end-of-table marker on
126 * some systems, so don't trust it.
113 */ 127 */
114 if (dm->type == DMI_ENTRY_END_OF_TABLE) 128 if (!dmi_num && dm->type == DMI_ENTRY_END_OF_TABLE)
115 break; 129 break;
116
117 data += 2;
118 i++;
119 } 130 }
131
132 /* Trim DMI table length if needed */
133 if (dmi_len > data - buf)
134 dmi_len = data - buf;
120} 135}
121 136
122static phys_addr_t dmi_base; 137static phys_addr_t dmi_base;
@@ -125,16 +140,17 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
125 void *)) 140 void *))
126{ 141{
127 u8 *buf; 142 u8 *buf;
143 u32 orig_dmi_len = dmi_len;
128 144
129 buf = dmi_early_remap(dmi_base, dmi_len); 145 buf = dmi_early_remap(dmi_base, orig_dmi_len);
130 if (buf == NULL) 146 if (buf == NULL)
131 return -1; 147 return -1;
132 148
133 dmi_table(buf, decode, NULL); 149 dmi_decode_table(buf, decode, NULL);
134 150
135 add_device_randomness(buf, dmi_len); 151 add_device_randomness(buf, dmi_len);
136 152
137 dmi_early_unmap(buf, dmi_len); 153 dmi_early_unmap(buf, orig_dmi_len);
138 return 0; 154 return 0;
139} 155}
140 156
@@ -478,17 +494,19 @@ static int __init dmi_present(const u8 *buf)
478 if (memcmp(buf, "_SM_", 4) == 0 && 494 if (memcmp(buf, "_SM_", 4) == 0 &&
479 buf[5] < 32 && dmi_checksum(buf, buf[5])) { 495 buf[5] < 32 && dmi_checksum(buf, buf[5])) {
480 smbios_ver = get_unaligned_be16(buf + 6); 496 smbios_ver = get_unaligned_be16(buf + 6);
497 smbios_entry_point_size = buf[5];
498 memcpy(smbios_entry_point, buf, smbios_entry_point_size);
481 499
482 /* Some BIOS report weird SMBIOS version, fix that up */ 500 /* Some BIOS report weird SMBIOS version, fix that up */
483 switch (smbios_ver) { 501 switch (smbios_ver) {
484 case 0x021F: 502 case 0x021F:
485 case 0x0221: 503 case 0x0221:
486 pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 504 pr_debug("SMBIOS version fixup (2.%d->2.%d)\n",
487 smbios_ver & 0xFF, 3); 505 smbios_ver & 0xFF, 3);
488 smbios_ver = 0x0203; 506 smbios_ver = 0x0203;
489 break; 507 break;
490 case 0x0233: 508 case 0x0233:
491 pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6); 509 pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", 51, 6);
492 smbios_ver = 0x0206; 510 smbios_ver = 0x0206;
493 break; 511 break;
494 } 512 }
@@ -512,6 +530,9 @@ static int __init dmi_present(const u8 *buf)
512 pr_info("SMBIOS %d.%d present.\n", 530 pr_info("SMBIOS %d.%d present.\n",
513 dmi_ver >> 8, dmi_ver & 0xFF); 531 dmi_ver >> 8, dmi_ver & 0xFF);
514 } else { 532 } else {
533 smbios_entry_point_size = 15;
534 memcpy(smbios_entry_point, buf,
535 smbios_entry_point_size);
515 pr_info("Legacy DMI %d.%d present.\n", 536 pr_info("Legacy DMI %d.%d present.\n",
516 dmi_ver >> 8, dmi_ver & 0xFF); 537 dmi_ver >> 8, dmi_ver & 0xFF);
517 } 538 }
@@ -533,11 +554,12 @@ static int __init dmi_smbios3_present(const u8 *buf)
533{ 554{
534 if (memcmp(buf, "_SM3_", 5) == 0 && 555 if (memcmp(buf, "_SM3_", 5) == 0 &&
535 buf[6] < 32 && dmi_checksum(buf, buf[6])) { 556 buf[6] < 32 && dmi_checksum(buf, buf[6])) {
536 dmi_ver = get_unaligned_be32(buf + 6); 557 dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF;
537 dmi_ver &= 0xFFFFFF;
538 dmi_num = 0; /* No longer specified */ 558 dmi_num = 0; /* No longer specified */
539 dmi_len = get_unaligned_le32(buf + 12); 559 dmi_len = get_unaligned_le32(buf + 12);
540 dmi_base = get_unaligned_le64(buf + 16); 560 dmi_base = get_unaligned_le64(buf + 16);
561 smbios_entry_point_size = buf[6];
562 memcpy(smbios_entry_point, buf, smbios_entry_point_size);
541 563
542 if (dmi_walk_early(dmi_decode) == 0) { 564 if (dmi_walk_early(dmi_decode) == 0) {
543 pr_info("SMBIOS %d.%d.%d present.\n", 565 pr_info("SMBIOS %d.%d.%d present.\n",
@@ -629,6 +651,71 @@ void __init dmi_scan_machine(void)
629 dmi_initialized = 1; 651 dmi_initialized = 1;
630} 652}
631 653
654static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
655 struct bin_attribute *attr, char *buf,
656 loff_t pos, size_t count)
657{
658 memcpy(buf, attr->private + pos, count);
659 return count;
660}
661
662static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
663static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);
664
665static int __init dmi_init(void)
666{
667 struct kobject *tables_kobj;
668 u8 *dmi_table;
669 int ret = -ENOMEM;
670
671 if (!dmi_available) {
672 ret = -ENODATA;
673 goto err;
674 }
675
676 /*
677 * Set up dmi directory at /sys/firmware/dmi. This entry should stay
678 * even after farther error, as it can be used by other modules like
679 * dmi-sysfs.
680 */
681 dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
682 if (!dmi_kobj)
683 goto err;
684
685 tables_kobj = kobject_create_and_add("tables", dmi_kobj);
686 if (!tables_kobj)
687 goto err;
688
689 dmi_table = dmi_remap(dmi_base, dmi_len);
690 if (!dmi_table)
691 goto err_tables;
692
693 bin_attr_smbios_entry_point.size = smbios_entry_point_size;
694 bin_attr_smbios_entry_point.private = smbios_entry_point;
695 ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
696 if (ret)
697 goto err_unmap;
698
699 bin_attr_DMI.size = dmi_len;
700 bin_attr_DMI.private = dmi_table;
701 ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
702 if (!ret)
703 return 0;
704
705 sysfs_remove_bin_file(tables_kobj,
706 &bin_attr_smbios_entry_point);
707 err_unmap:
708 dmi_unmap(dmi_table);
709 err_tables:
710 kobject_del(tables_kobj);
711 kobject_put(tables_kobj);
712 err:
713 pr_err("dmi: Firmware registration failed.\n");
714
715 return ret;
716}
717subsys_initcall(dmi_init);
718
632/** 719/**
633 * dmi_set_dump_stack_arch_desc - set arch description for dump_stack() 720 * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
634 * 721 *
@@ -897,7 +984,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
897 if (buf == NULL) 984 if (buf == NULL)
898 return -1; 985 return -1;
899 986
900 dmi_table(buf, decode, private_data); 987 dmi_decode_table(buf, decode, private_data);
901 988
902 dmi_unmap(buf); 989 dmi_unmap(buf);
903 return 0; 990 return 0;
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index f820f0a336c9..5055ac34142d 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -2,6 +2,7 @@
2#define __DMI_H__ 2#define __DMI_H__
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <linux/kobject.h>
5#include <linux/mod_devicetable.h> 6#include <linux/mod_devicetable.h>
6 7
7/* enum dmi_field is in mod_devicetable.h */ 8/* enum dmi_field is in mod_devicetable.h */
@@ -74,7 +75,7 @@ struct dmi_header {
74 u8 type; 75 u8 type;
75 u8 length; 76 u8 length;
76 u16 handle; 77 u16 handle;
77}; 78} __packed;
78 79
79struct dmi_device { 80struct dmi_device {
80 struct list_head list; 81 struct list_head list;
@@ -93,6 +94,7 @@ struct dmi_dev_onboard {
93 int devfn; 94 int devfn;
94}; 95};
95 96
97extern struct kobject *dmi_kobj;
96extern int dmi_check_system(const struct dmi_system_id *list); 98extern int dmi_check_system(const struct dmi_system_id *list);
97const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); 99const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
98extern const char * dmi_get_system_info(int field); 100extern const char * dmi_get_system_info(int field);