lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 5 Feb 2008 02:30:10 -0500
From:	Len Brown <lenb@...nel.org>
To:	linux-acpi@...r.kernel.org, Greg Kroah-Hartman <gregkh@...e.de>
Cc:	linux-kernel@...r.kernel.org
Subject: [PATCH for review] ACPI: Create /sys/firmware/acpi/interrupts/ counters

From: Len Brown <len.brown@...el.com>

Here is the ACPI GPE statistics patch, forward ported to grok 2.6.25's kobject changes.
(Greg, let me know if I was able to unleash the inner beauty of the kobj interface)
(yes, I know you don't like sysfs files with more than 1 value,
 but I violate that rule for only one of the 33 files:-)

thanks,
-Len
--

# ls /sys/firmware/acpi/interrupts/
gpe00  gpe02  gpe04  gpe06  gpe08  gpe0A  gpe0C  gpe0E  gpe10  gpe12  gpe14  gpe16  gpe18  gpe1A  gpe1C  gpe1E  summary
gpe01  gpe03  gpe05  gpe07  gpe09  gpe0B  gpe0D  gpe0F  gpe11  gpe13  gpe15  gpe17  gpe19  gpe1B  gpe1D  gpe1F

# cat /sys/firmware/acpi/interrupts/summary
pm_timer     0
glbl_lock    0
power_btn    0
sleep_btn    0
rtc          0
gpe00    0
gpe01    0
gpe02    0
gpe03    0
gpe04    0
gpe05    0
gpe06    0
gpe07    0
gpe08    0
gpe09    2
gpe0A    0
gpe0B    0
gpe0C    0
gpe0D    0
gpe0E    0
gpe0F    0
gpe10    0
gpe11   60
gpe12    0
gpe13    0
gpe14    0
gpe15    0
gpe16    0
gpe17    0
gpe18    0
gpe19    1
gpe1A    0
gpe1B    0
gpe1C    0
gpe1D    0
gpe1E    0
gpe1F    0
gpe_hi    0
gpe_total   63
acpi_irq    63

Inspired-by-original-patch-by: Luming Yu <luming.yu@...el.com>
Signed-off-by: Len Brown <len.brown@...el.com>
---
 drivers/acpi/events/evevent.c     |    2 +-
 drivers/acpi/events/evgpe.c       |    2 +
 drivers/acpi/osl.c                |   12 ++-
 drivers/acpi/system.c             |  218 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/utilities/utglobal.c |    2 +
 include/acpi/acglobal.h           |    1 +
 include/acpi/aclocal.h            |    1 +
 include/acpi/acpiosxf.h           |    2 +
 include/linux/acpi.h              |    2 +
 9 files changed, 240 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index e412878..18514bf 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -259,7 +259,7 @@ u32 acpi_ev_fixed_event_detect(void)
 			enable_bit_mask)) {
 
 			/* Found an active (signalled) event */
-
+			acpi_fixed_event_count[i]++;
 			int_status |= acpi_ev_fixed_event_dispatch((u32) i);
 		}
 	}
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index e22f4a9..515128f 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -620,6 +620,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
 
 	acpi_gpe_count++;
 
+	acpi_os_gpe_count(gpe_number);
+
 	/*
 	 * 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/osl.c b/drivers/acpi/osl.c
index e53fb51..1087efe 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -332,7 +332,15 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
 
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
-	return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+	u32 handled;
+
+	handled = (*acpi_irq_handler) (acpi_irq_context);
+
+	if (handled) {
+		acpi_irq_handled++;
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
 }
 
 acpi_status
@@ -341,6 +349,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
 {
 	unsigned int irq;
 
+	acpi_irq_stats_init();
+
 	/*
 	 * Ignore the GSI from the core, and use the value in our copy of the
 	 * FADT. It may not be the same if an interrupt source override exists
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 5ffe0ea..538d154 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -40,6 +40,8 @@ ACPI_MODULE_NAME("system");
 #define ACPI_SYSTEM_CLASS		"system"
 #define ACPI_SYSTEM_DEVICE_NAME		"System"
 
+u32 acpi_irq_handled;
+
 /*
  * Make ACPICA version work as module param
  */
@@ -166,6 +168,222 @@ static int acpi_system_sysfs_init(void)
 	return 0;
 }
 
+/*
+ * ACPI IRQ counters
+ *
+ * /sys/firmware/acpi/interrupts/
+ *   summary -- IRQ, Fixed Event, and GPE counters
+ *   gpeXX -- broken-out counters for up to 32 GPEs
+ */
+
+static u32 *acpi_gpe_counters;
+static u32 gpe_counter_high;			/* bucket for GPE's >= 32 */
+static u32 number_of_gpes;
+static struct attribute **all_attrs;
+
+static struct attribute_group interrupt_stats_attr_group = {
+	.name = "interrupts",
+};
+static struct kobj_attribute *gpe_attrs;
+
+static int count_num_gpes(void)
+{
+	int count = 0;
+	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+	struct acpi_gpe_block_info *gpe_block;
+	acpi_cpu_flags flags;
+
+	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) {
+			count += gpe_block->register_count *
+			    ACPI_GPE_REGISTER_WIDTH;
+			gpe_block = gpe_block->next;
+		}
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+	return count;
+}
+
+static void delete_gpe_attr_array(void)
+{
+
+	u32 *tmp = acpi_gpe_counters;
+
+	acpi_gpe_counters = NULL;
+	kfree(tmp);
+
+	if (gpe_attrs) {
+		int i;
+
+		for (i = 0; i < number_of_gpes; i++)
+			kfree(gpe_attrs[i].attr.name);
+
+		kfree(gpe_attrs);
+	}
+	kfree(all_attrs);
+
+	return;
+}
+
+static ssize_t interrupt_summary_show(struct kobject *kobj,
+	struct kobj_attribute *attribute, char *buf)
+{
+	int i;
+	ssize_t count = 0;
+
+	/*
+	 * Fixed event counters
+	 */
+	count += sprintf(buf + count, "pm_timer  %4d\n",
+		acpi_fixed_event_count[ACPI_EVENT_PMTIMER]);
+
+	count += sprintf(buf + count, "glbl_lock %4d\n",
+		acpi_fixed_event_count[ACPI_EVENT_GLOBAL]);
+
+	count += sprintf(buf + count, "power_btn %4d\n",
+		acpi_fixed_event_count[ACPI_EVENT_POWER_BUTTON]);
+
+	count += sprintf(buf + count, "sleep_btn %4d\n",
+		acpi_fixed_event_count[ACPI_EVENT_SLEEP_BUTTON]);
+
+	count += sprintf(buf + count, "rtc       %4d\n",
+		acpi_fixed_event_count[ACPI_EVENT_RTC]);
+
+	/*
+	 * General Purpose Events
+	 */
+	for (i = 0; i < number_of_gpes; i++) {
+		count += sprintf(buf + count, "gpe%02X %4d\n",
+			i, acpi_gpe_counters[i]);
+	}
+
+	count += sprintf(buf + count, "gpe_hi %4d\n",
+		gpe_counter_high);
+
+	count += sprintf(buf + count, "gpe_total %4d\n",
+		acpi_gpe_count);
+
+	count += sprintf(buf + count, "acpi_irq  %4d\n",
+		acpi_irq_handled);
+
+	return count;
+}
+
+/*
+ * write anything to summary file: resets all counters
+ */
+static ssize_t interrupt_summary_reset(struct kobject *kobj,
+	struct kobj_attribute *attribute, const char *buf, size_t count)
+{
+	int i;
+
+	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; ++i)
+		acpi_fixed_event_count[i] = 0;
+
+	for (i = 0; i < number_of_gpes; ++i)
+		acpi_gpe_counters[i] = 0;
+
+	acpi_gpe_count = 0;
+	gpe_counter_high = 0;
+	acpi_irq_handled = 0;
+
+	return count;
+}
+void acpi_os_gpe_count(u32 gpe_number)
+{
+
+	if (!acpi_gpe_counters)
+		return;
+
+	if (gpe_number < number_of_gpes)
+		acpi_gpe_counters[gpe_number]++;
+	else
+		gpe_counter_high++;
+
+	return;
+}
+
+static struct kobj_attribute summary_attribute =
+	__ATTR(summary, 0644, interrupt_summary_show, interrupt_summary_reset);
+
+
+static ssize_t gpe_count_show(struct kobject *kobj,
+	struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", acpi_gpe_counters[attr - gpe_attrs]);
+}
+
+static ssize_t gpe_count_reset(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t size)
+{
+	acpi_gpe_counters[attr - gpe_attrs] = strtoul(buf, NULL, 0);
+
+	return size;
+}
+
+void acpi_irq_stats_init(void)
+{
+	int i;
+
+	number_of_gpes = count_num_gpes();
+
+	all_attrs = kzalloc(sizeof(struct attribute *) * (number_of_gpes + 2),
+			GFP_KERNEL);
+	if (all_attrs == NULL)
+		return;
+
+	acpi_gpe_counters = kzalloc(sizeof(u32) * (number_of_gpes), GFP_KERNEL);
+	if (acpi_gpe_counters == NULL)
+		goto fail;
+
+	gpe_attrs = kzalloc(sizeof(struct kobj_attribute) * (number_of_gpes),
+			GFP_KERNEL);
+	if (gpe_attrs == NULL)
+		goto fail;
+
+	for (i = 0; i < number_of_gpes; ++i) {
+		char buffer[10];
+		char *name;
+
+		sprintf(buffer, "gpe%02X", i);
+		name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
+		if (name == NULL)
+			goto fail;
+		strncpy(name, buffer, strlen(buffer) + 1);
+
+		gpe_attrs[i].attr.name = name;
+		gpe_attrs[i].attr.mode = 0644;
+		gpe_attrs[i].show = gpe_count_show;
+		gpe_attrs[i].store = gpe_count_reset;
+
+		all_attrs[i] = &gpe_attrs[i].attr;
+	}
+	all_attrs[number_of_gpes] = &summary_attribute.attr;
+
+	interrupt_stats_attr_group.attrs = all_attrs;
+	sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group);
+	return;
+
+fail:
+	delete_gpe_attr_array();
+	return;
+}
+
+static void __exit interrupt_stats_exit(void)
+{
+	sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
+
+	delete_gpe_attr_array();
+
+	return;
+}
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 93ea829..9cc1c3a 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -672,6 +672,8 @@ void acpi_ut_init_globals(void)
 	/* GPE support */
 
 	acpi_gpe_count = 0;
+	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++)
+		acpi_fixed_event_count[i] = 0;
 	acpi_gbl_gpe_xrupt_list_head = NULL;
 	acpi_gbl_gpe_fadt_blocks[0] = NULL;
 	acpi_gbl_gpe_fadt_blocks[1] = NULL;
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 347a911..7b3a2ba 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -120,6 +120,7 @@ extern u32 acpi_gbl_nesting_level;
 /* Event counters */
 
 ACPI_EXTERN u32 acpi_gpe_count;
+ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS];
 
 /* Support for dynamic control method tracing mechanism */
 
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 202cd42..cabdf12 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/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index ca882b8..4a64da5 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -181,6 +181,8 @@ acpi_os_install_interrupt_handler(u32 gsi,
 acpi_status
 acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine);
 
+void acpi_os_gpe_count(u32 gpe_number);
+
 /*
  * Threads and Scheduling
  */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 63f2e6e..cb911f3 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -115,7 +115,9 @@ int acpi_unmap_lsapic(int cpu);
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
 int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
+void acpi_irq_stats_init(void);
 
+extern u32 acpi_irq_handled;
 extern int acpi_mp_config;
 
 extern struct acpi_mcfg_allocation *pci_mmcfg_config;
-- 
1.5.4.18.gd0b8

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ