Commit 716e084e authored by Luming Yu's avatar Luming Yu Committed by Len Brown

[ACPI] Fix "ec_burst=1" mode latency issue

http://bugzilla.kernel.org/show_bug.cgi?id=3851Signed-off-by: default avatarLuming Yu <luming.yu@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent cbfc1bae
...@@ -234,18 +234,29 @@ static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event) ...@@ -234,18 +234,29 @@ static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event)
ec->burst.expect_event = event; ec->burst.expect_event = event;
smp_mb(); smp_mb();
result = wait_event_interruptible_timeout(ec->burst.wait, switch (event) {
case ACPI_EC_EVENT_OBF:
if (acpi_ec_read_status(ec) & event) {
ec->burst.expect_event = 0;
return_VALUE(0);
}
break;
case ACPI_EC_EVENT_IBE:
if (~acpi_ec_read_status(ec) & event) {
ec->burst.expect_event = 0;
return_VALUE(0);
}
break;
}
result = wait_event_timeout(ec->burst.wait,
!ec->burst.expect_event, !ec->burst.expect_event,
msecs_to_jiffies(ACPI_EC_DELAY)); msecs_to_jiffies(ACPI_EC_DELAY));
ec->burst.expect_event = 0; ec->burst.expect_event = 0;
smp_mb(); smp_mb();
if (result < 0){
ACPI_DEBUG_PRINT((ACPI_DB_ERROR," result = %d ", result));
return_VALUE(result);
}
/* /*
* Verify that the event in question has actually happened by * Verify that the event in question has actually happened by
* querying EC status. Do the check even if operation timed-out * querying EC status. Do the check even if operation timed-out
...@@ -280,14 +291,14 @@ acpi_ec_enter_burst_mode ( ...@@ -280,14 +291,14 @@ acpi_ec_enter_burst_mode (
status = acpi_ec_read_status(ec); status = acpi_ec_read_status(ec);
if (status != -EINVAL && if (status != -EINVAL &&
!(status & ACPI_EC_FLAG_BURST)){ !(status & ACPI_EC_FLAG_BURST)){
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if(status)
goto end;
acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->common.command_addr); acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->common.command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (status){ if (status)
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
}
acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr); acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
if(tmp != 0x90 ) {/* Burst ACK byte*/ if(tmp != 0x90 ) {/* Burst ACK byte*/
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
} }
...@@ -295,31 +306,19 @@ acpi_ec_enter_burst_mode ( ...@@ -295,31 +306,19 @@ acpi_ec_enter_burst_mode (
atomic_set(&ec->burst.leaving_burst , 0); atomic_set(&ec->burst.leaving_burst , 0);
return_VALUE(0); return_VALUE(0);
end:
printk("Error in acpi_ec_wait\n");
return_VALUE(-1);
} }
static int static int
acpi_ec_leave_burst_mode ( acpi_ec_leave_burst_mode (
union acpi_ec *ec) union acpi_ec *ec)
{ {
int status =0;
ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode"); ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode");
atomic_set(&ec->burst.leaving_burst , 1); atomic_set(&ec->burst.leaving_burst, 1);
status = acpi_ec_read_status(ec);
if (status != -EINVAL &&
(status & ACPI_EC_FLAG_BURST)){
acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
if (status){
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n"));
return_VALUE(-EINVAL);
}
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
status = acpi_ec_read_status(ec);
}
return_VALUE(0); return_VALUE(0);
} }
...@@ -461,7 +460,6 @@ acpi_ec_burst_read ( ...@@ -461,7 +460,6 @@ acpi_ec_burst_read (
if (!ec || !data) if (!ec || !data)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
retry:
*data = 0; *data = 0;
if (ec->common.global_lock) { if (ec->common.global_lock) {
...@@ -473,26 +471,25 @@ acpi_ec_burst_read ( ...@@ -473,26 +471,25 @@ acpi_ec_burst_read (
WARN_ON(in_interrupt()); WARN_ON(in_interrupt());
down(&ec->burst.sem); down(&ec->burst.sem);
if(acpi_ec_enter_burst_mode(ec)) acpi_ec_enter_burst_mode(ec);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (status) {
printk("read EC, IB not empty\n");
goto end; goto end;
}
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->common.command_addr); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->common.command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
if (status) { if (status) {
goto end; printk("read EC, IB not empty\n");
} }
acpi_hw_low_level_write(8, address, &ec->common.data_addr); acpi_hw_low_level_write(8, address, &ec->common.data_addr);
status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (status){ if (status){
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); printk("read EC, OB not full\n");
goto end; goto end;
} }
acpi_hw_low_level_read(8, data, &ec->common.data_addr); acpi_hw_low_level_read(8, data, &ec->common.data_addr);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address)); *data, address));
...@@ -503,15 +500,6 @@ acpi_ec_burst_read ( ...@@ -503,15 +500,6 @@ acpi_ec_burst_read (
if (ec->common.global_lock) if (ec->common.global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
if(atomic_read(&ec->burst.leaving_burst) == 2){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
while(atomic_read(&ec->burst.pending_gpe)){
msleep(1);
}
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
goto retry;
}
return_VALUE(status); return_VALUE(status);
} }
...@@ -524,13 +512,12 @@ acpi_ec_burst_write ( ...@@ -524,13 +512,12 @@ acpi_ec_burst_write (
{ {
int status = 0; int status = 0;
u32 glk; u32 glk;
u32 tmp;
ACPI_FUNCTION_TRACE("acpi_ec_write"); ACPI_FUNCTION_TRACE("acpi_ec_write");
if (!ec) if (!ec)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
retry:
if (ec->common.global_lock) { if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
...@@ -540,61 +527,35 @@ acpi_ec_burst_write ( ...@@ -540,61 +527,35 @@ acpi_ec_burst_write (
WARN_ON(in_interrupt()); WARN_ON(in_interrupt());
down(&ec->burst.sem); down(&ec->burst.sem);
if(acpi_ec_enter_burst_mode(ec)) acpi_ec_enter_burst_mode(ec);
goto end;
status = acpi_ec_read_status(ec); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (status != -EINVAL && if ( status) {
!(status & ACPI_EC_FLAG_BURST)){ printk("write EC, IB not empty\n");
acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->common.command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (status)
goto end;
acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
if(tmp != 0x90 ) /* Burst ACK byte*/
goto end;
} }
/*Now we are in burst mode*/
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->common.command_addr); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->common.command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); if (status) {
if (status){ printk ("write EC, IB not empty\n");
goto end;
} }
acpi_hw_low_level_write(8, address, &ec->common.data_addr); acpi_hw_low_level_write(8, address, &ec->common.data_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (status){ if (status){
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); printk("write EC, IB not empty\n");
goto end;
} }
acpi_hw_low_level_write(8, data, &ec->common.data_addr); acpi_hw_low_level_write(8, data, &ec->common.data_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
if (status)
goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
data, address)); data, address));
end:
acpi_ec_leave_burst_mode(ec); acpi_ec_leave_burst_mode(ec);
up(&ec->burst.sem); up(&ec->burst.sem);
if (ec->common.global_lock) if (ec->common.global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
if(atomic_read(&ec->burst.leaving_burst) == 2){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
while(atomic_read(&ec->burst.pending_gpe)){
msleep(1);
}
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
goto retry;
}
return_VALUE(status); return_VALUE(status);
} }
...@@ -719,8 +680,12 @@ acpi_ec_burst_query ( ...@@ -719,8 +680,12 @@ acpi_ec_burst_query (
} }
down(&ec->burst.sem); down(&ec->burst.sem);
if(acpi_ec_enter_burst_mode(ec))
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (status) {
printk("query EC, IB not empty\n");
goto end; goto end;
}
/* /*
* Query the EC to find out which _Qxx method we need to evaluate. * Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI * Note that successful completion of the query causes the ACPI_EC_SCI
...@@ -729,27 +694,20 @@ acpi_ec_burst_query ( ...@@ -729,27 +694,20 @@ acpi_ec_burst_query (
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->common.command_addr); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->common.command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (status){ if (status){
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); printk("query EC, OB not full\n");
goto end; goto end;
} }
acpi_hw_low_level_read(8, data, &ec->common.data_addr); acpi_hw_low_level_read(8, data, &ec->common.data_addr);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
if (!*data) if (!*data)
status = -ENODATA; status = -ENODATA;
end: end:
acpi_ec_leave_burst_mode(ec);
up(&ec->burst.sem); up(&ec->burst.sem);
if (ec->common.global_lock) if (ec->common.global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
if(atomic_read(&ec->burst.leaving_burst) == 2){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
status = -ENODATA;
}
return_VALUE(status); return_VALUE(status);
} }
...@@ -885,31 +843,21 @@ acpi_ec_gpe_burst_handler ( ...@@ -885,31 +843,21 @@ acpi_ec_gpe_burst_handler (
if (!ec) if (!ec)
return ACPI_INTERRUPT_NOT_HANDLED; return ACPI_INTERRUPT_NOT_HANDLED;
acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
value = acpi_ec_read_status(ec); value = acpi_ec_read_status(ec);
if((value & ACPI_EC_FLAG_IBF) && switch ( ec->burst.expect_event) {
!(value & ACPI_EC_FLAG_BURST) && case ACPI_EC_EVENT_OBF:
(atomic_read(&ec->burst.leaving_burst) == 0)) { if (!(value & ACPI_EC_FLAG_OBF))
/* break;
* the embedded controller disables case ACPI_EC_EVENT_IBE:
* burst mode for any reason other if ((value & ACPI_EC_FLAG_IBF))
* than the burst disable command break;
* to process critical event. ec->burst.expect_event = 0;
*/
atomic_set(&ec->burst.leaving_burst , 2); /* block current pending transaction
and retry */
wake_up(&ec->burst.wait); wake_up(&ec->burst.wait);
}else { return ACPI_INTERRUPT_HANDLED;
if ((ec->burst.expect_event == ACPI_EC_EVENT_OBF && default:
(value & ACPI_EC_FLAG_OBF)) || break;
(ec->burst.expect_event == ACPI_EC_EVENT_IBE &&
!(value & ACPI_EC_FLAG_IBF))) {
ec->burst.expect_event = 0;
wake_up(&ec->burst.wait);
return ACPI_INTERRUPT_HANDLED;
}
} }
if (value & ACPI_EC_FLAG_SCI){ if (value & ACPI_EC_FLAG_SCI){
...@@ -1242,6 +1190,7 @@ acpi_ec_burst_add ( ...@@ -1242,6 +1190,7 @@ acpi_ec_burst_add (
if (result) if (result)
goto end; goto end;
printk("burst-mode-ec-10-Aug\n");
printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n", printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n",
acpi_device_name(device), acpi_device_bid(device), acpi_device_name(device), acpi_device_bid(device),
(u32) ec->common.gpe_bit); (u32) ec->common.gpe_bit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment