diff options
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
-rw-r--r-- | drivers/firmware/dmi_scan.c | 78 |
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 | ||
13 | struct kobject *dmi_kobj; | ||
14 | EXPORT_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[] = " "; | |||
20 | static u32 dmi_ver __initdata; | 23 | static u32 dmi_ver __initdata; |
21 | static u32 dmi_len; | 24 | static u32 dmi_len; |
22 | static u16 dmi_num; | 25 | static u16 dmi_num; |
26 | static u8 smbios_entry_point[32]; | ||
27 | static 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 | ||
655 | static 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 | |||
663 | static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0); | ||
664 | static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0); | ||
665 | |||
666 | static 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 | } | ||
718 | subsys_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 | * |