diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-firmware-sfi | 15 | ||||
-rw-r--r-- | drivers/sfi/sfi_acpi.c | 41 | ||||
-rw-r--r-- | drivers/sfi/sfi_core.c | 105 | ||||
-rw-r--r-- | drivers/sfi/sfi_core.h | 8 | ||||
-rw-r--r-- | include/linux/sfi.h | 24 |
5 files changed, 191 insertions, 2 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 @@ | |||
1 | What: /sys/firmware/sfi/tables/ | ||
2 | Date: May 2010 | ||
3 | Contact: Len Brown <lenb@kernel.org> | ||
4 | Description: | ||
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 | |||
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..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) |
@@ -390,7 +487,7 @@ void __init sfi_init(void) | |||
390 | if (sfi_disabled) | 487 | if (sfi_disabled) |
391 | return; | 488 | return; |
392 | 489 | ||
393 | pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n"); | 490 | pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n"); |
394 | 491 | ||
395 | if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init()) | 492 | if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init()) |
396 | disable_sfi(); | 493 | disable_sfi(); |
@@ -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); | ||
diff --git a/include/linux/sfi.h b/include/linux/sfi.h index 9a6f7607174e..0299b4ce63db 100644 --- a/include/linux/sfi.h +++ b/include/linux/sfi.h | |||
@@ -73,6 +73,8 @@ | |||
73 | #define SFI_SIG_SPIB "SPIB" | 73 | #define SFI_SIG_SPIB "SPIB" |
74 | #define SFI_SIG_I2CB "I2CB" | 74 | #define SFI_SIG_I2CB "I2CB" |
75 | #define SFI_SIG_GPEM "GPEM" | 75 | #define SFI_SIG_GPEM "GPEM" |
76 | #define SFI_SIG_DEVS "DEVS" | ||
77 | #define SFI_SIG_GPIO "GPIO" | ||
76 | 78 | ||
77 | #define SFI_SIGNATURE_SIZE 4 | 79 | #define SFI_SIGNATURE_SIZE 4 |
78 | #define SFI_OEM_ID_SIZE 6 | 80 | #define SFI_OEM_ID_SIZE 6 |
@@ -145,6 +147,27 @@ struct sfi_rtc_table_entry { | |||
145 | u32 irq; | 147 | u32 irq; |
146 | } __packed; | 148 | } __packed; |
147 | 149 | ||
150 | struct sfi_device_table_entry { | ||
151 | u8 type; /* bus type, I2C, SPI or ...*/ | ||
152 | #define SFI_DEV_TYPE_SPI 0 | ||
153 | #define SFI_DEV_TYPE_I2C 1 | ||
154 | #define SFI_DEV_TYPE_UART 2 | ||
155 | #define SFI_DEV_TYPE_HSI 3 | ||
156 | #define SFI_DEV_TYPE_IPC 4 | ||
157 | |||
158 | u8 host_num; /* attached to host 0, 1...*/ | ||
159 | u16 addr; | ||
160 | u8 irq; | ||
161 | u32 max_freq; | ||
162 | char name[16]; | ||
163 | } __packed; | ||
164 | |||
165 | struct sfi_gpio_table_entry { | ||
166 | char controller_name[16]; | ||
167 | u16 pin_no; | ||
168 | char pin_name[16]; | ||
169 | } __packed; | ||
170 | |||
148 | struct sfi_spi_table_entry { | 171 | struct sfi_spi_table_entry { |
149 | u16 host_num; /* attached to host 0, 1...*/ | 172 | u16 host_num; /* attached to host 0, 1...*/ |
150 | u16 cs; /* chip select */ | 173 | u16 cs; /* chip select */ |
@@ -166,7 +189,6 @@ struct sfi_gpe_table_entry { | |||
166 | u16 phys_id; /* physical GPE id */ | 189 | u16 phys_id; /* physical GPE id */ |
167 | } __packed; | 190 | } __packed; |
168 | 191 | ||
169 | |||
170 | typedef int (*sfi_table_handler) (struct sfi_table_header *table); | 192 | typedef int (*sfi_table_handler) (struct sfi_table_header *table); |
171 | 193 | ||
172 | #ifdef CONFIG_SFI | 194 | #ifdef CONFIG_SFI |