aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorMike Waychison <mikew@google.com>2011-02-22 20:53:21 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-25 15:01:19 -0500
commit948af1f0bbc8526448e8cbe3f8d3bf211bdf5181 (patch)
tree6ecf0035c6466002d3ae32b4ab5230f5abb567eb /drivers/firmware
parent93c890dbe5287d146007083021148e7318058e37 (diff)
firmware: Basic dmi-sysfs support
Introduce a new module "dmi-sysfs" that exports the broken out entries of the DMI table through sysfs. Entries are enumerated via dmi_walk() on module load, and are populated as kobjects rooted at /sys/firmware/dmi/entries. Entries are named "<type>-<instance>", where: <type> : is the type of the entry, and <instance> : is the ordinal count within the DMI table of that entry type. This instance is used in lieu the DMI entry's handle as no assurances are made by the kernel that handles are unique. All entries export the following attributes: length : The length of the formatted portion of the entry handle : The handle given to this entry by the firmware raw : The raw bytes of the entire entry, including the formatted portion, the unformatted (strings) portion, and the two terminating nul characters. type : The DMI entry type instance : The ordinal instance of this entry given its type. position : The position ordinal of the entry within the table in its entirety. Entries in dmi-sysfs are kobject backed members called "struct dmi_sysfs_entry" and belong to dmi_kset. They are threaded through entry_list (protected by entry_list_lock) so that we can find them at cleanup time. Signed-off-by: Mike Waychison <mikew@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig11
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/dmi-sysfs.c396
3 files changed, 408 insertions, 0 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index e710424b59ea..3c56afc5eb1b 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -113,6 +113,17 @@ config DMIID
113 information from userspace through /sys/class/dmi/id/ or if you want 113 information from userspace through /sys/class/dmi/id/ or if you want
114 DMI-based module auto-loading. 114 DMI-based module auto-loading.
115 115
116config DMI_SYSFS
117 tristate "DMI table support in sysfs"
118 depends on SYSFS && DMI
119 default n
120 help
121 Say Y or M here to enable the exporting of the raw DMI table
122 data via sysfs. This is useful for consuming the data without
123 requiring any access to /dev/mem at all. Tables are found
124 under /sys/firmware/dmi when this option is enabled and
125 loaded.
126
116config ISCSI_IBFT_FIND 127config ISCSI_IBFT_FIND
117 bool "iSCSI Boot Firmware Table Attributes" 128 bool "iSCSI Boot Firmware Table Attributes"
118 depends on X86 129 depends on X86
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 1c3c17343dbe..20c17fca1232 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -2,6 +2,7 @@
2# Makefile for the linux kernel. 2# Makefile for the linux kernel.
3# 3#
4obj-$(CONFIG_DMI) += dmi_scan.o 4obj-$(CONFIG_DMI) += dmi_scan.o
5obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
5obj-$(CONFIG_EDD) += edd.o 6obj-$(CONFIG_EDD) += edd.o
6obj-$(CONFIG_EFI_VARS) += efivars.o 7obj-$(CONFIG_EFI_VARS) += efivars.o
7obj-$(CONFIG_EFI_PCDP) += pcdp.o 8obj-$(CONFIG_EFI_PCDP) += pcdp.o
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
new file mode 100644
index 000000000000..2d8a04a95085
--- /dev/null
+++ b/drivers/firmware/dmi-sysfs.c
@@ -0,0 +1,396 @@
1/*
2 * dmi-sysfs.c
3 *
4 * This module exports the DMI tables read-only to userspace through the
5 * sysfs file system.
6 *
7 * Data is currently found below
8 * /sys/firmware/dmi/...
9 *
10 * DMI attributes are presented in attribute files with names
11 * formatted using %d-%d, so that the first integer indicates the
12 * structure type (0-255), and the second field is the instance of that
13 * entry.
14 *
15 * Copyright 2011 Google, Inc.
16 */
17
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/kobject.h>
23#include <linux/dmi.h>
24#include <linux/capability.h>
25#include <linux/slab.h>
26#include <linux/list.h>
27#include <linux/io.h>
28
29#define MAX_ENTRY_TYPE 255 /* Most of these aren't used, but we consider
30 the top entry type is only 8 bits */
31
32struct dmi_sysfs_entry {
33 struct dmi_header dh;
34 struct kobject kobj;
35 int instance;
36 int position;
37 struct list_head list;
38};
39
40/*
41 * Global list of dmi_sysfs_entry. Even though this should only be
42 * manipulated at setup and teardown, the lazy nature of the kobject
43 * system means we get lazy removes.
44 */
45static LIST_HEAD(entry_list);
46static DEFINE_SPINLOCK(entry_list_lock);
47
48/* dmi_sysfs_attribute - Top level attribute. used by all entries. */
49struct dmi_sysfs_attribute {
50 struct attribute attr;
51 ssize_t (*show)(struct dmi_sysfs_entry *entry, char *buf);
52};
53
54#define DMI_SYSFS_ATTR(_entry, _name) \
55struct dmi_sysfs_attribute dmi_sysfs_attr_##_entry##_##_name = { \
56 .attr = {.name = __stringify(_name), .mode = 0400}, \
57 .show = dmi_sysfs_##_entry##_##_name, \
58}
59
60/*
61 * dmi_sysfs_mapped_attribute - Attribute where we require the entry be
62 * mapped in. Use in conjunction with dmi_sysfs_specialize_attr_ops.
63 */
64struct dmi_sysfs_mapped_attribute {
65 struct attribute attr;
66 ssize_t (*show)(struct dmi_sysfs_entry *entry,
67 const struct dmi_header *dh,
68 char *buf);
69};
70
71#define DMI_SYSFS_MAPPED_ATTR(_entry, _name) \
72struct dmi_sysfs_mapped_attribute dmi_sysfs_attr_##_entry##_##_name = { \
73 .attr = {.name = __stringify(_name), .mode = 0400}, \
74 .show = dmi_sysfs_##_entry##_##_name, \
75}
76
77/*************************************************
78 * Generic DMI entry support.
79 *************************************************/
80
81static struct dmi_sysfs_entry *to_entry(struct kobject *kobj)
82{
83 return container_of(kobj, struct dmi_sysfs_entry, kobj);
84}
85
86static struct dmi_sysfs_attribute *to_attr(struct attribute *attr)
87{
88 return container_of(attr, struct dmi_sysfs_attribute, attr);
89}
90
91static ssize_t dmi_sysfs_attr_show(struct kobject *kobj,
92 struct attribute *_attr, char *buf)
93{
94 struct dmi_sysfs_entry *entry = to_entry(kobj);
95 struct dmi_sysfs_attribute *attr = to_attr(_attr);
96
97 /* DMI stuff is only ever admin visible */
98 if (!capable(CAP_SYS_ADMIN))
99 return -EACCES;
100
101 return attr->show(entry, buf);
102}
103
104static const struct sysfs_ops dmi_sysfs_attr_ops = {
105 .show = dmi_sysfs_attr_show,
106};
107
108typedef ssize_t (*dmi_callback)(struct dmi_sysfs_entry *,
109 const struct dmi_header *dh, void *);
110
111struct find_dmi_data {
112 struct dmi_sysfs_entry *entry;
113 dmi_callback callback;
114 void *private;
115 int instance_countdown;
116 ssize_t ret;
117};
118
119static void find_dmi_entry_helper(const struct dmi_header *dh,
120 void *_data)
121{
122 struct find_dmi_data *data = _data;
123 struct dmi_sysfs_entry *entry = data->entry;
124
125 /* Is this the entry we want? */
126 if (dh->type != entry->dh.type)
127 return;
128
129 if (data->instance_countdown != 0) {
130 /* try the next instance? */
131 data->instance_countdown--;
132 return;
133 }
134
135 /*
136 * Don't ever revisit the instance. Short circuit later
137 * instances by letting the instance_countdown run negative
138 */
139 data->instance_countdown--;
140
141 /* Found the entry */
142 data->ret = data->callback(entry, dh, data->private);
143}
144
145/* State for passing the read parameters through dmi_find_entry() */
146struct dmi_read_state {
147 char *buf;
148 loff_t pos;
149 size_t count;
150};
151
152static ssize_t find_dmi_entry(struct dmi_sysfs_entry *entry,
153 dmi_callback callback, void *private)