summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/events/evxfevnt.c18
-rw-r--r--drivers/acpi/hardware/hwgpe.c2
-rw-r--r--drivers/acpi/system.c169
3 files changed, 171 insertions, 18 deletions
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 99a7502e6a87..73bfd6bf962f 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -472,7 +472,6 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
}
ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
-#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
* FUNCTION: acpi_get_event_status
@@ -489,6 +488,7 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
{
acpi_status status = AE_OK;
+ u32 value;
ACPI_FUNCTION_TRACE(acpi_get_event_status);
@@ -506,7 +506,20 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- status_register_id, event_status);
+ enable_register_id, &value);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
+ *event_status = value;
+
+ status =
+ acpi_get_register(acpi_gbl_fixed_event_info[event].
+ status_register_id, &value);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
+ if (value)
+ *event_status |= ACPI_EVENT_FLAG_SET;
return_ACPI_STATUS(status);
}
@@ -566,7 +579,6 @@ acpi_get_gpe_status(acpi_handle gpe_device,
}
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
-#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
*
* FUNCTION: acpi_install_gpe_block
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 58347d6c43f8..0b80db9d9197 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -186,7 +186,6 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
*
******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
acpi_event_status * event_status)
@@ -246,7 +245,6 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
unlock_and_exit:
return (status);
}
-#endif /* ACPI_FUTURE_USAGE */
/******************************************************************************
*
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 5bd2dec9a7ac..d8e3f153b295 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -167,7 +167,13 @@ static int acpi_system_sysfs_init(void)
#define COUNT_ERROR 2 /* other */
#define NUM_COUNTERS_EXTRA 3
-static u32 *all_counters;
+#define ACPI_EVENT_VALID 0x01
+struct event_counter {
+ u32 count;
+ u32 flags;
+};
+
+static struct event_counter *all_counters;
static u32 num_gpes;
static u32 num_counters;
static struct attribute **all_attrs;
@@ -202,9 +208,44 @@ static int count_num_gpes(void)
return count;
}
+static int get_gpe_device(int index, acpi_handle *handle)
+{
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+ struct acpi_gpe_block_info *gpe_block;
+ acpi_cpu_flags flags;
+ struct acpi_namespace_node *node;
+
+ 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;
+ node = gpe_block->node;
+ while (gpe_block) {
+ index -= gpe_block->register_count *
+ ACPI_GPE_REGISTER_WIDTH;
+ if (index < 0) {
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ /* return NULL if it's FADT GPE */
+ if (node->type != ACPI_TYPE_DEVICE)
+ *handle = NULL;
+ else
+ *handle = node;
+ return 0;
+ }
+ node = gpe_block->node;
+ gpe_block = gpe_block->next;
+ }
+ gpe_xrupt_info = gpe_xrupt_info->next;
+ }
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+ return -ENODEV;
+}
+
static void delete_gpe_attr_array(void)
{
- u32 *tmp = all_counters;
+ struct event_counter *tmp = all_counters;
all_counters = NULL;
kfree(tmp);
@@ -230,9 +271,10 @@ void acpi_os_gpe_count(u32 gpe_number)
return;
if (gpe_number < num_gpes)
- all_counters[gpe_number]++;
+ all_counters[gpe_number].count++;
else
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR].
+ count++;
return;
}
@@ -243,44 +285,144 @@ void acpi_os_fixed_event_count(u32 event_number)
return;
if (event_number < ACPI_NUM_FIXED_EVENTS)
- all_counters[num_gpes + event_number]++;
+ all_counters[num_gpes + event_number].count++;
else
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR].
+ count++;
return;
}
+static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle)
+{
+ int result = 0;
+
+ if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
+ goto end;
+
+ if (index < num_gpes) {
+ result = get_gpe_device(index, handle);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
+ "Invalid GPE 0x%x\n", index));
+ goto end;
+ }
+ result = acpi_get_gpe_status(*handle, index,
+ ACPI_NOT_ISR, status);
+ } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS))
+ result = acpi_get_event_status(index - num_gpes, status);
+
+ /*
+ * sleep/power button GPE/Fixed Event is enabled after acpi_system_init,
+ * check the status at runtime and mark it as valid once it's enabled
+ */
+ if (!result && (*status & ACPI_EVENT_FLAG_ENABLED))
+ all_counters[index].flags |= ACPI_EVENT_VALID;
+end:
+ return result;
+}
+
static ssize_t counter_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
+ int index = attr - counter_attrs;
+ int size;
+ acpi_handle handle;
+ acpi_event_status status;
+ int result = 0;
+
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count =
acpi_irq_handled;
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count =
acpi_gpe_count;
- return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
+ size = sprintf(buf, "%8d", all_counters[index].count);
+
+ /* "gpe_all" or "sci" */
+ if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
+ goto end;
+
+ result = get_status(index, &status, &handle);
+ if (result)
+ goto end;
+
+ if (!(all_counters[index].flags & ACPI_EVENT_VALID))
+ size += sprintf(buf + size, " invalid");
+ else if (status & ACPI_EVENT_FLAG_ENABLED)
+ size += sprintf(buf + size, " enable");
+ else
+ size += sprintf(buf + size, " disable");
+
+end:
+ size += sprintf(buf + size, "\n");
+ return result ? result : size;
}
/*
* counter_set() sets the specified counter.
* setting the total "sci" file to any value clears all counters.
+ * enable/disable/clear a gpe/fixed event in user space.
*/
static ssize_t counter_set(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t size)
{
int index = attr - counter_attrs;
+ acpi_event_status status;
+ acpi_handle handle;
+ int result = 0;
if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
int i;
for (i = 0; i < num_counters; ++i)
- all_counters[i] = 0;
+ all_counters[i].count = 0;
acpi_gpe_count = 0;
acpi_irq_handled = 0;
+ goto end;
+ }
+ /* show the event status for both GPEs and Fixed Events */
+ result = get_status(index, &status, &handle);
+ if (result)
+ goto end;
+
+ if (!(all_counters[index].flags & ACPI_EVENT_VALID)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Can not change Invalid GPE/Fixed Event status\n"));
+ return -EINVAL;
+ }
+
+ if (index < num_gpes) {
+ if (!strcmp(buf, "disable\n") &&
+ (status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_disable_gpe(handle, index, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "enable\n") &&
+ !(status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_enable_gpe(handle, index, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "clear\n") &&
+ (status & ACPI_EVENT_FLAG_SET))
+ result = acpi_clear_gpe(handle, index, ACPI_NOT_ISR);
+ else
+ all_counters[index].count = strtoul(buf, NULL, 0);
+ } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) {
+ int event = index - num_gpes;
+ if (!strcmp(buf, "disable\n") &&
+ (status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_disable_event(event, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "enable\n") &&
+ !(status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_enable_event(event, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "clear\n") &&
+ (status & ACPI_EVENT_FLAG_SET))
+ result = acpi_clear_event(event);
+ else
+ all_counters[index].count = strtoul(buf, NULL, 0);
} else
- all_counters[index] = strtoul(buf, NULL, 0);
+ all_counters[index].count = strtoul(buf, NULL, 0);
- return size;
+ if (ACPI_FAILURE(result))
+ result = -EINVAL;
+end:
+ return result ? result : size;
}
void acpi_irq_stats_init(void)
@@ -298,7 +440,8 @@ void acpi_irq_stats_init(void)
if (all_attrs == NULL)
return;
- all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
+ all_counters = kzalloc(sizeof(struct event_counter) * (num_counters),
+ GFP_KERNEL);
if (all_counters == NULL)
goto fail;