Skip to content

Commit 68bdb67

Browse files
Octavian Purdilarafaeljw
authored andcommitted
ACPI: add support for ACPI reconfiguration notifiers
Add support for ACPI reconfiguration notifiers to allow subsystems to react to changes in the ACPI tables that happen after the initial enumeration. This is similar with the way dynamic device tree notifications work. The reconfigure notifications supported for now are device add and device remove. Since ACPICA allows only one table notification handler, this patch makes the table notifier function generic and moves it out of the sysfs specific code. Signed-off-by: Octavian Purdila <[email protected]> Reviewed-by: Mika Westerberg <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 10c7e20 commit 68bdb67

File tree

5 files changed

+99
-5
lines changed

5 files changed

+99
-5
lines changed

drivers/acpi/bus.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,13 @@ void __init acpi_subsystem_init(void)
990990
}
991991
}
992992

993+
static acpi_status acpi_bus_table_handler(u32 event, void *table, void *context)
994+
{
995+
acpi_scan_table_handler(event, table, context);
996+
997+
return acpi_sysfs_table_handler(event, table, context);
998+
}
999+
9931000
static int __init acpi_bus_init(void)
9941001
{
9951002
int result;
@@ -1043,6 +1050,8 @@ static int __init acpi_bus_init(void)
10431050
* _PDC control method may load dynamic SSDT tables,
10441051
* and we need to install the table handler before that.
10451052
*/
1053+
status = acpi_install_table_handler(acpi_bus_table_handler, NULL);
1054+
10461055
acpi_sysfs_init();
10471056

10481057
acpi_early_processor_set_pdc();

drivers/acpi/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ bool acpi_queue_hotplug_work(struct work_struct *work);
8787
void acpi_device_hotplug(struct acpi_device *adev, u32 src);
8888
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
8989

90+
acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context);
91+
void acpi_scan_table_handler(u32 event, void *table, void *context);
92+
9093
/* --------------------------------------------------------------------------
9194
Device Node Initialization / Removal
9295
-------------------------------------------------------------------------- */

drivers/acpi/scan.c

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ static void acpi_device_del(struct acpi_device *device)
494494
device_del(&device->dev);
495495
}
496496

497+
static BLOCKING_NOTIFIER_HEAD(acpi_reconfig_chain);
498+
497499
static LIST_HEAD(acpi_device_del_list);
498500
static DEFINE_MUTEX(acpi_device_del_lock);
499501

@@ -514,6 +516,9 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used)
514516

515517
mutex_unlock(&acpi_device_del_lock);
516518

519+
blocking_notifier_call_chain(&acpi_reconfig_chain,
520+
ACPI_RECONFIG_DEVICE_REMOVE, adev);
521+
517522
acpi_device_del(adev);
518523
/*
519524
* Drop references to all power resources that might have been
@@ -1676,7 +1681,7 @@ static void acpi_default_enumeration(struct acpi_device *device)
16761681
bool is_spi_i2c_slave = false;
16771682

16781683
/*
1679-
* Do not enemerate SPI/I2C slaves as they will be enuerated by their
1684+
* Do not enumerate SPI/I2C slaves as they will be enumerated by their
16801685
* respective parents.
16811686
*/
16821687
INIT_LIST_HEAD(&resource_list);
@@ -1686,6 +1691,9 @@ static void acpi_default_enumeration(struct acpi_device *device)
16861691
if (!is_spi_i2c_slave) {
16871692
acpi_create_platform_device(device);
16881693
acpi_device_set_enumerated(device);
1694+
} else {
1695+
blocking_notifier_call_chain(&acpi_reconfig_chain,
1696+
ACPI_RECONFIG_DEVICE_ADD, device);
16891697
}
16901698
}
16911699

@@ -1917,6 +1925,8 @@ static int acpi_bus_scan_fixed(void)
19171925
return result < 0 ? result : 0;
19181926
}
19191927

1928+
static bool acpi_scan_initialized;
1929+
19201930
int __init acpi_scan_init(void)
19211931
{
19221932
int result;
@@ -1961,6 +1971,8 @@ int __init acpi_scan_init(void)
19611971

19621972
acpi_update_all_gpes();
19631973

1974+
acpi_scan_initialized = true;
1975+
19641976
out:
19651977
mutex_unlock(&acpi_scan_lock);
19661978
return result;
@@ -2004,3 +2016,57 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
20042016

20052017
return count;
20062018
}
2019+
2020+
struct acpi_table_events_work {
2021+
struct work_struct work;
2022+
void *table;
2023+
u32 event;
2024+
};
2025+
2026+
static void acpi_table_events_fn(struct work_struct *work)
2027+
{
2028+
struct acpi_table_events_work *tew;
2029+
2030+
tew = container_of(work, struct acpi_table_events_work, work);
2031+
2032+
if (tew->event == ACPI_TABLE_EVENT_LOAD) {
2033+
acpi_scan_lock_acquire();
2034+
acpi_bus_scan(ACPI_ROOT_OBJECT);
2035+
acpi_scan_lock_release();
2036+
}
2037+
2038+
kfree(tew);
2039+
}
2040+
2041+
void acpi_scan_table_handler(u32 event, void *table, void *context)
2042+
{
2043+
struct acpi_table_events_work *tew;
2044+
2045+
if (!acpi_scan_initialized)
2046+
return;
2047+
2048+
if (event != ACPI_TABLE_EVENT_LOAD)
2049+
return;
2050+
2051+
tew = kmalloc(sizeof(*tew), GFP_KERNEL);
2052+
if (!tew)
2053+
return;
2054+
2055+
INIT_WORK(&tew->work, acpi_table_events_fn);
2056+
tew->table = table;
2057+
tew->event = event;
2058+
2059+
schedule_work(&tew->work);
2060+
}
2061+
2062+
int acpi_reconfig_notifier_register(struct notifier_block *nb)
2063+
{
2064+
return blocking_notifier_chain_register(&acpi_reconfig_chain, nb);
2065+
}
2066+
EXPORT_SYMBOL(acpi_reconfig_notifier_register);
2067+
2068+
int acpi_reconfig_notifier_unregister(struct notifier_block *nb)
2069+
{
2070+
return blocking_notifier_chain_unregister(&acpi_reconfig_chain, nb);
2071+
}
2072+
EXPORT_SYMBOL(acpi_reconfig_notifier_unregister);

drivers/acpi/sysfs.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
378378
return;
379379
}
380380

381-
static acpi_status
382-
acpi_sysfs_table_handler(u32 event, void *table, void *context)
381+
acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
383382
{
384383
struct acpi_table_attr *table_attr;
385384

@@ -452,9 +451,8 @@ static int acpi_tables_sysfs_init(void)
452451

453452
kobject_uevent(tables_kobj, KOBJ_ADD);
454453
kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);
455-
status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL);
456454

457-
return ACPI_FAILURE(status) ? -EINVAL : 0;
455+
return 0;
458456
err_dynamic_tables:
459457
kobject_put(tables_kobj);
460458
err:

include/linux/acpi.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,14 @@ static inline void acpi_device_clear_enumerated(struct acpi_device *adev)
541541
adev->flags.visited = false;
542542
}
543543

544+
enum acpi_reconfig_event {
545+
ACPI_RECONFIG_DEVICE_ADD = 0,
546+
ACPI_RECONFIG_DEVICE_REMOVE,
547+
};
548+
549+
int acpi_reconfig_notifier_register(struct notifier_block *nb);
550+
int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
551+
544552
#else /* !CONFIG_ACPI */
545553

546554
#define acpi_disabled 1
@@ -694,6 +702,16 @@ static inline void acpi_device_clear_enumerated(struct acpi_device *adev)
694702
{
695703
}
696704

705+
static inline int acpi_reconfig_notifier_register(struct notifier_block *nb)
706+
{
707+
return -EINVAL;
708+
}
709+
710+
static inline int acpi_reconfig_notifier_unregister(struct notifier_block *nb)
711+
{
712+
return -EINVAL;
713+
}
714+
697715
#endif /* !CONFIG_ACPI */
698716

699717
#ifdef CONFIG_ACPI

0 commit comments

Comments
 (0)