aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/evxfgpe.c
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2012-06-28 22:04:17 -0400
committerLen Brown <len.brown@intel.com>2012-07-14 11:17:29 -0400
commit5816b3430c4b5f31d9c35af1da7be721c9518137 (patch)
tree6d5877c622f05f65cab4040771a6654a5fbf47b3 /drivers/acpi/acpica/evxfgpe.c
parente40d5940396aa4002feeab8323224b5c7f84246c (diff)
ACPICA: Add support for implicit notify on multiple devices
Adds basic support to allow multiple devices to be implicitly notified. This change is partially derived from original commit 981858b("ACPI / ACPICA: Implicit notify for multiple devices") by Rafael. Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jung-uk Kim <jkim@freebsd.org> Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/evxfgpe.c')
-rw-r--r--drivers/acpi/acpica/evxfgpe.c106
1 files changed, 69 insertions, 37 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 86f9b343ebd4..2ce44099eb84 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -197,12 +197,12 @@ acpi_status
197acpi_setup_gpe_for_wake(acpi_handle wake_device, 197acpi_setup_gpe_for_wake(acpi_handle wake_device,
198 acpi_handle gpe_device, u32 gpe_number) 198 acpi_handle gpe_device, u32 gpe_number)
199{ 199{
200 acpi_status status = AE_BAD_PARAMETER; 200 acpi_status status;
201 struct acpi_gpe_event_info *gpe_event_info; 201 struct acpi_gpe_event_info *gpe_event_info;
202 struct acpi_namespace_node *device_node; 202 struct acpi_namespace_node *device_node;
203 struct acpi_gpe_notify_object *notify_object; 203 struct acpi_gpe_notify_info *notify;
204 struct acpi_gpe_notify_info *new_notify;
204 acpi_cpu_flags flags; 205 acpi_cpu_flags flags;
205 u8 gpe_dispatch_mask;
206 206
207 ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); 207 ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);
208 208
@@ -216,63 +216,95 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
216 return_ACPI_STATUS(AE_BAD_PARAMETER); 216 return_ACPI_STATUS(AE_BAD_PARAMETER);
217 } 217 }
218 218
219 /* Handle root object case */
220
221 if (wake_device == ACPI_ROOT_OBJECT) {
222 device_node = acpi_gbl_root_node;
223 } else {
224 device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
225 }
226
227 /* Validate WakeDevice is of type Device */
228
229 if (device_node->type != ACPI_TYPE_DEVICE) {
230 return_ACPI_STATUS (AE_BAD_PARAMETER);
231 }
232
233 /*
234 * Allocate a new notify object up front, in case it is needed.
235 * Memory allocation while holding a spinlock is a big no-no
236 * on some hosts.
237 */
238 new_notify = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_notify_info));
239 if (!new_notify) {
240 return_ACPI_STATUS(AE_NO_MEMORY);
241 }
242
219 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 243 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
220 244
221 /* Ensure that we have a valid GPE number */ 245 /* Ensure that we have a valid GPE number */
222 246
223 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); 247 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
224 if (!gpe_event_info) { 248 if (!gpe_event_info) {
249 status = AE_BAD_PARAMETER;
225 goto unlock_and_exit; 250 goto unlock_and_exit;
226 } 251 }
227 252
228 if (wake_device == ACPI_ROOT_OBJECT) {
229 goto out;
230 }
231
232 /* 253 /*
233 * If there is no method or handler for this GPE, then the 254 * If there is no method or handler for this GPE, then the
234 * wake_device will be notified whenever this GPE fires (aka 255 * wake_device will be notified whenever this GPE fires. This is
235 * "implicit notify") Note: The GPE is assumed to be 256 * known as an "implicit notify". Note: The GPE is assumed to be
236 * level-triggered (for windows compatibility). 257 * level-triggered (for windows compatibility).
237 */ 258 */
238 gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK; 259 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
239 if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE 260 ACPI_GPE_DISPATCH_NONE) {
240 && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) { 261 /*
241 goto out; 262 * This is the first device for implicit notify on this GPE.
242 } 263 * Just set the flags here, and enter the NOTIFY block below.
243 264 */
244 /* Validate wake_device is of type Device */ 265 gpe_event_info->flags =
245 266 (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED);
246 device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
247 if (device_node->type != ACPI_TYPE_DEVICE) {
248 goto unlock_and_exit;
249 } 267 }
250 268
251 if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) { 269 /*
252 gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | 270 * If we already have an implicit notify on this GPE, add
253 ACPI_GPE_LEVEL_TRIGGERED); 271 * this device to the notify list.
254 gpe_event_info->dispatch.device.node = device_node; 272 */
255 gpe_event_info->dispatch.device.next = NULL; 273 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
256 } else { 274 ACPI_GPE_DISPATCH_NOTIFY) {
257 /* There are multiple devices to notify implicitly. */ 275
258 276 /* Ensure that the device is not already in the list */
259 notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object)); 277
260 if (!notify_object) { 278 notify = gpe_event_info->dispatch.notify_list;
261 status = AE_NO_MEMORY; 279 while (notify) {
262 goto unlock_and_exit; 280 if (notify->device_node == device_node) {
281 status = AE_ALREADY_EXISTS;
282 goto unlock_and_exit;
283 }
284 notify = notify->next;
263 } 285 }
264 286
265 notify_object->node = device_node; 287 /* Add this device to the notify list for this GPE */
266 notify_object->next = gpe_event_info->dispatch.device.next; 288
267 gpe_event_info->dispatch.device.next = notify_object; 289 new_notify->device_node = device_node;
290 new_notify->next = gpe_event_info->dispatch.notify_list;
291 gpe_event_info->dispatch.notify_list = new_notify;
292 new_notify = NULL;
268 } 293 }
269 294
270 out: 295 /* Mark the GPE as a possible wake event */
296
271 gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; 297 gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
272 status = AE_OK; 298 status = AE_OK;
273 299
274 unlock_and_exit: 300unlock_and_exit:
275 acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 301 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
302
303 /* Delete the notify object if it was not used above */
304
305 if (new_notify) {
306 ACPI_FREE(new_notify);
307 }
276 return_ACPI_STATUS(status); 308 return_ACPI_STATUS(status);
277} 309}
278ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) 310ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake)