diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2008-11-08 13:42:30 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-11-11 18:34:19 -0500 |
commit | dd15f8c42af09031e27da5b4d697ce925511f2e1 (patch) | |
tree | 284d25e1c8387df3672d88b9108c06b283b6bad5 /drivers/acpi/ec.c | |
parent | f8248434e6a11d7cd314281be3b39bbcf82fc243 (diff) |
ACPI: EC: wait for last write gpe
There is a possibility that EC might break if next command is
issued within 1 us after write or burst-disable command.
Suggestd-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index b340e08cf1d9..cebd65d2e2a9 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -102,6 +102,7 @@ struct transaction { | |||
102 | u8 command; | 102 | u8 command; |
103 | u8 wlen; | 103 | u8 wlen; |
104 | u8 rlen; | 104 | u8 rlen; |
105 | bool done; | ||
105 | }; | 106 | }; |
106 | 107 | ||
107 | static struct acpi_ec { | 108 | static struct acpi_ec { |
@@ -178,7 +179,7 @@ static int ec_transaction_done(struct acpi_ec *ec) | |||
178 | unsigned long flags; | 179 | unsigned long flags; |
179 | int ret = 0; | 180 | int ret = 0; |
180 | spin_lock_irqsave(&ec->curr_lock, flags); | 181 | spin_lock_irqsave(&ec->curr_lock, flags); |
181 | if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen)) | 182 | if (!ec->curr || ec->curr->done) |
182 | ret = 1; | 183 | ret = 1; |
183 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 184 | spin_unlock_irqrestore(&ec->curr_lock, flags); |
184 | return ret; | 185 | return ret; |
@@ -195,17 +196,20 @@ static void gpe_transaction(struct acpi_ec *ec, u8 status) | |||
195 | acpi_ec_write_data(ec, *(ec->curr->wdata++)); | 196 | acpi_ec_write_data(ec, *(ec->curr->wdata++)); |
196 | --ec->curr->wlen; | 197 | --ec->curr->wlen; |
197 | } else | 198 | } else |
198 | /* false interrupt, state didn't change */ | 199 | goto err; |
199 | ++ec->curr->irq_count; | ||
200 | |||
201 | } else if (ec->curr->rlen > 0) { | 200 | } else if (ec->curr->rlen > 0) { |
202 | if ((status & ACPI_EC_FLAG_OBF) == 1) { | 201 | if ((status & ACPI_EC_FLAG_OBF) == 1) { |
203 | *(ec->curr->rdata++) = acpi_ec_read_data(ec); | 202 | *(ec->curr->rdata++) = acpi_ec_read_data(ec); |
204 | --ec->curr->rlen; | 203 | if (--ec->curr->rlen == 0) |
204 | ec->curr->done = true; | ||
205 | } else | 205 | } else |
206 | /* false interrupt, state didn't change */ | 206 | goto err; |
207 | ++ec->curr->irq_count; | 207 | } else if (ec->curr->wlen == 0 && (status & ACPI_EC_FLAG_IBF) == 0) |
208 | } | 208 | ec->curr->done = true; |
209 | goto unlock; | ||
210 | err: | ||
211 | /* false interrupt, state didn't change */ | ||
212 | ++ec->curr->irq_count; | ||
209 | unlock: | 213 | unlock: |
210 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 214 | spin_unlock_irqrestore(&ec->curr_lock, flags); |
211 | } | 215 | } |
@@ -265,6 +269,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
265 | spin_lock_irqsave(&ec->curr_lock, tmp); | 269 | spin_lock_irqsave(&ec->curr_lock, tmp); |
266 | /* following two actions should be kept atomic */ | 270 | /* following two actions should be kept atomic */ |
267 | t->irq_count = 0; | 271 | t->irq_count = 0; |
272 | t->done = false; | ||
268 | ec->curr = t; | 273 | ec->curr = t; |
269 | acpi_ec_write_cmd(ec, ec->curr->command); | 274 | acpi_ec_write_cmd(ec, ec->curr->command); |
270 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) | 275 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) |