aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
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
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')
-rw-r--r--drivers/acpi/acpica/acevents.h4
-rw-r--r--drivers/acpi/acpica/achware.h3
-rw-r--r--drivers/acpi/acpica/evgpe.c108
-rw-r--r--drivers/acpi/acpica/evxfevnt.c59
-rw-r--r--drivers/acpi/acpica/hwgpe.c26
5 files changed, 78 insertions, 122 deletions
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 5e094a28cf54..138bbb521930 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -78,10 +78,6 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node *node,
78acpi_status 78acpi_status
79acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info); 79acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info);
80 80
81acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
82
83acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
84
85struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, 81struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
86 u32 gpe_number); 82 u32 gpe_number);
87 83
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index c46277d179f0..32391588e163 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -93,7 +93,8 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width);
93u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info, 93u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
94 struct acpi_gpe_register_info *gpe_register_info); 94 struct acpi_gpe_register_info *gpe_register_info);
95 95
96acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info); 96acpi_status
97acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action);
97 98
98acpi_status 99acpi_status
99acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info); 100acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 57eeb3bde41e..66cd03835d6e 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -99,106 +99,6 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
99 return_ACPI_STATUS(AE_OK); 99 return_ACPI_STATUS(AE_OK);
100} 100}
101 101
102/*******************************************************************************
103 *
104 * FUNCTION: acpi_ev_enable_gpe
105 *
106 * PARAMETERS: gpe_event_info - GPE to enable
107 *
108 * RETURN: Status
109 *
110 * DESCRIPTION: Hardware-enable a GPE. Always enables the GPE, regardless
111 * of type or number of references.
112 *
113 * Note: The GPE lock should be already acquired when this function is called.
114 *
115 ******************************************************************************/
116
117acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
118{
119 acpi_status status;
120
121
122 ACPI_FUNCTION_TRACE(ev_enable_gpe);
123
124
125 /*
126 * We will only allow a GPE to be enabled if it has either an
127 * associated method (_Lxx/_Exx) or a handler. Otherwise, the
128 * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
129 * first time it fires.
130 */
131 if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
132 return_ACPI_STATUS(AE_NO_HANDLER);
133 }
134
135 /* Ensure the HW enable masks are current */
136
137 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
138 if (ACPI_FAILURE(status)) {
139 return_ACPI_STATUS(status);
140 }
141
142 /* Clear the GPE (of stale events) */
143
144 status = acpi_hw_clear_gpe(gpe_event_info);
145 if (ACPI_FAILURE(status)) {
146 return_ACPI_STATUS(status);
147 }
148
149 /* Enable the requested GPE */
150
151 status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
152 return_ACPI_STATUS(status);
153}
154
155/*******************************************************************************
156 *
157 * FUNCTION: acpi_ev_disable_gpe
158 *
159 * PARAMETERS: gpe_event_info - GPE to disable
160 *
161 * RETURN: Status
162 *
163 * DESCRIPTION: Hardware-disable a GPE. Always disables the requested GPE,
164 * regardless of the type or number of references.
165 *
166 * Note: The GPE lock should be already acquired when this function is called.
167 *
168 ******************************************************************************/
169
170acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
171{
172 acpi_status status;
173
174 ACPI_FUNCTION_TRACE(ev_disable_gpe);
175
176
177 /*
178 * Note: Always disable the GPE, even if we think that that it is already
179 * disabled. It is possible that the AML or some other code has enabled
180 * the GPE behind our back.
181 */
182
183 /* Ensure the HW enable masks are current */
184
185 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
186 if (ACPI_FAILURE(status)) {
187 return_ACPI_STATUS(status);
188 }
189
190 /*
191 * Always H/W disable this GPE, even if we don't know the GPE type.
192 * Simply clear the enable bit for this particular GPE, but do not
193 * write out the current GPE enable mask since this may inadvertently
194 * enable GPEs too early. An example is a rogue GPE that has arrived
195 * during ACPICA initialization - possibly because AML or other code
196 * has enabled the GPE.
197 */
198 status = acpi_hw_low_disable_gpe(gpe_event_info);
199 return_ACPI_STATUS(status);
200}
201
202 102
203/******************************************************************************* 103/*******************************************************************************
204 * 104 *
@@ -450,10 +350,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
450 return_VOID; 350 return_VOID;
451 } 351 }
452 352
453 /* Update the GPE register masks for return to enabled state */
454
455 (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
456
457 /* 353 /*
458 * Take a snapshot of the GPE info for this level - we copy the info to 354 * Take a snapshot of the GPE info for this level - we copy the info to
459 * prevent a race condition with remove_handler/remove_block. 355 * prevent a race condition with remove_handler/remove_block.
@@ -606,7 +502,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
606 * Disable the GPE, so it doesn't keep firing before the method has a 502 * Disable the GPE, so it doesn't keep firing before the method has a
607 * chance to run (it runs asynchronously with interrupts enabled). 503 * chance to run (it runs asynchronously with interrupts enabled).
608 */ 504 */
609 status = acpi_ev_disable_gpe(gpe_event_info); 505 status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
610 if (ACPI_FAILURE(status)) { 506 if (ACPI_FAILURE(status)) {
611 ACPI_EXCEPTION((AE_INFO, status, 507 ACPI_EXCEPTION((AE_INFO, status,
612 "Unable to disable GPE[0x%2X]", 508 "Unable to disable GPE[0x%2X]",
@@ -643,7 +539,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
643 * Disable the GPE. The GPE will remain disabled a handler 539 * Disable the GPE. The GPE will remain disabled a handler
644 * is installed or ACPICA is restarted. 540 * is installed or ACPICA is restarted.
645 */ 541 */
646 status = acpi_ev_disable_gpe(gpe_event_info); 542 status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
647 if (ACPI_FAILURE(status)) { 543 if (ACPI_FAILURE(status)) {
648 ACPI_EXCEPTION((AE_INFO, status, 544 ACPI_EXCEPTION((AE_INFO, status,
649 "Unable to disable GPE[0x%2X]", 545 "Unable to disable GPE[0x%2X]",
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
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index d989b8e786cc..40388e23e103 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -78,23 +78,27 @@ u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
78 78
79/****************************************************************************** 79/******************************************************************************
80 * 80 *
81 * FUNCTION: acpi_hw_low_disable_gpe 81 * FUNCTION: acpi_hw_low_set_gpe
82 * 82 *
83 * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled 83 * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled
84 * action - Enable or disable
84 * 85 *
85 * RETURN: Status 86 * RETURN: Status
86 * 87 *
87 * DESCRIPTION: Disable a single GPE in the enable register. 88 * DESCRIPTION: Enable or disable a single GPE in its enable register.
88 * 89 *
89 ******************************************************************************/ 90 ******************************************************************************/
90 91
91acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) 92acpi_status
93acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
92{ 94{
93 struct acpi_gpe_register_info *gpe_register_info; 95 struct acpi_gpe_register_info *gpe_register_info;
94 acpi_status status; 96 acpi_status status;
95 u32 enable_mask; 97 u32 enable_mask;
96 u32 register_bit; 98 u32 register_bit;
97 99
100 ACPI_FUNCTION_ENTRY();
101
98 /* Get the info block for the entire GPE register */ 102 /* Get the info block for the entire GPE register */
99 103
100 gpe_register_info = gpe_event_info->register_info; 104 gpe_register_info = gpe_event_info->register_info;
@@ -109,11 +113,23 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
109 return (status); 113 return (status);
110 } 114 }
111 115
112 /* Clear just the bit that corresponds to this GPE */ 116 /* Set ot clear just the bit that corresponds to this GPE */
113 117
114 register_bit = acpi_hw_gpe_register_bit(gpe_event_info, 118 register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
115 gpe_register_info); 119 gpe_register_info);
116 ACPI_CLEAR_BIT(enable_mask, register_bit); 120 switch (action) {
121 case ACPI_GPE_ENABLE:
122 ACPI_SET_BIT(enable_mask, register_bit);
123 break;
124
125 case ACPI_GPE_DISABLE:
126 ACPI_CLEAR_BIT(enable_mask, register_bit);
127 break;
128
129 default:
130 ACPI_ERROR((AE_INFO, "Invalid action\n"));
131 return (AE_BAD_PARAMETER);
132 }
117 133
118 /* Write the updated enable mask */ 134 /* Write the updated enable mask */
119 135