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);

Attachment: gpe_count.patch
Description: Binary data

Reply via email to