diff options
Diffstat (limited to 'drivers/sfi')
-rw-r--r-- | drivers/sfi/sfi_acpi.c | 41 | ||||
-rw-r--r-- | drivers/sfi/sfi_core.c | 107 | ||||
-rw-r--r-- | drivers/sfi/sfi_core.h | 8 |
3 files changed, 155 insertions, 1 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 b204a0929139..ceba593dc84f 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,104 @@ 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 | tbl_attr = NULL; | ||
447 | } | ||
448 | |||
449 | sfi_unmap_table(th); | ||
450 | return tbl_attr; | ||
451 | } | ||
452 | |||
453 | static int __init sfi_sysfs_init(void) | ||
454 | { | ||
455 | int tbl_cnt, i; | ||
456 | |||
457 | if (sfi_disabled) | ||
458 | return 0; | ||
459 | |||
460 | sfi_kobj = kobject_create_and_add("sfi", firmware_kobj); | ||
461 | if (!sfi_kobj) | ||
462 | return 0; | ||
463 | |||
464 | tables_kobj = kobject_create_and_add("tables", sfi_kobj); | ||
465 | if (!tables_kobj) { | ||
466 | kobject_put(sfi_kobj); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | sfi_sysfs_install_table(syst_pa); | ||
471 | |||
472 | tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64); | ||
473 | |||
474 | for (i = 0; i < tbl_cnt; i++) | ||
475 | sfi_sysfs_install_table(syst_va->pentry[i]); | ||
476 | |||
477 | sfi_acpi_sysfs_init(); | ||
478 | kobject_uevent(sfi_kobj, KOBJ_ADD); | ||
479 | kobject_uevent(tables_kobj, KOBJ_ADD); | ||
480 | pr_info("SFI sysfs interfaces init success\n"); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
385 | void __init sfi_init(void) | 484 | void __init sfi_init(void) |
386 | { | 485 | { |
387 | if (!acpi_disabled) | 486 | if (!acpi_disabled) |
@@ -390,7 +489,7 @@ void __init sfi_init(void) | |||
390 | if (sfi_disabled) | 489 | if (sfi_disabled) |
391 | return; | 490 | return; |
392 | 491 | ||
393 | pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n"); | 492 | pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n"); |
394 | 493 | ||
395 | if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init()) | 494 | if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init()) |
396 | disable_sfi(); | 495 | disable_sfi(); |
@@ -414,3 +513,9 @@ void __init sfi_init_late(void) | |||
414 | 513 | ||
415 | sfi_acpi_init(); | 514 | sfi_acpi_init(); |
416 | } | 515 | } |
516 | |||
517 | /* | ||
518 | * The reason we put it here becasue we need wait till the /sys/firmware | ||
519 | * is setup, then our interface can be registered in /sys/firmware/sfi | ||
520 | */ | ||
521 | 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); | ||