diff options
author | Feng Tang <feng.tang@intel.com> | 2010-05-25 23:28:08 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-05-27 12:46:20 -0400 |
commit | dce80a56268fffd6b5ea57b3f6ba3d027a68f05e (patch) | |
tree | 387349e5e6ee31dbe26c57ac0bf5d223af4ef838 /drivers/sfi | |
parent | 5487ab4a5a71e955fef7094a0624df0542da91ef (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>
Diffstat (limited to 'drivers/sfi')
-rw-r--r-- | drivers/sfi/sfi_acpi.c | 41 | ||||
-rw-r--r-- | drivers/sfi/sfi_core.c | 103 | ||||
-rw-r--r-- | drivers/sfi/sfi_core.h | 8 |
3 files changed, 152 insertions, 0 deletions
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 | |||
177 | static 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 | |||
203 | void __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 | ||
386 | static struct kobject *sfi_kobj; | ||
387 | static struct kobject *tables_kobj; | ||
388 | |||
389 | static 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 | |||
418 | struct 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 | |||
451 | static 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 | |||
385 | void __init sfi_init(void) | 482 | void __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 | */ | ||
519 | core_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 */ | ||
65 | struct 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 | ||
66 | extern int __init sfi_acpi_init(void); | 72 | extern 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); |
69 | struct sfi_table_header *sfi_get_table(struct sfi_table_key *key); | 75 | struct sfi_table_header *sfi_get_table(struct sfi_table_key *key); |
70 | extern void sfi_put_table(struct sfi_table_header *table); | 76 | extern void sfi_put_table(struct sfi_table_header *table); |
77 | extern struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa); | ||
78 | extern void __init sfi_acpi_sysfs_init(void); | ||