Add GPE count under /sys/firmware/acpi/gpe. signed-off-by: Luming Yu <[EMAIL PROTECTED]> -- 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 <[EMAIL PROTECTED]>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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 <[EMAIL PROTECTED]>");
+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);
gpe_count.patch
Description: Binary data
