aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/dmi_scan.c
diff options
context:
space:
mode:
authorIvan Khoronzhuk <ivan.khoronzhuk@globallogic.com>2015-06-25 03:06:56 -0400
committerJean Delvare <jdelvare@suse.de>2015-06-25 03:06:56 -0400
commitd7f96f97c4031fa4ffdb7801f9aae23e96170a6f (patch)
tree0fd0894bbaa8714105bc33e7bd36f15599455945 /drivers/firmware/dmi_scan.c
parent6e0ad59e3d838a2887e7aa657baee5896030d009 (diff)
firmware: dmi_scan: add SBMIOS entry and DMI tables
Some utils, like dmidecode and smbios, need to access SMBIOS entry table area in order to get information like SMBIOS version, size, etc. Currently it's done via /dev/mem. But for situation when /dev/mem usage is disabled, the utils have to use dmi sysfs instead, which doesn't represent SMBIOS entry and adds code/delay redundancy when direct access for table is needed. So this patch creates dmi/tables and adds SMBIOS entry point to allow utils in question to work correctly without /dev/mem. Also patch adds raw dmi table to simplify dmi table processing in user space, as proposed by Jean Delvare. Tested-by: Roy Franz <roy.franz@linaro.org> Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com> Signed-off-by: Jean Delvare <jdelvare@suse.de>
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
-rw-r--r--drivers/firmware/dmi_scan.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 7fdf2868a276..5e0b770fdae5 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 */
@@ -488,6 +494,8 @@ static int __init dmi_present(const u8 *buf)
488 if (memcmp(buf, "_SM_", 4) == 0 && 494 if (memcmp(buf, "_SM_", 4) == 0 &&
489 buf[5] < 32 && dmi_checksum(buf, buf[5])) { 495 buf[5] < 32 && dmi_checksum(buf, buf[5])) {
490 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);
491 499
492 /* Some BIOS report weird SMBIOS version, fix that up */ 500 /* Some BIOS report weird SMBIOS version, fix that up */
493 switch (smbios_ver) { 501 switch (smbios_ver) {
@@ -522,6 +530,9 @@ static int __init dmi_present(const u8 *buf)
522 pr_info("SMBIOS %d.%d present.\n", 530 pr_info("SMBIOS %d.%d present.\n",
523 dmi_ver >> 8, dmi_ver & 0xFF); 531 dmi_ver >> 8, dmi_ver & 0xFF);
524 } else { 532 } else {
533 smbios_entry_point_size = 15;
534 memcpy(smbios_entry_point, buf,
535 smbios_entry_point_size);
525 pr_info("Legacy DMI %d.%d present.\n", 536 pr_info("Legacy DMI %d.%d present.\n",
526 dmi_ver >> 8, dmi_ver & 0xFF); 537 dmi_ver >> 8, dmi_ver & 0xFF);
527 } 538 }
@@ -548,6 +559,8 @@ static int __init dmi_smbios3_present(const u8 *buf)
548 dmi_num = 0; /* No longer specified */ 559 dmi_num = 0; /* No longer specified */
549 dmi_len = get_unaligned_le32(buf + 12); 560 dmi_len = get_unaligned_le32(buf + 12);
550 dmi_base = get_unaligned_le64(buf + 16); 561 dmi_base = get_unaligned_le64(buf + 16);
562 smbios_entry_point_size = buf[6];
563 memcpy(smbios_entry_point, buf, smbios_entry_point_size);
551 564
552 if (dmi_walk_early(dmi_decode) == 0) { 565 if (dmi_walk_early(dmi_decode) == 0) {
553 pr_info("SMBIOS %d.%d.%d present.\n", 566 pr_info("SMBIOS %d.%d.%d present.\n",
@@ -639,6 +652,71 @@ void __init dmi_scan_machine(void)
639 dmi_initialized = 1; 652 dmi_initialized = 1;
640} 653}
641 654
655static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
656 struct bin_attribute *attr, char *buf,
657 loff_t pos, size_t count)
658{
659 memcpy(buf, attr->private + pos, count);
660 return count;
661}
662
663static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
664static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);
665
666static int __init dmi_init(void)
667{
668 struct kobject *tables_kobj;
669 u8 *dmi_table;
670 int ret = -ENOMEM;
671
672 if (!dmi_available) {
673 ret = -ENODATA;
674 goto err;
675 }
676
677 /*
678 * Set up dmi directory at /sys/firmware/dmi. This entry should stay
679 * even after farther error, as it can be used by other modules like
680 * dmi-sysfs.
681 */
682 dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
683 if (!dmi_kobj)
684 goto err;
685
686 tables_kobj = kobject_create_and_add("tables", dmi_kobj);
687 if (!tables_kobj)
688 goto err;
689
690 dmi_table = dmi_remap(dmi_base, dmi_len);
691 if (!dmi_table)
692 goto err_tables;
693
694 bin_attr_smbios_entry_point.size = smbios_entry_point_size;
695 bin_attr_smbios_entry_point.private = smbios_entry_point;
696 ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
697 if (ret)
698 goto err_unmap;
699
700 bin_attr_DMI.size = dmi_len;
701 bin_attr_DMI.private = dmi_table;
702 ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
703 if (!ret)
704 return 0;
705
706 sysfs_remove_bin_file(tables_kobj,
707 &bin_attr_smbios_entry_point);
708 err_unmap:
709 dmi_unmap(dmi_table);
710 err_tables:
711 kobject_del(tables_kobj);
712 kobject_put(tables_kobj);
713 err:
714 pr_err("dmi: Firmware registration failed.\n");
715
716 return ret;
717}
718subsys_initcall(dmi_init);
719
642/** 720/**
643 * dmi_set_dump_stack_arch_desc - set arch description for dump_stack() 721 * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
644 * 722 *