aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Waychison <mikew@google.com>2011-02-22 20:53:26 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-25 15:02:13 -0500
commit925a1da7477fc4ba5849c6f0243934fa5072493c (patch)
tree969e9b156cc5a027de3f44c2936d140857eb39a6
parent948af1f0bbc8526448e8cbe3f8d3bf211bdf5181 (diff)
firmware: Break out system_event_log in dmi-sysfs
The optional type 15 entry of the DMI table describes a non-volatile storage-backed system event log. In preparation for the next commit which exposes the raw bits of the event log to userland, create a new sub-directory within the dmi entry called "system_event_log" and expose attribute files that describe the event log itself. Currently, only a single child object is permitted within a dmi_sysfs_entry. We simply point at this child from the dmi_sysfs_entry if it exists. Signed-off-by: Mike Waychison <mikew@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/firmware/dmi-sysfs.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
index 2d8a04a95085..d20961011039 100644
--- a/drivers/firmware/dmi-sysfs.c
+++ b/drivers/firmware/dmi-sysfs.c
@@ -35,6 +35,7 @@ struct dmi_sysfs_entry {
35 int instance; 35 int instance;
36 int position; 36 int position;
37 struct list_head list; 37 struct list_head list;
38 struct kobject *child;
38}; 39};
39 40
40/* 41/*
@@ -77,6 +78,10 @@ struct dmi_sysfs_mapped_attribute dmi_sysfs_attr_##_entry##_##_name = { \
77/************************************************* 78/*************************************************
78 * Generic DMI entry support. 79 * Generic DMI entry support.
79 *************************************************/ 80 *************************************************/
81static void dmi_entry_free(struct kobject *kobj)
82{
83 kfree(kobj);
84}
80 85
81static struct dmi_sysfs_entry *to_entry(struct kobject *kobj) 86static struct dmi_sysfs_entry *to_entry(struct kobject *kobj)
82{ 87{
@@ -186,6 +191,146 @@ static size_t dmi_entry_length(const struct dmi_header *dh)
186} 191}
187 192
188/************************************************* 193/*************************************************
194 * Support bits for specialized DMI entry support
195 *************************************************/
196struct dmi_entry_attr_show_data {
197 struct attribute *attr;
198 char *buf;
199};
200
201static ssize_t dmi_entry_attr_show_helper(struct dmi_sysfs_entry *entry,
202 const struct dmi_header *dh,
203 void *_data)
204{
205 struct dmi_entry_attr_show_data *data = _data;
206 struct dmi_sysfs_mapped_attribute *attr;
207
208 attr = container_of(data->attr,
209 struct dmi_sysfs_mapped_attribute, attr);
210 return attr->show(entry, dh, data->buf);
211}
212
213static ssize_t dmi_entry_attr_show(struct kobject *kobj,
214 struct attribute *attr,
215 char *buf)
216{
217 struct dmi_entry_attr_show_data data = {
218 .attr = attr,
219 .buf = buf,
220 };
221 /* Find the entry according to our parent and call the
222 * normalized show method hanging off of the attribute */
223 return find_dmi_entry(to_entry(kobj->parent),
224 dmi_entry_attr_show_helper, &data);
225}
226
227static const struct sysfs_ops dmi_sysfs_specialize_attr_ops = {
228 .show = dmi_entry_attr_show,
229};
230
231/*************************************************
232 * Specialized DMI entry support.
233 *************************************************/
234
235/*** Type 15 - System Event Table ***/
236
237#define DMI_SEL_ACCESS_METHOD_IO8 0x00
238#define DMI_SEL_ACCESS_METHOD_IO2x8 0x01
239#define DMI_SEL_ACCESS_METHOD_IO16 0x02
240#define DMI_SEL_ACCESS_METHOD_PHYS32 0x03
241#define DMI_SEL_ACCESS_METHOD_GPNV 0x04
242
243struct dmi_system_event_log {
244 struct dmi_header header;
245 u16 area_length;
246 u16 header_start_offset;
247 u16 data_start_offset;
248 u8 access_method;
249 u8 status;
250 u32 change_token;
251 union {
252 struct {
253 u16 index_addr;
254 u16 data_addr;
255 } io;
256 u32 phys_addr32;
257 u16 gpnv_handle;
258 u32 access_method_address;
259 };
260 u8 header_format;
261 u8 type_descriptors_supported_count;
262 u8 per_log_type_descriptor_length;
263 u8 supported_log_type_descriptos[0];
264} __packed;
265
266static const struct dmi_system_event_log *to_sel(const struct dmi_header *dh)
267{
268 return (const struct dmi_system_event_log *)dh;
269}
270
271#define DMI_SYSFS_SEL_FIELD(_field) \
272static ssize_t dmi_sysfs_sel_##_field(struct dmi_sysfs_entry *entry, \
273 const struct dmi_header *dh, \
274 char *buf) \
275{ \
276 const struct dmi_system_event_log *sel = to_sel(dh); \
277 if (sizeof(*sel) > dmi_entry_length(dh)) \
278 return -EIO; \
279 return sprintf(buf, "%u\n", sel->_field); \
280} \
281static DMI_SYSFS_MAPPED_ATTR(sel, _field)
282
283DMI_SYSFS_SEL_FIELD(area_length);
284DMI_SYSFS_SEL_FIELD(header_start_offset);
285DMI_SYSFS_SEL_FIELD(data_start_offset);
286DMI_SYSFS_SEL_FIELD(access_method);
287DMI_SYSFS_SEL_FIELD(status);
288DMI_SYSFS_SEL_FIELD(change_token);
289DMI_SYSFS_SEL_FIELD(access_method_address);
290DMI_SYSFS_SEL_FIELD(header_format);
291DMI_SYSFS_SEL_FIELD(type_descriptors_supported_count);
292DMI_SYSFS_SEL_FIELD(per_log_type_descriptor_length);
293
294static struct attribute *dmi_sysfs_sel_attrs[] = {
295 &dmi_sysfs_attr_sel_area_length.attr,
296 &dmi_sysfs_attr_sel_header_start_offset.attr,
297 &dmi_sysfs_attr_sel_data_start_offset.attr,
298 &dmi_sysfs_attr_sel_access_method.attr,
299 &dmi_sysfs_attr_sel_status.attr,
300 &dmi_sysfs_attr_sel_change_token.attr,
301 &dmi_sysfs_attr_sel_access_method_address.attr,
302 &dmi_sysfs_attr_sel_header_format.attr,
303 &dmi_sysfs_attr_sel_type_descriptors_supported_count.attr,
304 &dmi_sysfs_attr_sel_per_log_type_descriptor_length.attr,
305 NULL,
306};
307
308
309static struct kobj_type dmi_system_event_log_ktype = {
310 .release = dmi_entry_free,
311 .sysfs_ops = &dmi_sysfs_specialize_attr_ops,
312 .default_attrs = dmi_sysfs_sel_attrs,
313};
314
315static int dmi_system_event_log(struct dmi_sysfs_entry *entry)
316{
317 int ret;
318
319 entry->child = kzalloc(sizeof(*entry->child), GFP_KERNEL);
320 if (!entry->child)
321 return -ENOMEM;
322 ret = kobject_init_and_add(entry->child,
323 &dmi_system_event_log_ktype,
324 &entry->kobj,
325 "system_event_log");
326 if (ret)
327 goto out_free;
328out_free:
329 kfree(entry->child);
330 return ret;
331}
332
333/*************************************************
189 * Generic DMI entry support. 334 * Generic DMI entry support.
190 *************************************************/ 335 *************************************************/
191 336
@@ -325,6 +470,18 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh,
325 list_add_tail(&entry->list, &entry_list); 470 list_add_tail(&entry->list, &entry_list);
326 spin_unlock(&entry_list_lock); 471 spin_unlock(&entry_list_lock);
327 472
473 /* Handle specializations by type */
474 switch (dh->type) {
475 case DMI_ENTRY_SYSTEM_EVENT_LOG:
476 *ret = dmi_system_event_log(entry);
477 break;
478 default:
479 /* No specialization */
480 break;
481 }
482 if (*ret)
483 goto out_err;
484
328 /* Create the raw binary file to access the entry */ 485 /* Create the raw binary file to access the entry */
329 *ret = sysfs_create_bin_file(&entry->kobj, &dmi_entry_raw_attr); 486 *ret = sysfs_create_bin_file(&entry->kobj, &dmi_entry_raw_attr);
330 if (*ret) 487 if (*ret)
@@ -332,6 +489,7 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh,
332 489
333 return; 490 return;
334out_err: 491out_err:
492 kobject_put(entry->child);
335 kobject_put(&entry->kobj); 493 kobject_put(&entry->kobj);
336 return; 494 return;
337} 495}
@@ -342,6 +500,7 @@ static void cleanup_entry_list(void)
342 500
343 /* No locks, we are on our way out */ 501 /* No locks, we are on our way out */
344 list_for_each_entry_safe(entry, next, &entry_list, list) { 502 list_for_each_entry_safe(entry, next, &entry_list, list) {
503 kobject_put(entry->child);
345 kobject_put(&entry->kobj); 504 kobject_put(&entry->kobj);
346 } 505 }
347} 506}