aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;