Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dce80a56 authored by Feng Tang's avatar Feng Tang Committed by Len Brown
Browse files

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: default avatarFeng Tang <feng.tang@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5487ab4a
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
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
+41 −0
Original line number Diff line number Diff line
@@ -173,3 +173,44 @@ int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
	sfi_acpi_put_table(table);
	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;
}
+103 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/sfi.h>
#include <linux/slab.h>

#include "sfi_core.h"

@@ -382,6 +383,102 @@ static __init int sfi_find_syst(void)
	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)
{
	if (!acpi_disabled)
@@ -414,3 +511,9 @@ void __init sfi_init_late(void)

	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);
+8 −0
Original line number Diff line number Diff line
@@ -61,6 +61,12 @@ struct sfi_table_key{
	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 }

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_header *sfi_get_table(struct sfi_table_key *key);
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);