Some clean-ups to query handling in EC. From: <> --- drivers/acpi/ec.c | 103 ++++++++++++++++++++++++++++++----------------------- 1 files changed, 58 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e6d4b08..a1dea6e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -67,8 +67,8 @@ enum { #define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ -#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ -#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ +#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ +#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 100ms max. during EC ops */ enum { EC_INTR = 1, /* Output buffer full */ @@ -101,8 +101,9 @@ struct acpi_ec { unsigned long data_addr; unsigned long global_lock; struct semaphore sem; - unsigned int expect_event; atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ + atomic_t query_pending; /* EC asked to query itself */ + atomic_t expect_event; /* Tell interrupt handler we are waiting for something... */ wait_queue_head_t wait; } *ec_ecdt; @@ -137,6 +138,8 @@ static inline void acpi_ec_write_data(st static int acpi_ec_check_status(u8 status, u8 event) { switch (event) { + case 0: + return 1; case ACPI_EC_EVENT_OBF_1: if (status & ACPI_EC_FLAG_OBF) return 1; @@ -145,21 +148,20 @@ static int acpi_ec_check_status(u8 statu if (!(status & ACPI_EC_FLAG_IBF)) return 1; break; - default: - break; + default:; } return 0; } -static int acpi_ec_wait(struct acpi_ec *ec, u8 event) +static int acpi_ec_wait(struct acpi_ec *ec) { int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0; long time_left; + u8 status; - ec->expect_event = event; - if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { - ec->expect_event = 0; + if (acpi_ec_check_status(acpi_ec_read_status(ec), atomic_read(&ec->expect_event))) { + atomic_set(&ec->expect_event, 0); return 0; } @@ -168,21 +170,24 @@ static int acpi_ec_wait(struct acpi_ec * udelay(ACPI_EC_UDELAY); } else { time_left = wait_event_timeout(ec->wait, - !ec->expect_event, + !atomic_read(&ec->expect_event), msecs_to_jiffies(ACPI_EC_DELAY)); if (time_left > 0) { - ec->expect_event = 0; - return 0; + atomic_set(&ec->expect_event, 0); } + if (!atomic_read(&ec->expect_event)) + return 0; + status = acpi_ec_read_status(ec); + printk("EC: wait_event_timeout returned 0, status = %d, expect = %d\n", + status, atomic_read(&ec->expect_event)); } - if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { - ec->expect_event = 0; + if (acpi_ec_check_status(acpi_ec_read_status(ec), atomic_read(&ec->expect_event))) { + atomic_set(&ec->expect_event, 0); return 0; } } while (--i > 0); - ec->expect_event = 0; - + atomic_set(&ec->expect_event, 0); return -ETIME; } @@ -244,26 +249,38 @@ static int acpi_ec_transaction_unlocked( { int result; + atomic_set(&ec->expect_event, wdata_len ? ACPI_EC_EVENT_IBF_0 : ACPI_EC_EVENT_OBF_1); acpi_ec_write_cmd(ec, command); - for (; wdata_len > 0; wdata_len --) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); - if (result) + for (;wdata_len > 0; --wdata_len) { + result = acpi_ec_wait(ec); + if (result) { + printk("EC: ec_wait timeout, command = %d, wdata_len = %d, rdata_len = %d\n", + command, wdata_len, rdata_len); return result; + } + atomic_set(&ec->expect_event, wdata_len ? ACPI_EC_EVENT_IBF_0 : ACPI_EC_EVENT_OBF_1); acpi_ec_write_data(ec, *(wdata++)); } if (command == ACPI_EC_COMMAND_WRITE) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); - if (result) + result = acpi_ec_wait(ec); + if (result) { + printk("EC: ec_wait timeout, command = %d, wdata_len = %d, rdata_len = %d\n", + command, wdata_len, rdata_len); return result; + } } - for (; rdata_len > 0; rdata_len --) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); - if (result) + for (;rdata_len > 0; --rdata_len) { + result = acpi_ec_wait(ec); + if (result) { + printk("EC: ec_wait timeout, command = %d, wdata_len = %d, rdata_len = %d\n", + command, wdata_len, rdata_len); return result; - + } + if (rdata_len) + atomic_set(&ec->expect_event, ACPI_EC_EVENT_OBF_1); *(rdata++) = acpi_ec_read_data(ec); } @@ -290,8 +307,7 @@ static int acpi_ec_transaction(struct ac } down(&ec->sem); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); - if (status) { + if (!acpi_ec_check_status(acpi_ec_read_status(ec), ACPI_EC_EVENT_IBF_0)) { printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); goto end; } @@ -299,7 +315,8 @@ static int acpi_ec_transaction(struct ac status = acpi_ec_transaction_unlocked(ec, command, wdata, wdata_len, rdata, rdata_len); - + if (atomic_read(&ec->query_pending)) + printk("EC: Query is pending!\n"); end: up(&ec->sem); @@ -424,27 +441,21 @@ static void acpi_ec_gpe_query(void *ec_c { struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; u8 value = 0; - static char object_name[8]; + char object_name[8]; if (!ec) - goto end; - - value = acpi_ec_read_status(ec); - - if (!(value & ACPI_EC_FLAG_SCI)) - goto end; + return; + + atomic_set(&ec->query_pending, 0); if (acpi_ec_query(ec, &value)) - goto end; + return; snprintf(object_name, 8, "_Q%2.2X", value); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); + printk("EC: evaluating %s\n", object_name); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - - end: - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } static u32 acpi_ec_gpe_handler(void *data) @@ -457,17 +468,17 @@ static u32 acpi_ec_gpe_handler(void *dat value = acpi_ec_read_status(ec); if (acpi_ec_mode == EC_INTR) { - if (acpi_ec_check_status(value, ec->expect_event)) { - ec->expect_event = 0; + if (acpi_ec_check_status(value, atomic_read(&ec->expect_event))) { + atomic_set(&ec->expect_event, 0); wake_up(&ec->wait); } } - if (value & ACPI_EC_FLAG_SCI) { + if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { + atomic_set(&ec->query_pending, 1); status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); - return status == AE_OK ? - ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; @@ -660,6 +671,8 @@ static int acpi_ec_add(struct acpi_devic ec->handle = device->handle; ec->uid = -1; init_MUTEX(&ec->sem); + atomic_set(&ec->query_pending, 0); + atomic_set(&ec->expect_event, 0); if (acpi_ec_mode == EC_INTR) { atomic_set(&ec->leaving_burst, 1); init_waitqueue_head(&ec->wait);