Skip to content

Commit 3f0be67

Browse files
rjwysockijbarnes993
authored andcommitted
ACPI / ACPICA: Multiple system notify handlers per device
Currently it only is possible to install one system notify handler per namespace node, but this is not enough for PCI run-time power management, because we need to install power management notifiers for devices that already have hotplug notifiers installed. While in principle this could be handled at the PCI level, that would be suboptimal due to the way in which the ACPI-based PCI hotplug code is designed. For this reason, modify ACPICA so that it is possible to install more than one system notify handler per namespace node. Namely, make acpi_install_notify_handler(), acpi_remove_notify_handler() and acpi_ev_notify_dispatch() use a list of system notify handler objects associated with a namespace node. Make acpi_remove_notify_handler() call acpi_os_wait_events_complete() upfront to avoid a situation in which concurrent instance of acpi_remove_notify_handler() removes the handler from under us while we're waiting for the event queues to flush. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
1 parent f517709 commit 3f0be67

File tree

3 files changed

+150
-39
lines changed

3 files changed

+150
-39
lines changed

drivers/acpi/acpica/acobject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,10 @@ struct acpi_object_buffer_field {
287287

288288
struct acpi_object_notify_handler {
289289
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
290+
u32 handler_type;
290291
acpi_notify_handler handler;
291292
void *context;
293+
struct acpi_object_notify_handler *next;
292294
};
293295

294296
struct acpi_object_addr_handler {

drivers/acpi/acpica/evmisc.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,15 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
259259

260260
handler_obj = notify_info->notify.handler_obj;
261261
if (handler_obj) {
262-
handler_obj->notify.handler(notify_info->notify.node,
263-
notify_info->notify.value,
264-
handler_obj->notify.context);
262+
struct acpi_object_notify_handler *notifier;
263+
264+
notifier = &handler_obj->notify;
265+
while (notifier) {
266+
notifier->handler(notify_info->notify.node,
267+
notify_info->notify.value,
268+
notifier->context);
269+
notifier = notifier->next;
270+
}
265271
}
266272

267273
/* All done with the info object */

drivers/acpi/acpica/evxface.c

Lines changed: 139 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,72 @@ acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
216216

217217
ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
218218

219+
/*******************************************************************************
220+
*
221+
* FUNCTION: acpi_populate_handler_object
222+
*
223+
* PARAMETERS: handler_obj - Handler object to populate
224+
* handler_type - The type of handler:
225+
* ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
226+
* ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
227+
* ACPI_ALL_NOTIFY: both system and device
228+
* handler - Address of the handler
229+
* context - Value passed to the handler on each GPE
230+
* next - Address of a handler object to link to
231+
*
232+
* RETURN: None
233+
*
234+
* DESCRIPTION: Populate a handler object.
235+
*
236+
******************************************************************************/
237+
static void
238+
acpi_populate_handler_object(struct acpi_object_notify_handler *handler_obj,
239+
u32 handler_type,
240+
acpi_notify_handler handler, void *context,
241+
struct acpi_object_notify_handler *next)
242+
{
243+
handler_obj->handler_type = handler_type;
244+
handler_obj->handler = handler;
245+
handler_obj->context = context;
246+
handler_obj->next = next;
247+
}
248+
249+
/*******************************************************************************
250+
*
251+
* FUNCTION: acpi_add_handler_object
252+
*
253+
* PARAMETERS: parent_obj - Parent of the new object
254+
* handler - Address of the handler
255+
* context - Value passed to the handler on each GPE
256+
*
257+
* RETURN: Status
258+
*
259+
* DESCRIPTION: Create a new handler object and populate it.
260+
*
261+
******************************************************************************/
262+
static acpi_status
263+
acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj,
264+
acpi_notify_handler handler, void *context)
265+
{
266+
struct acpi_object_notify_handler *handler_obj;
267+
268+
/* The parent must not be a defice notify handler object. */
269+
if (parent_obj->handler_type & ACPI_DEVICE_NOTIFY)
270+
return AE_BAD_PARAMETER;
271+
272+
handler_obj = ACPI_ALLOCATE_ZEROED(sizeof(*handler_obj));
273+
if (!handler_obj)
274+
return AE_NO_MEMORY;
275+
276+
acpi_populate_handler_object(handler_obj,
277+
ACPI_SYSTEM_NOTIFY,
278+
handler, context,
279+
parent_obj->next);
280+
parent_obj->next = handler_obj;
281+
282+
return AE_OK;
283+
}
284+
219285
/*******************************************************************************
220286
*
221287
* FUNCTION: acpi_install_notify_handler
@@ -316,15 +382,32 @@ acpi_install_notify_handler(acpi_handle device,
316382
obj_desc = acpi_ns_get_attached_object(node);
317383
if (obj_desc) {
318384

319-
/* Object exists - make sure there's no handler */
385+
/* Object exists. */
320386

321-
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
322-
obj_desc->common_notify.system_notify) ||
323-
((handler_type & ACPI_DEVICE_NOTIFY) &&
324-
obj_desc->common_notify.device_notify)) {
387+
/* For a device notify, make sure there's no handler. */
388+
if ((handler_type & ACPI_DEVICE_NOTIFY) &&
389+
obj_desc->common_notify.device_notify) {
325390
status = AE_ALREADY_EXISTS;
326391
goto unlock_and_exit;
327392
}
393+
394+
/* System notifies may have more handlers installed. */
395+
notify_obj = obj_desc->common_notify.system_notify;
396+
397+
if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) {
398+
struct acpi_object_notify_handler *parent_obj;
399+
400+
if (handler_type & ACPI_DEVICE_NOTIFY) {
401+
status = AE_ALREADY_EXISTS;
402+
goto unlock_and_exit;
403+
}
404+
405+
parent_obj = &notify_obj->notify;
406+
status = acpi_add_handler_object(parent_obj,
407+
handler,
408+
context);
409+
goto unlock_and_exit;
410+
}
328411
} else {
329412
/* Create a new object */
330413

@@ -356,9 +439,10 @@ acpi_install_notify_handler(acpi_handle device,
356439
goto unlock_and_exit;
357440
}
358441

359-
notify_obj->notify.node = node;
360-
notify_obj->notify.handler = handler;
361-
notify_obj->notify.context = context;
442+
acpi_populate_handler_object(&notify_obj->notify,
443+
handler_type,
444+
handler, context,
445+
NULL);
362446

363447
if (handler_type & ACPI_SYSTEM_NOTIFY) {
364448
obj_desc->common_notify.system_notify = notify_obj;
@@ -418,6 +502,10 @@ acpi_remove_notify_handler(acpi_handle device,
418502
goto exit;
419503
}
420504

505+
506+
/* Make sure all deferred tasks are completed */
507+
acpi_os_wait_events_complete(NULL);
508+
421509
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
422510
if (ACPI_FAILURE(status)) {
423511
goto exit;
@@ -445,15 +533,6 @@ acpi_remove_notify_handler(acpi_handle device,
445533
goto unlock_and_exit;
446534
}
447535

448-
/* Make sure all deferred tasks are completed */
449-
450-
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
451-
acpi_os_wait_events_complete(NULL);
452-
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
453-
if (ACPI_FAILURE(status)) {
454-
goto exit;
455-
}
456-
457536
if (handler_type & ACPI_SYSTEM_NOTIFY) {
458537
acpi_gbl_system_notify.node = NULL;
459538
acpi_gbl_system_notify.handler = NULL;
@@ -488,28 +567,60 @@ acpi_remove_notify_handler(acpi_handle device,
488567
/* Object exists - make sure there's an existing handler */
489568

490569
if (handler_type & ACPI_SYSTEM_NOTIFY) {
570+
struct acpi_object_notify_handler *handler_obj;
571+
struct acpi_object_notify_handler *parent_obj;
572+
491573
notify_obj = obj_desc->common_notify.system_notify;
492574
if (!notify_obj) {
493575
status = AE_NOT_EXIST;
494576
goto unlock_and_exit;
495577
}
496578

497-
if (notify_obj->notify.handler != handler) {
579+
handler_obj = &notify_obj->notify;
580+
parent_obj = NULL;
581+
while (handler_obj->handler != handler) {
582+
if (handler_obj->next) {
583+
parent_obj = handler_obj;
584+
handler_obj = handler_obj->next;
585+
} else {
586+
break;
587+
}
588+
}
589+
590+
if (handler_obj->handler != handler) {
498591
status = AE_BAD_PARAMETER;
499592
goto unlock_and_exit;
500593
}
501-
/* Make sure all deferred tasks are completed */
502594

503-
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
504-
acpi_os_wait_events_complete(NULL);
505-
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
506-
if (ACPI_FAILURE(status)) {
507-
goto exit;
595+
/*
596+
* Remove the handler. There are three possible cases.
597+
* First, we may need to remove a non-embedded object.
598+
* Second, we may need to remove the embedded object's
599+
* handler data, while non-embedded objects exist.
600+
* Finally, we may need to remove the embedded object
601+
* entirely along with its container.
602+
*/
603+
if (parent_obj) {
604+
/* Non-embedded object is being removed. */
605+
parent_obj->next = handler_obj->next;
606+
ACPI_FREE(handler_obj);
607+
} else if (notify_obj->notify.next) {
608+
/*
609+
* The handler matches the embedded object, but
610+
* there are more handler objects in the list.
611+
* Replace the embedded object's data with the
612+
* first next object's data and remove that
613+
* object.
614+
*/
615+
parent_obj = &notify_obj->notify;
616+
handler_obj = notify_obj->notify.next;
617+
*parent_obj = *handler_obj;
618+
ACPI_FREE(handler_obj);
619+
} else {
620+
/* No more handler objects in the list. */
621+
obj_desc->common_notify.system_notify = NULL;
622+
acpi_ut_remove_reference(notify_obj);
508623
}
509-
510-
/* Remove the handler */
511-
obj_desc->common_notify.system_notify = NULL;
512-
acpi_ut_remove_reference(notify_obj);
513624
}
514625

515626
if (handler_type & ACPI_DEVICE_NOTIFY) {
@@ -523,14 +634,6 @@ acpi_remove_notify_handler(acpi_handle device,
523634
status = AE_BAD_PARAMETER;
524635
goto unlock_and_exit;
525636
}
526-
/* Make sure all deferred tasks are completed */
527-
528-
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
529-
acpi_os_wait_events_complete(NULL);
530-
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
531-
if (ACPI_FAILURE(status)) {
532-
goto exit;
533-
}
534637

535638
/* Remove the handler */
536639
obj_desc->common_notify.device_notify = NULL;

0 commit comments

Comments
 (0)