aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/dmi-sysfs.c
diff options
context:
space:
mode:
authorMike Waychison <mikew@google.com>2011-02-22 20:53:31 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-25 15:02:34 -0500
commita3857a5c9893aa69d44be6e881927b0950b1d931 (patch)
tree4ffadf0c16167fecfc66b3a096a19cab48e27c0d /drivers/firmware/dmi-sysfs.c
parent925a1da7477fc4ba5849c6f0243934fa5072493c (diff)
firmware: Expose DMI type 15 System Event Log
The System Event Log described by DMI entry type 15 may be backed by either memory or may be indirectly accessed via an IO index/data register pair. In order to get read access to this log, expose it in the "system_event_log" sub-directory of type 15 DMI entries, ie: /sys/firmware/dmi/entries/15-0/system_event_log/raw_event_log. This commit handles both IO accessed and memory access system event logs. OEM specific access and GPNV support is explicitly not handled and we error out in the logs when we do not recognize the access method. Signed-off-by: Mike Waychison <mikew@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/firmware/dmi-sysfs.c')
-rw-r--r--drivers/firmware/dmi-sysfs.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
index d20961011039..a5afd805e66f 100644
--- a/drivers/firmware/dmi-sysfs.c
+++ b/drivers/firmware/dmi-sysfs.c
@@ -312,6 +312,140 @@ static struct kobj_type dmi_system_event_log_ktype = {
312 .default_attrs = dmi_sysfs_sel_attrs, 312 .default_attrs = dmi_sysfs_sel_attrs,
313}; 313};
314 314
315typedef u8 (*sel_io_reader)(const struct dmi_system_event_log *sel,
316 loff_t offset);
317
318static DEFINE_MUTEX(io_port_lock);
319
320static u8 read_sel_8bit_indexed_io(const struct dmi_system_event_log *sel,
321 loff_t offset)
322{
323 u8 ret;
324
325 mutex_lock(&io_port_lock);
326 outb((u8)offset, sel->io.index_addr);
327 ret = inb(sel->io.data_addr);
328 mutex_unlock(&io_port_lock);
329 return ret;
330}
331
332static u8 read_sel_2x8bit_indexed_io(const struct dmi_system_event_log *sel,
333 loff_t offset)
334{
335 u8 ret;
336
337 mutex_lock(&io_port_lock);
338 outb((u8)offset, sel->io.index_addr);
339 outb((u8)(offset >> 8), sel->io.index_addr + 1);
340 ret = inb(sel->io.data_addr);
341 mutex_unlock(&io_port_lock);
342 return ret;
343}
344
345static u8 read_sel_16bit_indexed_io(const struct dmi_system_event_log *sel,
346 loff_t offset)
347{
348 u8 ret;
349
350 mutex_lock(&io_port_lock);
351 outw((u16)offset, sel->io.index_addr);
352 ret = inb(sel->io.data_addr);
353 mutex_unlock(&io_port_lock);
354 return ret;
355}
356
357static sel_io_reader sel_io_readers[] = {
358 [DMI_SEL_ACCESS_METHOD_IO8] = read_sel_8bit_indexed_io,
359 [DMI_SEL_ACCESS_METHOD_IO2x8] = read_sel_2x8bit_indexed_io,
360 [DMI_SEL_ACCESS_METHOD_IO16] = read_sel_16bit_indexed_io,
361};
362
363static ssize_t dmi_sel_raw_read_io(struct dmi_sysfs_entry *entry,
364 const struct dmi_system_event_log *sel,
365 char *buf, loff_t pos, size_t count)
366{
367 ssize_t wrote = 0;
368
369 sel_io_reader io_reader = sel_io_readers[sel->access_method];
370
371 while (count && pos < sel->area_length) {
372 count--;
373 *(buf++) = io_reader(sel, pos++);
374 wrote++;
375 }
376
377 return wrote;
378}
379
380static ssize_t dmi_sel_raw_read_phys32(struct dmi_sysfs_entry *entry,
381 const struct dmi_system_event_log *sel,
382 char *buf, loff_t pos, size_t count)
383{
384 u8 __iomem *mapped;
385 ssize_t wrote = 0;
386
387 mapped = ioremap(sel->access_method_address, sel->area_length);
388 if (!mapped)
389 return -EIO;
390
391 while (count && pos < sel->area_length) {
392 count--;
393 *(buf++) = readb(mapped + pos++);
394 wrote++;
395 }
396
397 iounmap(mapped);
398 return wrote;
399}
400
401static ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry,
402 const struct dmi_header *dh,
403 void *_state)
404{
405 struct dmi_read_state *state = _state;
406 const struct dmi_system_event_log *sel = to_sel(dh);
407
408 if (sizeof(*sel) > dmi_entry_length(dh))
409 return -EIO;
410
411 switch (sel->access_method) {
412 case DMI_SEL_ACCESS_METHOD_IO8:
413 case DMI_SEL_ACCESS_METHOD_IO2x8:
414 case DMI_SEL_ACCESS_METHOD_IO16:
415 return dmi_sel_raw_read_io(entry, sel, state->buf,
416 state->pos, state->count);
417 case DMI_SEL_ACCESS_METHOD_PHYS32:
418 return dmi_sel_raw_read_phys32(entry, sel, state->buf,
419 state->pos, state->count);
420 case DMI_SEL_ACCESS_METHOD_GPNV:
421 pr_info("dmi-sysfs: GPNV support missing.\n");
422 return -EIO;
423 default:
424 pr_info("dmi-sysfs: Unknown access method %02x\n",
425 sel->access_method);
426 return -EIO;
427 }
428}
429
430static ssize_t dmi_sel_raw_read(struct file *filp, struct kobject *kobj,
431 struct bin_attribute *bin_attr,
432 char *buf, loff_t pos, size_t count)
433{
434 struct dmi_sysfs_entry *entry = to_entry(kobj->parent);
435 struct dmi_read_state state = {
436 .buf = buf,
437 .pos = pos,
438 .count = count,
439 };
440
441 return find_dmi_entry(entry, dmi_sel_raw_read_helper, &state);
442}
443
444static struct bin_attribute dmi_sel_raw_attr = {
445 .attr = {.name = "raw_event_log", .mode = 0400},
446 .read = dmi_sel_raw_read,
447};
448
315static int dmi_system_event_log(struct dmi_sysfs_entry *entry) 449static int dmi_system_event_log(struct dmi_sysfs_entry *entry)
316{ 450{
317 int ret; 451 int ret;
@@ -325,6 +459,15 @@ static int dmi_system_event_log(struct dmi_sysfs_entry *entry)
325 "system_event_log"); 459 "system_event_log");
326 if (ret) 460 if (ret)
327 goto out_free; 461 goto out_free;
462
463 ret = sysfs_create_bin_file(entry->child, &dmi_sel_raw_attr);
464 if (ret)
465 goto out_del;
466
467 return 0;
468
469out_del:
470 kobject_del(entry->child);
328out_free: 471out_free:
329 kfree(entry->child); 472 kfree(entry->child);
330 return ret; 473 return ret;