aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-05-25 23:28:08 -0400
committerLen Brown <len.brown@intel.com>2010-05-27 12:46:20 -0400
commitdce80a56268fffd6b5ea57b3f6ba3d027a68f05e (patch)
tree387349e5e6ee31dbe26c57ac0bf5d223af4ef838
parent5487ab4a5a71e955fef7094a0624df0542da91ef (diff)
SFI: add sysfs interface for SFI tables.
Analogous to ACPI's /sys/firmware/acpi/tables/... create /sys/firmware/sfi/tables/ The tables are primariy for the kernel, but sometimes it is useful for user-space to be able to read them. Signed-off-by: Feng Tang <feng.tang@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-sfi15
-rw-r--r--drivers/sfi/sfi_acpi.c41
-rw-r--r--drivers/sfi/sfi_core.c103
-rw-r--r--drivers/sfi/sfi_core.h8
4 files changed, 167 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-sfi b/Documentation/ABI/testing/sysfs-firmware-sfi
new file mode 100644
index 000000000000..4be7d44aeacf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-sfi
@@ -0,0 +1,15 @@
1What: /sys/firmware/sfi/tables/
2Date: May 2010
3Contact: Len Brown <lenb@kernel.org>
4Description:
5 SFI defines a number of small static memory tables
6 so the kernel can get platform information from firmware.
7
8 The tables are defined in the latest SFI specification:
9 http://simplefirmware.org/documentation
10
11 While the tables are used by the kernel, user-space
12 can observe them this way:
13
14 # cd /sys/firmware/sfi/tables
15 # cat $TABLENAME > $TABLENAME.bin
diff --git a/drivers/sfi/sfi_acpi.c b/drivers/sfi/sfi_acpi.c
index 34aba30eb84b..f5b4ca581541 100644
--- a/drivers/sfi/sfi_acpi.c
+++ b/drivers/sfi/sfi_acpi.c
@@ -173,3 +173,44 @@ int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
173 sfi_acpi_put_table(table); 173 sfi_acpi_put_table(table);
174 return ret; 174 return ret;
175} 175}
176
177static ssize_t sfi_acpi_table_show(struct file *filp, struct kobject *kobj,
178 struct bin_attribute *bin_attr, char *buf,
179 loff_t offset, size_t count)
180{
181 struct sfi_table_attr *tbl_attr =
182 container_of(bin_attr, struct sfi_table_attr, attr);
183 struct acpi_table_header *th = NULL;
184 struct sfi_table_key key;
185 ssize_t cnt;
186
187 key.sig = tbl_attr->name;
188 key.oem_id = NULL;
189 key.oem_table_id = NULL;
190
191 th = sfi_acpi_get_table(&key);
192 if (!th)
193 return 0;
194
195 cnt = memory_read_from_buffer(buf, count, &offset,
196 th, th->length);
197 sfi_acpi_put_table(th);
198
199 return cnt;
200}
201
202
203void __init sfi_acpi_sysfs_init(void)
204{
205 u32 tbl_cnt, i;
206 struct sfi_table_attr *tbl_attr;
207
208 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
209 for (i = 0; i < tbl_cnt; i++) {
210 tbl_attr =
211 sfi_sysfs_install_table(xsdt_va->table_offset_entry[i]);
212 tbl_attr->attr.read = sfi_acpi_table_show;
213 }
214
215 return;
216}
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index aba6a461365b..005195958647 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -67,6 +67,7 @@
67#include <linux/acpi.h> 67#include <linux/acpi.h>
68#include <linux/init.h> 68#include <linux/init.h>
69#include <linux/sfi.h> 69#include <linux/sfi.h>
70#include <linux/slab.h>
70 71
71#include "sfi_core.h" 72#include "sfi_core.h"
72 73
@@ -382,6 +383,102 @@ static __init int sfi_find_syst(void)
382 return -1; 383 return -1;
383} 384}
384 385
386static struct kobject *sfi_kobj;
387static struct kobject *tables_kobj;
388
389static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
390 struct bin_attribute *bin_attr, char *buf,
391 loff_t offset, size_t count)
392{
393 struct sfi_table_attr *tbl_attr =
394 container_of(bin_attr, struct sfi_table_attr, attr);
395 struct sfi_table_header *th = NULL;
396 struct sfi_table_key key;
397 ssize_t cnt;
398
399 key.sig = tbl_attr->name;
400 key.oem_id = NULL;
401 key.oem_table_id = NULL;
402
403 if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
404 th = sfi_get_table(&key);
405 if (!th)
406 return 0;
407
408 cnt = memory_read_from_buffer(buf, count, &offset,
409 th, th->len);
410 sfi_put_table(th);
411 } else
412 cnt = memory_read_from_buffer(buf, count, &offset,
413 syst_va, syst_va->header.len);
414
415 return cnt;
416}
417
418struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
419{
420 struct sfi_table_attr *tbl_attr;
421 struct sfi_table_header *th;
422 int ret;
423
424 tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
425 if (!tbl_attr)
426 return NULL;
427
428 th = sfi_map_table(pa);
429 if (!th || !th->sig[0]) {
430 kfree(tbl_attr);
431 return NULL;
432 }
433
434 sysfs_attr_init(&tbl_attr->attr.attr);
435 memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
436
437 tbl_attr->attr.size = 0;
438 tbl_attr->attr.read = sfi_table_show;
439 tbl_attr->attr.attr.name = tbl_attr->name;
440 tbl_attr->attr.attr.mode = 0400;
441
442 ret = sysfs_create_bin_file(tables_kobj,
443 &tbl_attr->attr);
444 if (ret)
445 kfree(tbl_attr);
446
447 sfi_unmap_table(th);
448 return tbl_attr;
449}
450
451static int __init sfi_sysfs_init(void)
452{
453 int tbl_cnt, i;
454
455 if (sfi_disabled)
456 return 0;
457
458 sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
459 if (!sfi_kobj)
460 return 0;
461
462 tables_kobj = kobject_create_and_add("tables", sfi_kobj);
463 if (!tables_kobj) {
464 kobject_put(sfi_kobj);
465 return 0;
466 }
467
468 sfi_sysfs_install_table(syst_pa);
469
470 tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
471
472 for (i = 0; i < tbl_cnt; i++)
473 sfi_sysfs_install_table(syst_va->pentry[i]);
474
475 sfi_acpi_sysfs_init();
476 kobject_uevent(sfi_kobj, KOBJ_ADD);
477 kobject_uevent(tables_kobj, KOBJ_ADD);
478 pr_info("SFI sysfs interfaces init success\n");
479 return 0;
480}
481
385void __init sfi_init(void) 482void __init sfi_init(void)
386{ 483{
387 if (!acpi_disabled) 484 if (!acpi_disabled)
@@ -414,3 +511,9 @@ void __init sfi_init_late(void)
414 511
415 sfi_acpi_init(); 512 sfi_acpi_init();
416} 513}
514
515/*
516 * The reason we put it here becasue we need wait till the /sys/firmware
517 * is setup, then our interface can be registered in /sys/firmware/sfi
518 */
519core_initcall(sfi_sysfs_init);
diff --git a/drivers/sfi/sfi_core.h b/drivers/sfi/sfi_core.h
index da82d39e104d..b7cf220d44ec 100644
--- a/drivers/sfi/sfi_core.h
+++ b/drivers/sfi/sfi_core.h
@@ -61,6 +61,12 @@ struct sfi_table_key{
61 char *oem_table_id; 61 char *oem_table_id;
62}; 62};
63 63
64/* sysfs interface */
65struct sfi_table_attr {
66 struct bin_attribute attr;
67 char name[8];
68};
69
64#define SFI_ANY_KEY { .sig = NULL, .oem_id = NULL, .oem_table_id = NULL } 70#define SFI_ANY_KEY { .sig = NULL, .oem_id = NULL, .oem_table_id = NULL }
65 71
66extern int __init sfi_acpi_init(void); 72extern int __init sfi_acpi_init(void);
@@ -68,3 +74,5 @@ extern struct sfi_table_header *sfi_check_table(u64 paddr,
68 struct sfi_table_key *key); 74 struct sfi_table_key *key);
69struct sfi_table_header *sfi_get_table(struct sfi_table_key *key); 75struct sfi_table_header *sfi_get_table(struct sfi_table_key *key);
70extern void sfi_put_table(struct sfi_table_header *table); 76extern void sfi_put_table(struct sfi_table_header *table);
77extern struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa);
78extern void __init sfi_acpi_sysfs_init(void);