aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/evxfevnt.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-06-08 04:49:08 -0400
committerLen Brown <len.brown@intel.com>2010-06-12 00:44:37 -0400
commitfd247447c1d94a79d5cfc647430784306b3a8323 (patch)
treed3a58bb5e50068f4d9245f0788e7f14ff56ac711 /drivers/acpi/acpica/evxfevnt.c
parente4e9a735991c80fb0fc1bd4a13a93681c3c17ce0 (diff)
ACPI / ACPICA: Fix low-level GPE manipulation code
ACPICA uses acpi_ev_enable_gpe() for enabling GPEs at the low level, which is incorrect, because this function only enables the GPE if the corresponding bit in its enable register's enable_for_run mask is set. This causes acpi_set_gpe() to work incorrectly if used for enabling GPEs that were not previously enabled with acpi_enable_gpe(). As a result, among other things, wakeup-only GPEs are never enabled by acpi_enable_wakeup_device(), so the devices that use them are unable to wake up the system. To fix this issue remove acpi_ev_enable_gpe() and its counterpart acpi_ev_disable_gpe() and replace acpi_hw_low_disable_gpe() with acpi_hw_low_set_gpe() that will be used instead to manipulate GPE enable bits at the low level. Make the users of acpi_ev_enable_gpe() and acpi_ev_disable_gpe() call acpi_hw_low_set_gpe() instead and make sure that GPE enable masks are only updated by acpi_enable_gpe() and acpi_disable_gpe() when GPE reference counters change from 0 to 1 and from 1 to 0, respectively. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/evxfevnt.c')
-rw-r--r--drivers/acpi/acpica/evxfevnt.c59
1 files changed, 53 insertions, 6 deletions
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 7c7bbb4d402c..e3d9f5c8e53d 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -201,6 +201,44 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
201 201
202/******************************************************************************* 202/*******************************************************************************
203 * 203 *
204 * FUNCTION: acpi_clear_and_enable_gpe
205 *
206 * PARAMETERS: gpe_event_info - GPE to enable
207 *
208 * RETURN: Status
209 *
210 * DESCRIPTION: Clear the given GPE from stale events and enable it.
211 *
212 ******************************************************************************/
213static acpi_status
214acpi_clear_and_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
215{
216 acpi_status status;
217
218 /*
219 * We will only allow a GPE to be enabled if it has either an
220 * associated method (_Lxx/_Exx) or a handler. Otherwise, the
221 * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
222 * first time it fires.
223 */
224 if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
225 return_ACPI_STATUS(AE_NO_HANDLER);
226 }
227
228 /* Clear the GPE (of stale events) */
229 status = acpi_hw_clear_gpe(gpe_event_info);
230 if (ACPI_FAILURE(status)) {
231 return_ACPI_STATUS(status);
232 }
233
234 /* Enable the requested GPE */
235 status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
236
237 return_ACPI_STATUS(status);
238}
239
240/*******************************************************************************
241 *
204 * FUNCTION: acpi_set_gpe 242 * FUNCTION: acpi_set_gpe
205 * 243 *
206 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 244 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
@@ -240,11 +278,11 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
240 278
241 switch (action) { 279 switch (action) {
242 case ACPI_GPE_ENABLE: 280 case ACPI_GPE_ENABLE:
243 status = acpi_ev_enable_gpe(gpe_event_info); 281 status = acpi_clear_and_enable_gpe(gpe_event_info);
244 break; 282 break;
245 283
246 case ACPI_GPE_DISABLE: 284 case ACPI_GPE_DISABLE:
247 status = acpi_ev_disable_gpe(gpe_event_info); 285 status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
248 break; 286 break;
249 287
250 default: 288 default:
@@ -307,7 +345,11 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
307 345
308 gpe_event_info->runtime_count++; 346 gpe_event_info->runtime_count++;
309 if (gpe_event_info->runtime_count == 1) { 347 if (gpe_event_info->runtime_count == 1) {
310 status = acpi_ev_enable_gpe(gpe_event_info); 348 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
349 if (ACPI_SUCCESS(status)) {
350 status = acpi_clear_and_enable_gpe(gpe_event_info);
351 }
352
311 if (ACPI_FAILURE(status)) { 353 if (ACPI_FAILURE(status)) {
312 gpe_event_info->runtime_count--; 354 gpe_event_info->runtime_count--;
313 goto unlock_and_exit; 355 goto unlock_and_exit;
@@ -334,7 +376,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
334 */ 376 */
335 gpe_event_info->wakeup_count++; 377 gpe_event_info->wakeup_count++;
336 if (gpe_event_info->wakeup_count == 1) { 378 if (gpe_event_info->wakeup_count == 1) {
337 (void)acpi_ev_update_gpe_enable_masks(gpe_event_info); 379 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
338 } 380 }
339 } 381 }
340 382
@@ -394,7 +436,12 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
394 436
395 gpe_event_info->runtime_count--; 437 gpe_event_info->runtime_count--;
396 if (!gpe_event_info->runtime_count) { 438 if (!gpe_event_info->runtime_count) {
397 status = acpi_ev_disable_gpe(gpe_event_info); 439 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
440 if (ACPI_SUCCESS(status)) {
441 status = acpi_hw_low_set_gpe(gpe_event_info,
442 ACPI_GPE_DISABLE);
443 }
444
398 if (ACPI_FAILURE(status)) { 445 if (ACPI_FAILURE(status)) {
399 gpe_event_info->runtime_count++; 446 gpe_event_info->runtime_count++;
400 goto unlock_and_exit; 447 goto unlock_and_exit;
@@ -415,7 +462,7 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
415 462
416 gpe_event_info->wakeup_count--; 463 gpe_event_info->wakeup_count--;
417 if (!gpe_event_info->wakeup_count) { 464 if (!gpe_event_info->wakeup_count) {
418 (void)acpi_ev_update_gpe_enable_masks(gpe_event_info); 465 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
419 } 466 }
420 } 467 }
421 468