aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/ec.c103
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
123static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); 123static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
124static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); 124static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event);
125static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, 125static 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
164static 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
164static int acpi_ec_wait(union acpi_ec *ec, u8 event) 180static 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}
206static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
207{
208 int result = 0;
209 222
223static 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;
299end: 296end:
@@ -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
364static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, 361static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command,