aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/acpi/acpica/aclocal.h11
-rw-r--r--drivers/acpi/acpica/evgpe.c22
-rw-r--r--drivers/acpi/acpica/evgpeutil.c20
-rw-r--r--drivers/acpi/acpica/evxfgpe.c106
4 files changed, 109 insertions, 50 deletions
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index af7330f4a52d..6b225e810f3a 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -404,6 +404,13 @@ struct acpi_gpe_handler_info {
404 u8 originally_enabled; /* True if GPE was originally enabled */ 404 u8 originally_enabled; /* True if GPE was originally enabled */
405}; 405};
406 406
407/* Notify info for implicit notify, multiple device objects */
408
409struct acpi_gpe_notify_info {
410 struct acpi_namespace_node *device_node; /* Device to be notified */
411 struct acpi_gpe_notify_info *next;
412};
413
407struct acpi_gpe_notify_object { 414struct acpi_gpe_notify_object {
408 struct acpi_namespace_node *node; 415 struct acpi_namespace_node *node;
409 struct acpi_gpe_notify_object *next; 416 struct acpi_gpe_notify_object *next;
@@ -412,7 +419,7 @@ struct acpi_gpe_notify_object {
412union acpi_gpe_dispatch_info { 419union acpi_gpe_dispatch_info {
413 struct acpi_namespace_node *method_node; /* Method node for this GPE level */ 420 struct acpi_namespace_node *method_node; /* Method node for this GPE level */
414 struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ 421 struct acpi_gpe_handler_info *handler; /* Installed GPE handler */
415 struct acpi_gpe_notify_object device; /* List of _PRW devices for implicit notify */ 422 struct acpi_gpe_notify_info *notify_list; /* List of _PRW devices for implicit notifies */
416}; 423};
417 424
418/* 425/*
@@ -420,7 +427,7 @@ union acpi_gpe_dispatch_info {
420 * NOTE: Important to keep this struct as small as possible. 427 * NOTE: Important to keep this struct as small as possible.
421 */ 428 */
422struct acpi_gpe_event_info { 429struct acpi_gpe_event_info {
423 union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ 430 union acpi_gpe_dispatch_info dispatch; /* Either Method, Handler, or notify_list */
424 struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ 431 struct acpi_gpe_register_info *register_info; /* Backpointer to register info */
425 u8 flags; /* Misc info about this GPE */ 432 u8 flags; /* Misc info about this GPE */
426 u8 gpe_number; /* This GPE */ 433 u8 gpe_number; /* This GPE */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 8ba0e5f17091..afbd5cb391f6 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -466,7 +466,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
466 acpi_status status; 466 acpi_status status;
467 struct acpi_gpe_event_info *local_gpe_event_info; 467 struct acpi_gpe_event_info *local_gpe_event_info;
468 struct acpi_evaluate_info *info; 468 struct acpi_evaluate_info *info;
469 struct acpi_gpe_notify_object *notify_object; 469 struct acpi_gpe_notify_info *notify;
470 470
471 ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); 471 ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
472 472
@@ -517,17 +517,17 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
517 * completes. The notify handlers are NOT invoked synchronously 517 * completes. The notify handlers are NOT invoked synchronously
518 * from this thread -- because handlers may in turn run other 518 * from this thread -- because handlers may in turn run other
519 * control methods. 519 * control methods.
520 *
521 * June 2012: Expand implicit notify mechanism to support
522 * notifies on multiple device objects.
520 */ 523 */
521 status = acpi_ev_queue_notify_request( 524 notify = local_gpe_event_info->dispatch.notify_list;
522 local_gpe_event_info->dispatch.device.node, 525 while (ACPI_SUCCESS(status) && notify) {
523 ACPI_NOTIFY_DEVICE_WAKE); 526 status =
524 527 acpi_ev_queue_notify_request(notify->device_node,
525 notify_object = local_gpe_event_info->dispatch.device.next; 528 ACPI_NOTIFY_DEVICE_WAKE);
526 while (ACPI_SUCCESS(status) && notify_object) { 529
527 status = acpi_ev_queue_notify_request( 530 notify = notify->next;
528 notify_object->node,
529 ACPI_NOTIFY_DEVICE_WAKE);
530 notify_object = notify_object->next;
531 } 531 }
532 532
533 break; 533 break;
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 3c43796b8361..0c33c62bd9eb 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -347,6 +347,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
347 void *context) 347 void *context)
348{ 348{
349 struct acpi_gpe_event_info *gpe_event_info; 349 struct acpi_gpe_event_info *gpe_event_info;
350 struct acpi_gpe_notify_info *notify;
351 struct acpi_gpe_notify_info *next;
350 u32 i; 352 u32 i;
351 u32 j; 353 u32 j;
352 354
@@ -365,10 +367,28 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
365 367
366 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == 368 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
367 ACPI_GPE_DISPATCH_HANDLER) { 369 ACPI_GPE_DISPATCH_HANDLER) {
370
371 /* Delete an installed handler block */
372
368 ACPI_FREE(gpe_event_info->dispatch.handler); 373 ACPI_FREE(gpe_event_info->dispatch.handler);
369 gpe_event_info->dispatch.handler = NULL; 374 gpe_event_info->dispatch.handler = NULL;
370 gpe_event_info->flags &= 375 gpe_event_info->flags &=
371 ~ACPI_GPE_DISPATCH_MASK; 376 ~ACPI_GPE_DISPATCH_MASK;
377 } else if ((gpe_event_info->
378 flags & ACPI_GPE_DISPATCH_MASK) ==
379 ACPI_GPE_DISPATCH_NOTIFY) {
380
381 /* Delete the implicit notification device list */
382
383 notify = gpe_event_info->dispatch.notify_list;
384 while (notify) {
385 next = notify->next;
386 ACPI_FREE(notify);
387 notify = next;
388 }
389 gpe_event_info->dispatch.notify_list = NULL;
390 gpe_event_info->flags &=
391 ~ACPI_GPE_DISPATCH_MASK;
372 } 392 }
373 } 393 }
374 } 394 }
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)