diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 103 |
1 files changed, 50 insertions, 53 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a0dcbad97c45..b6f935d0c3ad 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -100,7 +100,7 @@ union acpi_ec { | |||
100 | struct acpi_generic_address command_addr; | 100 | struct acpi_generic_address command_addr; |
101 | struct acpi_generic_address data_addr; | 101 | struct acpi_generic_address data_addr; |
102 | unsigned long global_lock; | 102 | unsigned long global_lock; |
103 | unsigned int expect_event; | 103 | u8 expect_event; |
104 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ | 104 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ |
105 | atomic_t pending_gpe; | 105 | atomic_t pending_gpe; |
106 | struct semaphore sem; | 106 | struct semaphore sem; |
@@ -121,7 +121,7 @@ union acpi_ec { | |||
121 | }; | 121 | }; |
122 | 122 | ||
123 | static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); | 123 | static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); |
124 | static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); | 124 | static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event); |
125 | static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, | 125 | static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, |
126 | const u8 *wdata, unsigned wdata_len, | 126 | const u8 *wdata, unsigned wdata_len, |
127 | u8 *rdata, unsigned rdata_len); | 127 | u8 *rdata, unsigned rdata_len); |
@@ -161,6 +161,22 @@ static u32 acpi_ec_read_status(union acpi_ec *ec) | |||
161 | return status; | 161 | return status; |
162 | } | 162 | } |
163 | 163 | ||
164 | static int acpi_ec_check_status(u32 status, u8 event) { | ||
165 | |||
166 | switch (event) { | ||
167 | case ACPI_EC_EVENT_OBF: | ||
168 | if (status & ACPI_EC_FLAG_OBF) | ||
169 | return 1; | ||
170 | case ACPI_EC_EVENT_IBE: | ||
171 | if (!(status & ACPI_EC_FLAG_IBF)) | ||
172 | return 1; | ||
173 | default: | ||
174 | break; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
164 | static int acpi_ec_wait(union acpi_ec *ec, u8 event) | 180 | static int acpi_ec_wait(union acpi_ec *ec, u8 event) |
165 | { | 181 | { |
166 | if (acpi_ec_poll_mode) | 182 | if (acpi_ec_poll_mode) |
@@ -203,47 +219,28 @@ static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event) | |||
203 | 219 | ||
204 | return -ETIME; | 220 | return -ETIME; |
205 | } | 221 | } |
206 | static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event) | ||
207 | { | ||
208 | int result = 0; | ||
209 | 222 | ||
223 | static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event) | ||
224 | { | ||
225 | long time_left; | ||
210 | 226 | ||
211 | ec->intr.expect_event = event; | 227 | ec->intr.expect_event = event; |
212 | smp_mb(); | ||
213 | 228 | ||
214 | switch (event) { | 229 | if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { |
215 | case ACPI_EC_EVENT_IBE: | ||
216 | if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) { | ||
217 | ec->intr.expect_event = 0; | 230 | ec->intr.expect_event = 0; |
218 | return 0; | 231 | return 0; |
219 | } | ||
220 | break; | ||
221 | default: | ||
222 | break; | ||
223 | } | 232 | } |
224 | 233 | ||
225 | result = wait_event_timeout(ec->intr.wait, | 234 | time_left = wait_event_timeout(ec->intr.wait, !ec->intr.expect_event, |
226 | !ec->intr.expect_event, | 235 | msecs_to_jiffies(ACPI_EC_DELAY)); |
227 | msecs_to_jiffies(ACPI_EC_DELAY)); | ||
228 | 236 | ||
229 | ec->intr.expect_event = 0; | 237 | ec->intr.expect_event = 0; |
230 | smp_mb(); | 238 | if (time_left <= 0) { |
231 | 239 | if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { | |
232 | /* | 240 | return 0; |
233 | * Verify that the event in question has actually happened by | 241 | } |
234 | * querying EC status. Do the check even if operation timed-out | 242 | } else { |
235 | * to make sure that we did not miss interrupt. | 243 | return 0; |
236 | */ | ||
237 | switch (event) { | ||
238 | case ACPI_EC_EVENT_OBF: | ||
239 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) | ||
240 | return 0; | ||
241 | break; | ||
242 | |||
243 | case ACPI_EC_EVENT_IBE: | ||
244 | if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) | ||
245 | return 0; | ||
246 | break; | ||
247 | } | 244 | } |
248 | 245 | ||
249 | return -ETIME; | 246 | return -ETIME; |
@@ -293,7 +290,7 @@ int acpi_ec_leave_burst_mode(union acpi_ec *ec) | |||
293 | goto end; | 290 | goto end; |
294 | acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); | 291 | acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); |
295 | acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); | 292 | acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); |
296 | } | 293 | } |
297 | atomic_set(&ec->intr.leaving_burst, 1); | 294 | atomic_set(&ec->intr.leaving_burst, 1); |
298 | return 0; | 295 | return 0; |
299 | end: | 296 | end: |
@@ -333,32 +330,32 @@ static int acpi_ec_transaction_unlocked(union acpi_ec *ec, u8 command, | |||
333 | 330 | ||
334 | acpi_hw_low_level_write(8, command, &ec->common.command_addr); | 331 | acpi_hw_low_level_write(8, command, &ec->common.command_addr); |
335 | 332 | ||
336 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | 333 | for (; wdata_len > 0; wdata_len --) { |
337 | if (result) | 334 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); |
338 | return result; | 335 | if (result) |
339 | 336 | return result; | |
340 | for (; wdata_len > 0; wdata_len --) { | ||
341 | |||
342 | acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr); | ||
343 | 337 | ||
344 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | 338 | acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr); |
345 | if (result) | ||
346 | return result; | ||
347 | } | 339 | } |
348 | 340 | ||
341 | if (command == ACPI_EC_COMMAND_WRITE) { | ||
342 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | ||
343 | if (result) | ||
344 | return result; | ||
345 | } | ||
349 | 346 | ||
350 | for (; rdata_len > 0; rdata_len --) { | 347 | for (; rdata_len > 0; rdata_len --) { |
351 | u32 d; | 348 | u32 d; |
352 | 349 | ||
353 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); | 350 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); |
354 | if (result) | 351 | if (result) |
355 | return result; | 352 | return result; |
356 | 353 | ||
357 | acpi_hw_low_level_read(8, &d, &ec->common.data_addr); | 354 | acpi_hw_low_level_read(8, &d, &ec->common.data_addr); |
358 | *(rdata++) = (u8) d; | 355 | *(rdata++) = (u8) d; |
359 | } | 356 | } |
360 | 357 | ||
361 | return 0; | 358 | return 0; |
362 | } | 359 | } |
363 | 360 | ||
364 | static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, | 361 | static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, |