[RFC patch] add GPE count under firmware acpi sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add GPE count under /sys/firmware/acpi/gpe.

signed-off-by: Luming Yu <Luming.yu@xxxxxxxxx>
--
drivers/acpi/Makefile       |    1
drivers/acpi/bus.c          |   44 ++++++++++++-
drivers/acpi/events/evgpe.c |    1
drivers/acpi/gpe_stats.c    |  104 +++++++++++++++++++++++++++++++
drivers/acpi/osl.c          |  146 ++++++++++++++++++++++++++++++++++++++++++++
include/acpi/aclocal.h      |    1
include/linux/acpi.h        |    7 ++
7 files changed, 303 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5956e9f..066eeeb 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -60,3 +60,4 @@ obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_ac
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)	+= acpi_memhotplug.o
obj-y				+= cm_sbs.o
obj-$(CONFIG_ACPI_SBS)		+= i2c_ec.o sbs.o
+obj-m				+= gpe_stats.o
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index dd49ea0..b1a8b24 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -735,6 +735,47 @@ #endif

decl_subsys(acpi, NULL, NULL);

+struct acpi_subsys_attr {
+	struct attribute attr;
+	int type;
+	int value;
+	ssize_t(*show) (struct attribute *, char *);
+	ssize_t(*store) (struct attribute *, const char *, size_t count);
+};
+#define to_acpi_attr(k) container_of(k,struct acpi_subsys_attr,attr)
+static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct acpi_subsys_attr *aattr = to_acpi_attr(attr);
+	if (aattr->show)
+		return aattr->show(attr, buf);
+	else
+		return -EIO;
+}
+
+static ssize_t store(struct kobject *kobj, struct attribute *attr,
+			const char *buf, size_t count)
+{
+	struct acpi_subsys_attr *aattr = to_acpi_attr(attr);
+	if (aattr->store)
+		return aattr->store(attr, buf, count);
+	else
+		return -EIO;
+}
+static struct sysfs_ops sysfs_ops = {
+	.show = show,
+	.store = store,
+};
+
+static struct kobj_type ktype_acpi = {
+	.sysfs_ops = &sysfs_ops,
+};
+
+void acpi_subsys_set_sysfs_ops(void)
+{
+	acpi_subsys.kset.kobj.ktype = &ktype_acpi;
+	acpi_subsys.kset.ktype = &ktype_acpi;
+}
+
static int __init acpi_init(void)
{
	int result = 0;
@@ -749,7 +790,7 @@ static int __init acpi_init(void)
	if (result < 0)
		printk(KERN_WARNING "%s: firmware_register error: %d\n",
			__FUNCTION__, result);
-
+	acpi_subsys_set_sysfs_ops();
	result = acpi_bus_init();

	if (!result) {
@@ -769,4 +810,5 @@ #endif
	return result;
}

+EXPORT_SYMBOL(acpi_subsys);
subsys_initcall(acpi_init);
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 635ba44..9b3face 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -621,6 +621,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve

	acpi_gpe_count++;

+	gpe_event_info->count++;
	/*
	 * If edge-triggered, clear the GPE status bit now.  Note that
	 * level-triggered events are cleared after the GPE is serviced.
diff --git a/drivers/acpi/gpe_stats.c b/drivers/acpi/gpe_stats.c
new file mode 100644
index 0000000..7be639d
--- /dev/null
+++ b/drivers/acpi/gpe_stats.c
@@ -0,0 +1,104 @@
+/*
+ *  gpe_stats.c
+ *
+ *  Copyright (C) 2007 Luming Yu <luming.yu@xxxxxxxxx>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/spinlock.h>
+#include <linux/acpi.h>
+
+typedef ssize_t(*show_func) (struct attribute * attr, char *buf);
+extern struct subsystem acpi_subsys;
+#define to_gpe_attr(k) container_of(k,struct gpe_attr, attr)
+#define GPE_STATS_ATTR(_name,_mode,_show)\
+static struct gpe_attr _attr_##_name = {\
+	.attr = {.name = __stringify(_name), .owner = THIS_MODULE, \
+		.mode = _mode,},\
+	.type = 0,\
+	.value = -1, \
+	.show = _show,\
+};
+extern int acpi_show_gpe_count(char *buf);
+extern int acpi_show_one_gpe_count(int gpe_number, char *buf);
+static ssize_t show_gpe_states(struct attribute *attr, char *buf)
+{
+	struct gpe_attr *gattr = to_gpe_attr(attr);
+	if (gattr->type == 0) {
+		if (gattr->value == -1)
+			return acpi_show_gpe_count(buf);
+		else
+			return acpi_show_one_gpe_count(gattr->value, buf);
+	} else
+		return 0;
+}
+
+GPE_STATS_ATTR(stats, 0444, show_gpe_states);
+
+static struct attribute **default_attrs;
+static struct attribute_group gpe_stats_attr_group = {
+	.name = "gpe",
+};
+static struct gpe_attr *gpe_attrs;
+extern int create_gpe_attr_array(struct module *module,
+				 struct attribute ***attrs,
+				 struct gpe_attr **gpe_attrs,
+				 struct gpe_attr *attr, show_func func);
+static int __init gpe_stats_init(void)
+{
+	int gpe_count;
+	int ret = 0;
+
+	gpe_count = create_gpe_attr_array(THIS_MODULE, &default_attrs,
+					  &gpe_attrs, &_attr_stats,
+					  &show_gpe_states);
+	default_attrs[gpe_count] = &_attr_stats.attr;
+	gpe_stats_attr_group.attrs = default_attrs;
+	ret = sysfs_create_group(&acpi_subsys.kset.kobj, &gpe_stats_attr_group);
+	return ret;
+}
+
+static void __exit gpe_stats_exit(void)
+{
+	struct attribute **p;
+	sysfs_remove_group(&acpi_subsys.kset.kobj, &gpe_stats_attr_group);
+
+	p = default_attrs;
+	while (*p) {
+		if (*p != &_attr_stats.attr)
+			kfree((*p++)->name);
+		else
+			p++;
+	}
+	kfree(default_attrs);
+	kfree(gpe_attrs);
+	return;
+}
+
+MODULE_AUTHOR("Yu Luming <luming.yu@xxxxxxxxx>");
+MODULE_DESCRIPTION("gpe_stats");
+MODULE_LICENSE("GPL");
+
+module_init(gpe_stats_init);
+module_exit(gpe_stats_exit);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 971eca4..ab04591 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1019,6 +1019,152 @@ void acpi_os_release_lock(acpi_spinlock
	spin_unlock_irqrestore(lockp, flags);
}

+typedef ssize_t(*show_func) (struct attribute * attr, char *buf);
+int create_gpe_attr_array(struct module *module,
+			  struct attribute ***attrs,
+			  struct gpe_attr **gpe_attrs,
+			  struct gpe_attr *attr, show_func * func)
+{
+	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+	struct acpi_gpe_register_info *gpe_register;
+	acpi_cpu_flags flags;
+	int i, j, gpe_count, count;
+
+	gpe_count = 0;
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+	while (gpe_xrupt_info) {
+		gpe_block = gpe_xrupt_info->gpe_block_list_head;
+		while (gpe_block) {
+			gpe_count += gpe_block->register_count *
+			    ACPI_GPE_REGISTER_WIDTH;
+			gpe_block = gpe_block->next;
+		}
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+	*attrs =
+	    kzalloc(sizeof(struct attribute *) * (gpe_count + 2), GFP_KERNEL);
+	*gpe_attrs =
+	    kzalloc(sizeof(struct gpe_attr) * (gpe_count + 1), GFP_KERNEL);
+	count = 0;
+	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+	while (gpe_xrupt_info) {
+		gpe_block = gpe_xrupt_info->gpe_block_list_head;
+		while (gpe_block) {
+			for (i = 0; i < gpe_block->register_count; i++) {
+				gpe_register = &gpe_block->register_info[i];
+				for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+					char *name;
+					int base =
+					    gpe_register->base_gpe_number;
+					int gpe;
+					gpe = base + j;
+					name = kzalloc(10, GFP_KERNEL);
+					sprintf(name, "%x", gpe);
+					memcpy(&(*gpe_attrs)[count],
+					       attr, sizeof(struct gpe_attr));
+					(*gpe_attrs)[count].attr.name = name;
+					(*gpe_attrs)[count].value = gpe;
+					(*attrs)[count] = (struct attribute *)
+					    &(*gpe_attrs)[count].attr;
+					count++;
+				}
+			}
+			gpe_block = gpe_block->next;
+		}
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+	return gpe_count;
+}
+
+EXPORT_SYMBOL(create_gpe_attr_array);
+
+int acpi_show_gpe_count(char *buf)
+{
+	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+	struct acpi_gpe_register_info *gpe_register_info;
+	acpi_cpu_flags flags;
+	u32 i, j, count;
+
+	count = 0;
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+	while (gpe_xrupt_info) {
+		gpe_block = gpe_xrupt_info->gpe_block_list_head;
+		while (gpe_block) {
+			for (i = 0; i < gpe_block->register_count; i++) {
+				gpe_register_info =
+				    &gpe_block->register_info[i];
+				for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
+					count += sprintf(buf + count,
+							 "GPE[%d]: %d\n",
+							 gpe_register_info->
+							 base_gpe_number + j,
+							 gpe_block->
+							 event_info[(i *
+								     ACPI_GPE_REGISTER_WIDTH)
+								    + j].count);
+			}
+			gpe_block = gpe_block->next;
+		}
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return count;
+}
+
+EXPORT_SYMBOL(acpi_show_gpe_count);
+
+int acpi_show_one_gpe_count(int gpe_number, char *buf)
+{
+	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+	struct acpi_gpe_register_info *gpe_register_info;
+	acpi_cpu_flags flags;
+	u32 i, j, count;
+
+	count = 0;
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+	while (gpe_xrupt_info) {
+		gpe_block = gpe_xrupt_info->gpe_block_list_head;
+		while (gpe_block) {
+			for (i = 0; i < gpe_block->register_count; i++) {
+				gpe_register_info =
+				    &gpe_block->register_info[i];
+				for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
+					if (gpe_number ==
+					    (gpe_register_info->
+					     base_gpe_number + j)) {
+						count +=
+						    sprintf(buf + count,
+							    "GPE[%d]: %d\n",
+							    gpe_register_info->
+							    base_gpe_number + j,
+							    gpe_block->
+							    event_info[(i *
+									ACPI_GPE_REGISTER_WIDTH)
+								       +
+								       j].
+							    count);
+						acpi_os_release_lock
+						    (acpi_gbl_gpe_lock, flags);
+						return count;
+					}
+			}
+			gpe_block = gpe_block->next;
+		}
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return count;
+}
+
+EXPORT_SYMBOL(acpi_show_one_gpe_count);
#ifndef ACPI_USE_LOCAL_CACHE

/*******************************************************************************
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 6f83ddb..380a8a8 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -368,6 +368,7 @@ struct acpi_gpe_event_info {
	struct acpi_gpe_register_info *register_info;	/* Backpointer to
register info */
	u8 flags;		/* Misc info about this GPE */
	u8 gpe_number;		/* This GPE */
+	u32 count;
};

/* Information about a GPE register pair, one per each status/enable
pair in an array */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8bcfaa4..35fab01 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -158,6 +158,13 @@ struct acpi_prt_list {
	struct list_head	entries;
};

+struct gpe_attr {
+	struct attribute attr;
+	int type;
+	int value;
+	ssize_t(*show) (struct attribute *, char *);
+	ssize_t(*store) (struct attribute *, const char *, size_t count);
+};
struct pci_dev;

int acpi_pci_irq_enable (struct pci_dev *dev);

Attachment: gpe_count.patch
Description: Binary data


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux