diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-11 11:35:05 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-11 11:35:05 -0500 |
commit | 37d11391c2de8a846da50a2972a82289e65e5ea6 (patch) | |
tree | 9ada78f04f57cb1deadc8cc30a1efe55c396cbf0 | |
parent | e06bf91b59d3d95359e046ffcdc577145933da10 (diff) |
Revert "ACPI / EC: Add query flushing support"
Revert commit f252cb09e1cb (ACPI / EC: Add query flushing support),
because it breaks system suspend on Acer Aspire S5. The machine
just hangs solid at the last stage of suspend (after taking non-boot
CPUs offline).
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/ec.c | 101 |
1 files changed, 16 insertions, 85 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 40002ae7db2b..982b67faaaf3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -76,9 +76,7 @@ enum ec_command { | |||
76 | * when trying to clear the EC */ | 76 | * when trying to clear the EC */ |
77 | 77 | ||
78 | enum { | 78 | enum { |
79 | EC_FLAGS_EVENT_ENABLED, /* Event is enabled */ | 79 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
80 | EC_FLAGS_EVENT_PENDING, /* Event is pending */ | ||
81 | EC_FLAGS_EVENT_DETECTED, /* Event is detected */ | ||
82 | EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and | 80 | EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and |
83 | * OpReg are installed */ | 81 | * OpReg are installed */ |
84 | EC_FLAGS_STARTED, /* Driver is started */ | 82 | EC_FLAGS_STARTED, /* Driver is started */ |
@@ -153,12 +151,6 @@ static bool acpi_ec_flushed(struct acpi_ec *ec) | |||
153 | return ec->reference_count == 1; | 151 | return ec->reference_count == 1; |
154 | } | 152 | } |
155 | 153 | ||
156 | static bool acpi_ec_has_pending_event(struct acpi_ec *ec) | ||
157 | { | ||
158 | return test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || | ||
159 | test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); | ||
160 | } | ||
161 | |||
162 | /* -------------------------------------------------------------------------- | 154 | /* -------------------------------------------------------------------------- |
163 | * EC Registers | 155 | * EC Registers |
164 | * -------------------------------------------------------------------------- */ | 156 | * -------------------------------------------------------------------------- */ |
@@ -326,93 +318,36 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) | |||
326 | * the flush operation is not in | 318 | * the flush operation is not in |
327 | * progress | 319 | * progress |
328 | * @ec: the EC device | 320 | * @ec: the EC device |
329 | * @allow_event: whether event should be handled | ||
330 | * | 321 | * |
331 | * This function must be used before taking a new action that should hold | 322 | * This function must be used before taking a new action that should hold |
332 | * the reference count. If this function returns false, then the action | 323 | * the reference count. If this function returns false, then the action |
333 | * must be discarded or it will prevent the flush operation from being | 324 | * must be discarded or it will prevent the flush operation from being |
334 | * completed. | 325 | * completed. |
335 | * | ||
336 | * During flushing, QR_EC command need to pass this check when there is a | ||
337 | * pending event, so that the reference count held for the pending event | ||
338 | * can be decreased by the completion of the QR_EC command. | ||
339 | */ | 326 | */ |
340 | static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec, | 327 | static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) |
341 | bool allow_event) | ||
342 | { | 328 | { |
343 | if (!acpi_ec_started(ec)) { | 329 | if (!acpi_ec_started(ec)) |
344 | if (!allow_event || !acpi_ec_has_pending_event(ec)) | 330 | return false; |
345 | return false; | ||
346 | } | ||
347 | acpi_ec_submit_request(ec); | 331 | acpi_ec_submit_request(ec); |
348 | return true; | 332 | return true; |
349 | } | 333 | } |
350 | 334 | ||
351 | static void acpi_ec_submit_event(struct acpi_ec *ec) | 335 | static void acpi_ec_submit_query(struct acpi_ec *ec) |
352 | { | 336 | { |
353 | if (!test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || | 337 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { |
354 | !test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) | 338 | pr_debug("***** Event started *****\n"); |
355 | return; | ||
356 | /* Hold reference for pending event */ | ||
357 | if (!acpi_ec_submit_flushable_request(ec, true)) | ||
358 | return; | ||
359 | if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) { | ||
360 | pr_debug("***** Event query started *****\n"); | ||
361 | schedule_work(&ec->work); | 339 | schedule_work(&ec->work); |
362 | return; | ||
363 | } | ||
364 | acpi_ec_complete_request(ec); | ||
365 | } | ||
366 | |||
367 | static void acpi_ec_complete_event(struct acpi_ec *ec) | ||
368 | { | ||
369 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { | ||
370 | clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); | ||
371 | pr_debug("***** Event query stopped *****\n"); | ||
372 | /* Unhold reference for pending event */ | ||
373 | acpi_ec_complete_request(ec); | ||
374 | /* Check if there is another SCI_EVT detected */ | ||
375 | acpi_ec_submit_event(ec); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | static void acpi_ec_submit_detection(struct acpi_ec *ec) | ||
380 | { | ||
381 | /* Hold reference for query submission */ | ||
382 | if (!acpi_ec_submit_flushable_request(ec, false)) | ||
383 | return; | ||
384 | if (!test_and_set_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags)) { | ||
385 | pr_debug("***** Event detection blocked *****\n"); | ||
386 | acpi_ec_submit_event(ec); | ||
387 | return; | ||
388 | } | 340 | } |
389 | acpi_ec_complete_request(ec); | ||
390 | } | 341 | } |
391 | 342 | ||
392 | static void acpi_ec_complete_detection(struct acpi_ec *ec) | 343 | static void acpi_ec_complete_query(struct acpi_ec *ec) |
393 | { | 344 | { |
394 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { | 345 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { |
395 | clear_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags); | 346 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
396 | pr_debug("***** Event detetion unblocked *****\n"); | 347 | pr_debug("***** Event stopped *****\n"); |
397 | /* Unhold reference for query submission */ | ||
398 | acpi_ec_complete_request(ec); | ||
399 | } | 348 | } |
400 | } | 349 | } |
401 | 350 | ||
402 | static void acpi_ec_enable_event(struct acpi_ec *ec) | ||
403 | { | ||
404 | unsigned long flags; | ||
405 | |||
406 | spin_lock_irqsave(&ec->lock, flags); | ||
407 | set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags); | ||
408 | /* | ||
409 | * An event may be pending even with SCI_EVT=0, so QR_EC should | ||
410 | * always be issued right after started. | ||
411 | */ | ||
412 | acpi_ec_submit_detection(ec); | ||
413 | spin_unlock_irqrestore(&ec->lock, flags); | ||
414 | } | ||
415 | |||
416 | static int ec_transaction_completed(struct acpi_ec *ec) | 351 | static int ec_transaction_completed(struct acpi_ec *ec) |
417 | { | 352 | { |
418 | unsigned long flags; | 353 | unsigned long flags; |
@@ -454,7 +389,6 @@ static void advance_transaction(struct acpi_ec *ec) | |||
454 | t->rdata[t->ri++] = acpi_ec_read_data(ec); | 389 | t->rdata[t->ri++] = acpi_ec_read_data(ec); |
455 | if (t->rlen == t->ri) { | 390 | if (t->rlen == t->ri) { |
456 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 391 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
457 | acpi_ec_complete_event(ec); | ||
458 | if (t->command == ACPI_EC_COMMAND_QUERY) | 392 | if (t->command == ACPI_EC_COMMAND_QUERY) |
459 | pr_debug("***** Command(%s) hardware completion *****\n", | 393 | pr_debug("***** Command(%s) hardware completion *****\n", |
460 | acpi_ec_cmd_string(t->command)); | 394 | acpi_ec_cmd_string(t->command)); |
@@ -465,7 +399,6 @@ static void advance_transaction(struct acpi_ec *ec) | |||
465 | } else if (t->wlen == t->wi && | 399 | } else if (t->wlen == t->wi && |
466 | (status & ACPI_EC_FLAG_IBF) == 0) { | 400 | (status & ACPI_EC_FLAG_IBF) == 0) { |
467 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 401 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
468 | acpi_ec_complete_event(ec); | ||
469 | wakeup = true; | 402 | wakeup = true; |
470 | } | 403 | } |
471 | goto out; | 404 | goto out; |
@@ -474,17 +407,16 @@ static void advance_transaction(struct acpi_ec *ec) | |||
474 | !(status & ACPI_EC_FLAG_SCI) && | 407 | !(status & ACPI_EC_FLAG_SCI) && |
475 | (t->command == ACPI_EC_COMMAND_QUERY)) { | 408 | (t->command == ACPI_EC_COMMAND_QUERY)) { |
476 | t->flags |= ACPI_EC_COMMAND_POLL; | 409 | t->flags |= ACPI_EC_COMMAND_POLL; |
477 | acpi_ec_complete_detection(ec); | 410 | acpi_ec_complete_query(ec); |
478 | t->rdata[t->ri++] = 0x00; | 411 | t->rdata[t->ri++] = 0x00; |
479 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 412 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
480 | acpi_ec_complete_event(ec); | ||
481 | pr_debug("***** Command(%s) software completion *****\n", | 413 | pr_debug("***** Command(%s) software completion *****\n", |
482 | acpi_ec_cmd_string(t->command)); | 414 | acpi_ec_cmd_string(t->command)); |
483 | wakeup = true; | 415 | wakeup = true; |
484 | } else if ((status & ACPI_EC_FLAG_IBF) == 0) { | 416 | } else if ((status & ACPI_EC_FLAG_IBF) == 0) { |
485 | acpi_ec_write_cmd(ec, t->command); | 417 | acpi_ec_write_cmd(ec, t->command); |
486 | t->flags |= ACPI_EC_COMMAND_POLL; | 418 | t->flags |= ACPI_EC_COMMAND_POLL; |
487 | acpi_ec_complete_detection(ec); | 419 | acpi_ec_complete_query(ec); |
488 | } else | 420 | } else |
489 | goto err; | 421 | goto err; |
490 | goto out; | 422 | goto out; |
@@ -505,7 +437,7 @@ err: | |||
505 | } | 437 | } |
506 | out: | 438 | out: |
507 | if (status & ACPI_EC_FLAG_SCI) | 439 | if (status & ACPI_EC_FLAG_SCI) |
508 | acpi_ec_submit_detection(ec); | 440 | acpi_ec_submit_query(ec); |
509 | if (wakeup && in_interrupt()) | 441 | if (wakeup && in_interrupt()) |
510 | wake_up(&ec->wait); | 442 | wake_up(&ec->wait); |
511 | } | 443 | } |
@@ -566,7 +498,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
566 | /* start transaction */ | 498 | /* start transaction */ |
567 | spin_lock_irqsave(&ec->lock, tmp); | 499 | spin_lock_irqsave(&ec->lock, tmp); |
568 | /* Enable GPE for command processing (IBF=0/OBF=1) */ | 500 | /* Enable GPE for command processing (IBF=0/OBF=1) */ |
569 | if (!acpi_ec_submit_flushable_request(ec, true)) { | 501 | if (!acpi_ec_submit_flushable_request(ec)) { |
570 | ret = -EINVAL; | 502 | ret = -EINVAL; |
571 | goto unlock; | 503 | goto unlock; |
572 | } | 504 | } |
@@ -947,9 +879,7 @@ static void acpi_ec_gpe_poller(struct work_struct *work) | |||
947 | { | 879 | { |
948 | struct acpi_ec *ec = container_of(work, struct acpi_ec, work); | 880 | struct acpi_ec *ec = container_of(work, struct acpi_ec, work); |
949 | 881 | ||
950 | pr_debug("***** Event poller started *****\n"); | ||
951 | acpi_ec_query(ec, NULL); | 882 | acpi_ec_query(ec, NULL); |
952 | pr_debug("***** Event poller stopped *****\n"); | ||
953 | } | 883 | } |
954 | 884 | ||
955 | static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, | 885 | static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, |
@@ -1019,6 +949,7 @@ static struct acpi_ec *make_acpi_ec(void) | |||
1019 | 949 | ||
1020 | if (!ec) | 950 | if (!ec) |
1021 | return NULL; | 951 | return NULL; |
952 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; | ||
1022 | mutex_init(&ec->mutex); | 953 | mutex_init(&ec->mutex); |
1023 | init_waitqueue_head(&ec->wait); | 954 | init_waitqueue_head(&ec->wait); |
1024 | INIT_LIST_HEAD(&ec->list); | 955 | INIT_LIST_HEAD(&ec->list); |
@@ -1169,7 +1100,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
1169 | ret = ec_install_handlers(ec); | 1100 | ret = ec_install_handlers(ec); |
1170 | 1101 | ||
1171 | /* EC is fully operational, allow queries */ | 1102 | /* EC is fully operational, allow queries */ |
1172 | acpi_ec_enable_event(ec); | 1103 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
1173 | 1104 | ||
1174 | /* Clear stale _Q events if hardware might require that */ | 1105 | /* Clear stale _Q events if hardware might require that */ |
1175 | if (EC_FLAGS_CLEAR_ON_RESUME) | 1106 | if (EC_FLAGS_CLEAR_ON_RESUME) |