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>
This commit is contained in:
parent
5487ab4a5a
commit
dce80a5626
|
@ -0,0 +1,15 @@
|
||||||
|
What: /sys/firmware/sfi/tables/
|
||||||
|
Date: May 2010
|
||||||
|
Contact: Len Brown <lenb@kernel.org>
|
||||||
|
Description:
|
||||||
|
SFI defines a number of small static memory tables
|
||||||
|
so the kernel can get platform information from firmware.
|
||||||
|
|
||||||
|
The tables are defined in the latest SFI specification:
|
||||||
|
http://simplefirmware.org/documentation
|
||||||
|
|
||||||
|
While the tables are used by the kernel, user-space
|
||||||
|
can observe them this way:
|
||||||
|
|
||||||
|
# cd /sys/firmware/sfi/tables
|
||||||
|
# cat $TABLENAME > $TABLENAME.bin
|
|
@ -173,3 +173,44 @@ int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
|
||||||
sfi_acpi_put_table(table);
|
sfi_acpi_put_table(table);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t sfi_acpi_table_show(struct file *filp, struct kobject *kobj,
|
||||||
|
struct bin_attribute *bin_attr, char *buf,
|
||||||
|
loff_t offset, size_t count)
|
||||||
|
{
|
||||||
|
struct sfi_table_attr *tbl_attr =
|
||||||
|
container_of(bin_attr, struct sfi_table_attr, attr);
|
||||||
|
struct acpi_table_header *th = NULL;
|
||||||
|
struct sfi_table_key key;
|
||||||
|
ssize_t cnt;
|
||||||
|
|
||||||
|
key.sig = tbl_attr->name;
|
||||||
|
key.oem_id = NULL;
|
||||||
|
key.oem_table_id = NULL;
|
||||||
|
|
||||||
|
th = sfi_acpi_get_table(&key);
|
||||||
|
if (!th)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cnt = memory_read_from_buffer(buf, count, &offset,
|
||||||
|
th, th->length);
|
||||||
|
sfi_acpi_put_table(th);
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void __init sfi_acpi_sysfs_init(void)
|
||||||
|
{
|
||||||
|
u32 tbl_cnt, i;
|
||||||
|
struct sfi_table_attr *tbl_attr;
|
||||||
|
|
||||||
|
tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
|
||||||
|
for (i = 0; i < tbl_cnt; i++) {
|
||||||
|
tbl_attr =
|
||||||
|
sfi_sysfs_install_table(xsdt_va->table_offset_entry[i]);
|
||||||
|
tbl_attr->attr.read = sfi_acpi_table_show;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/sfi.h>
|
#include <linux/sfi.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "sfi_core.h"
|
#include "sfi_core.h"
|
||||||
|
|
||||||
|
@ -382,6 +383,102 @@ static __init int sfi_find_syst(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct kobject *sfi_kobj;
|
||||||
|
static struct kobject *tables_kobj;
|
||||||
|
|
||||||
|
static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
|
||||||
|
struct bin_attribute *bin_attr, char *buf,
|
||||||
|
loff_t offset, size_t count)
|
||||||
|
{
|
||||||
|
struct sfi_table_attr *tbl_attr =
|
||||||
|
container_of(bin_attr, struct sfi_table_attr, attr);
|
||||||
|
struct sfi_table_header *th = NULL;
|
||||||
|
struct sfi_table_key key;
|
||||||
|
ssize_t cnt;
|
||||||
|
|
||||||
|
key.sig = tbl_attr->name;
|
||||||
|
key.oem_id = NULL;
|
||||||
|
key.oem_table_id = NULL;
|
||||||
|
|
||||||
|
if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
|
||||||
|
th = sfi_get_table(&key);
|
||||||
|
if (!th)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cnt = memory_read_from_buffer(buf, count, &offset,
|
||||||
|
th, th->len);
|
||||||
|
sfi_put_table(th);
|
||||||
|
} else
|
||||||
|
cnt = memory_read_from_buffer(buf, count, &offset,
|
||||||
|
syst_va, syst_va->header.len);
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
|
||||||
|
{
|
||||||
|
struct sfi_table_attr *tbl_attr;
|
||||||
|
struct sfi_table_header *th;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
|
||||||
|
if (!tbl_attr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
th = sfi_map_table(pa);
|
||||||
|
if (!th || !th->sig[0]) {
|
||||||
|
kfree(tbl_attr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sysfs_attr_init(&tbl_attr->attr.attr);
|
||||||
|
memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
|
||||||
|
|
||||||
|
tbl_attr->attr.size = 0;
|
||||||
|
tbl_attr->attr.read = sfi_table_show;
|
||||||
|
tbl_attr->attr.attr.name = tbl_attr->name;
|
||||||
|
tbl_attr->attr.attr.mode = 0400;
|
||||||
|
|
||||||
|
ret = sysfs_create_bin_file(tables_kobj,
|
||||||
|
&tbl_attr->attr);
|
||||||
|
if (ret)
|
||||||
|
kfree(tbl_attr);
|
||||||
|
|
||||||
|
sfi_unmap_table(th);
|
||||||
|
return tbl_attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init sfi_sysfs_init(void)
|
||||||
|
{
|
||||||
|
int tbl_cnt, i;
|
||||||
|
|
||||||
|
if (sfi_disabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
|
||||||
|
if (!sfi_kobj)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tables_kobj = kobject_create_and_add("tables", sfi_kobj);
|
||||||
|
if (!tables_kobj) {
|
||||||
|
kobject_put(sfi_kobj);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfi_sysfs_install_table(syst_pa);
|
||||||
|
|
||||||
|
tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
|
||||||
|
|
||||||
|
for (i = 0; i < tbl_cnt; i++)
|
||||||
|
sfi_sysfs_install_table(syst_va->pentry[i]);
|
||||||
|
|
||||||
|
sfi_acpi_sysfs_init();
|
||||||
|
kobject_uevent(sfi_kobj, KOBJ_ADD);
|
||||||
|
kobject_uevent(tables_kobj, KOBJ_ADD);
|
||||||
|
pr_info("SFI sysfs interfaces init success\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void __init sfi_init(void)
|
void __init sfi_init(void)
|
||||||
{
|
{
|
||||||
if (!acpi_disabled)
|
if (!acpi_disabled)
|
||||||
|
@ -414,3 +511,9 @@ void __init sfi_init_late(void)
|
||||||
|
|
||||||
sfi_acpi_init();
|
sfi_acpi_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The reason we put it here becasue we need wait till the /sys/firmware
|
||||||
|
* is setup, then our interface can be registered in /sys/firmware/sfi
|
||||||
|
*/
|
||||||
|
core_initcall(sfi_sysfs_init);
|
||||||
|
|
|
@ -61,6 +61,12 @@ struct sfi_table_key{
|
||||||
char *oem_table_id;
|
char *oem_table_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* sysfs interface */
|
||||||
|
struct sfi_table_attr {
|
||||||
|
struct bin_attribute attr;
|
||||||
|
char name[8];
|
||||||
|
};
|
||||||
|
|
||||||
#define SFI_ANY_KEY { .sig = NULL, .oem_id = NULL, .oem_table_id = NULL }
|
#define SFI_ANY_KEY { .sig = NULL, .oem_id = NULL, .oem_table_id = NULL }
|
||||||
|
|
||||||
extern int __init sfi_acpi_init(void);
|
extern int __init sfi_acpi_init(void);
|
||||||
|
@ -68,3 +74,5 @@ extern struct sfi_table_header *sfi_check_table(u64 paddr,
|
||||||
struct sfi_table_key *key);
|
struct sfi_table_key *key);
|
||||||
struct sfi_table_header *sfi_get_table(struct sfi_table_key *key);
|
struct sfi_table_header *sfi_get_table(struct sfi_table_key *key);
|
||||||
extern void sfi_put_table(struct sfi_table_header *table);
|
extern void sfi_put_table(struct sfi_table_header *table);
|
||||||
|
extern struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa);
|
||||||
|
extern void __init sfi_acpi_sysfs_init(void);
|
||||||
|
|
Loading…
Reference in New Issue