From 02f57c67a8677ae55dcdd256a2a7abaf41e4cc1f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:46 +0100 Subject: ACPI: Remove acpi_start_single_object() and acpi_bus_start() The ACPI PCI root bridge driver was the only ACPI driver implementing the .start() callback, which isn't used by any ACPI drivers any more now. For this reason, acpi_start_single_object() has no purpose any more, so remove it and all references to it. Also remove acpi_bus_start_device(), whose only purpose was to call acpi_start_single_object(). Moreover, since after the removal of acpi_bus_start_device() the only purpose of acpi_bus_start() remains to call acpi_update_all_gpes(), move that into acpi_bus_add() and drop acpi_bus_start() too, remove its header from acpi_bus.h and update all of its former users accordingly. This change was previously proposed in a different from by Yinghai Lu. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/pci/hotplug/acpiphp_glue.c | 4 +--- drivers/pci/hotplug/sgi_hotplug.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 3d6d4fd1e3c..7e2bad4c2fc 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -759,7 +759,6 @@ static int acpiphp_bus_add(struct acpiphp_func *func) -ret_val); goto acpiphp_bus_add_out; } - ret_val = acpi_bus_start(device); acpiphp_bus_add_out: return ret_val; @@ -1148,8 +1147,7 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) err("cannot add bridge to acpi list\n"); return; } - if (!acpiphp_configure_bridge(handle) && - !acpi_bus_start(device)) + if (!acpiphp_configure_bridge(handle)) add_bridge(handle); else err("cannot configure and start bridge\n"); diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f64ca92253d..20c960d5317 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -457,8 +457,6 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) ret, (int)(adr>>16), (int)(adr&0xffff)); /* try to continue on */ - } else { - acpi_bus_start(device); } } } -- cgit v1.2.3 From 636458de36f1fb4cdd318387d2f45604e451b17a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:47 +0100 Subject: ACPI: Remove the arguments of acpi_bus_add() that are not used Notice that acpi_bus_add() uses only 2 of its 4 arguments and redefine its header to match the body. Update all of its callers as necessary and observe that this leads to quite a number of removed lines of code (Linus will like that). Add a kerneldoc comment documenting acpi_bus_add() and wonder how its callers make wrong assumptions about the second argument (make note to self to take care of that later). Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/pci/hotplug/acpiphp_glue.c | 21 ++++----------------- drivers/pci/hotplug/sgi_hotplug.c | 3 +-- 2 files changed, 5 insertions(+), 19 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7e2bad4c2fc..dfc2df54b93 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -734,15 +734,9 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) */ static int acpiphp_bus_add(struct acpiphp_func *func) { - acpi_handle phandle; - struct acpi_device *device, *pdevice; + struct acpi_device *device; int ret_val; - acpi_get_parent(func->handle, &phandle); - if (acpi_bus_get_device(phandle, &pdevice)) { - dbg("no parent device, assuming NULL\n"); - pdevice = NULL; - } if (!acpi_bus_get_device(func->handle, &device)) { dbg("bus exists... trim\n"); /* this shouldn't be in here, so remove @@ -752,8 +746,7 @@ static int acpiphp_bus_add(struct acpiphp_func *func) dbg("acpi_bus_trim return %x\n", ret_val); } - ret_val = acpi_bus_add(&device, pdevice, func->handle, - ACPI_BUS_TYPE_DEVICE); + ret_val = acpi_bus_add(func->handle, &device); if (ret_val) { dbg("error adding bus, %x\n", -ret_val); @@ -1129,8 +1122,7 @@ static int acpiphp_configure_bridge (acpi_handle handle) static void handle_bridge_insertion(acpi_handle handle, u32 type) { - struct acpi_device *device, *pdevice; - acpi_handle phandle; + struct acpi_device *device; if ((type != ACPI_NOTIFY_BUS_CHECK) && (type != ACPI_NOTIFY_DEVICE_CHECK)) { @@ -1138,12 +1130,7 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) return; } - acpi_get_parent(handle, &phandle); - if (acpi_bus_get_device(phandle, &pdevice)) { - dbg("no parent device, assuming NULL\n"); - pdevice = NULL; - } - if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { + if (acpi_bus_add(handle, &device)) { err("cannot add bridge to acpi list\n"); return; } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 20c960d5317..801b58d1f78 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -448,8 +448,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { - ret = acpi_bus_add(&device, pdevice, chandle, - ACPI_BUS_TYPE_DEVICE); + ret = acpi_bus_add(chandle, &device); if (ACPI_FAILURE(ret)) { printk(KERN_ERR "%s: acpi_bus_add " "failed (0x%x) for slot %d " -- cgit v1.2.3 From 0cd6ac52b333f66ee64e50ed216ec99231092dcd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:49 +0100 Subject: ACPI: Make acpi_bus_scan() and acpi_bus_add() take only one argument The callers of acpi_bus_add() usually assume that if it has succeeded, then a struct acpi_device object has been attached to the handle passed as the first argument. Unfortunately, however, this assumption is wrong, because acpi_bus_scan(), and acpi_bus_add() too as a result, may return a pointer to a different struct acpi_device object on success (it may be an object corresponding to one of the descendant ACPI nodes in the namespace scope below that handle). For this reason, the callers of acpi_bus_add() who care about whether or not a struct acpi_device object has been created for its first argument need to check that using acpi_bus_get_device() anyway, so the second argument of acpi_bus_add() is not really useful for them. The same observation applies to acpi_bus_scan() executed directly from acpi_scan_init(). Therefore modify the relevant callers of acpi_bus_add() to check the existence of the struct acpi_device in question with the help of acpi_bus_get_device() and drop the no longer necessary second argument of acpi_bus_add(). Accordingly, modify acpi_scan_init() to use acpi_bus_get_device() to get acpi_root and drop the no longer needed second argument of acpi_bus_scan(). Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/pci/hotplug/acpiphp_glue.c | 19 +++++++++++-------- drivers/pci/hotplug/sgi_hotplug.c | 3 +-- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index dfc2df54b93..91b5ad875c5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -746,14 +746,13 @@ static int acpiphp_bus_add(struct acpiphp_func *func) dbg("acpi_bus_trim return %x\n", ret_val); } - ret_val = acpi_bus_add(func->handle, &device); - if (ret_val) { - dbg("error adding bus, %x\n", - -ret_val); - goto acpiphp_bus_add_out; - } + ret_val = acpi_bus_add(func->handle); + if (!ret_val) + ret_val = acpi_bus_get_device(func->handle, &device); + + if (ret_val) + dbg("error adding bus, %x\n", -ret_val); -acpiphp_bus_add_out: return ret_val; } @@ -1130,10 +1129,14 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) return; } - if (acpi_bus_add(handle, &device)) { + if (acpi_bus_add(handle)) { err("cannot add bridge to acpi list\n"); return; } + if (acpi_bus_get_device(handle, &device)) { + err("ACPI device object missing\n"); + return; + } if (!acpiphp_configure_bridge(handle)) add_bridge(handle); else diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 801b58d1f78..f3c419256d2 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -412,7 +412,6 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (SN_ACPI_BASE_SUPPORT() && ssdt) { unsigned long long adr; struct acpi_device *pdevice; - struct acpi_device *device; acpi_handle phandle; acpi_handle chandle = NULL; acpi_handle rethandle; @@ -448,7 +447,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { - ret = acpi_bus_add(chandle, &device); + ret = acpi_bus_add(chandle); if (ACPI_FAILURE(ret)) { printk(KERN_ERR "%s: acpi_bus_add " "failed (0x%x) for slot %d " -- cgit v1.2.3 From d2e5f0c16ad60a7208fd371233e63b73c990ece2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Dec 2012 00:02:44 +0100 Subject: ACPI / PCI: Rework the setup and cleanup of device wakeup Currently, the ACPI wakeup capability of PCI devices is set up in two different places, partially in acpi_pci_bind() where runtime wakeup is initialized and partially in platform_pci_wakeup_init(), where system wakeup is initialized. The cleanup is only done in acpi_pci_unbind() and it only covers runtime wakeup. Use the new .setup() and .cleanup() callbacks in struct acpi_bus_type to consolidate that code and do the setup and the cleanup each in one place. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/pci/pci-acpi.c | 30 +++++++++++++++++++++++++++++- drivers/pci/pci.c | 26 +------------------------- drivers/pci/pci.h | 5 ----- drivers/pci/probe.c | 1 - 4 files changed, 30 insertions(+), 32 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 1af4008182f..b98106c110e 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -283,7 +283,6 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, - .can_wakeup = acpi_pci_can_wakeup, .sleep_wake = acpi_pci_sleep_wake, .run_wake = acpi_pci_run_wake, }; @@ -321,10 +320,39 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) return 0; } +static void acpi_pci_wakeup_setup(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct pci_dev *pci_dev = to_pci_dev(dev); + + if (!adev || !adev->wakeup.flags.valid) + return; + + device_set_wakeup_capable(dev, true); + acpi_pci_sleep_wake(pci_dev, false); + + pci_acpi_add_pm_notifier(adev, pci_dev); + if (adev->wakeup.flags.run_wake) + device_set_run_wake(dev, true); +} + +static void acpi_pci_wakeup_cleanup(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + + if (adev && adev->wakeup.flags.valid) { + device_set_wakeup_capable(dev, false); + device_set_run_wake(dev, false); + pci_acpi_remove_pm_notifier(adev); + } +} + static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, .find_device = acpi_pci_find_device, .find_bridge = acpi_pci_find_root_bridge, + .setup = acpi_pci_wakeup_setup, + .cleanup = acpi_pci_wakeup_cleanup, }; static int __init acpi_pci_init(void) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5cb5820fae4..0c4f641b7be 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -450,7 +450,7 @@ static struct pci_platform_pm_ops *pci_platform_pm; int pci_set_platform_pm(struct pci_platform_pm_ops *ops) { if (!ops->is_manageable || !ops->set_state || !ops->choose_state - || !ops->sleep_wake || !ops->can_wakeup) + || !ops->sleep_wake) return -EINVAL; pci_platform_pm = ops; return 0; @@ -473,11 +473,6 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev) pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR; } -static inline bool platform_pci_can_wakeup(struct pci_dev *dev) -{ - return pci_platform_pm ? pci_platform_pm->can_wakeup(dev) : false; -} - static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) { return pci_platform_pm ? @@ -1985,25 +1980,6 @@ void pci_pm_init(struct pci_dev *dev) } } -/** - * platform_pci_wakeup_init - init platform wakeup if present - * @dev: PCI device - * - * Some devices don't have PCI PM caps but can still generate wakeup - * events through platform methods (like ACPI events). If @dev supports - * platform wakeup events, set the device flag to indicate as much. This - * may be redundant if the device also supports PCI PM caps, but double - * initialization should be safe in that case. - */ -void platform_pci_wakeup_init(struct pci_dev *dev) -{ - if (!platform_pci_can_wakeup(dev)) - return; - - device_set_wakeup_capable(&dev->dev, true); - platform_pci_sleep_wake(dev, false); -} - static void pci_add_saved_cap(struct pci_dev *pci_dev, struct pci_cap_saved_state *new_cap) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e8518292826..adfd172c5b9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -43,9 +43,6 @@ int pci_probe_reset_function(struct pci_dev *dev); * platform; to be used during system-wide transitions from a * sleeping state to the working state and vice versa * - * @can_wakeup: returns 'true' if given device is capable of waking up the - * system from a sleeping state - * * @sleep_wake: enables/disables the system wake up capability of given device * * @run_wake: enables/disables the platform to generate run-time wake-up events @@ -59,7 +56,6 @@ struct pci_platform_pm_ops { bool (*is_manageable)(struct pci_dev *dev); int (*set_state)(struct pci_dev *dev, pci_power_t state); pci_power_t (*choose_state)(struct pci_dev *dev); - bool (*can_wakeup)(struct pci_dev *dev); int (*sleep_wake)(struct pci_dev *dev, bool enable); int (*run_wake)(struct pci_dev *dev, bool enable); }; @@ -74,7 +70,6 @@ extern void pci_wakeup_bus(struct pci_bus *bus); extern void pci_config_pm_runtime_get(struct pci_dev *dev); extern void pci_config_pm_runtime_put(struct pci_dev *dev); extern void pci_pm_init(struct pci_dev *dev); -extern void platform_pci_wakeup_init(struct pci_dev *dev); extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); void pci_free_cap_save_buffers(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6186f03d84f..2dcd22d9c81 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1280,7 +1280,6 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Power Management */ pci_pm_init(dev); - platform_pci_wakeup_init(dev); /* Vital Product Data */ pci_vpd_pci22_init(dev); -- cgit v1.2.3 From 38a9a67a281eeebcd7cccf87f0e371f58ae625e3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Dec 2012 00:02:54 +0100 Subject: ACPI / PCI: Move the _PRT setup and cleanup code to pci-acpi.c Move the code related to _PRT setup and removal and to power resources from acpi_pci_bind() and acpi_pci_unbind() to the .setup() and .cleanup() callbacks in acpi_pci_bus and remove acpi_pci_bind() and acpi_pci_unbind() that have no purpose any more. Accordingly, remove the code related to device .bind() and .unbind() operations from the ACPI PCI root bridge driver. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/pci/pci-acpi.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index b98106c110e..42736e213f2 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -320,12 +320,33 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) return 0; } -static void acpi_pci_wakeup_setup(struct device *dev) +static void pci_acpi_setup(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); struct pci_dev *pci_dev = to_pci_dev(dev); + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *adev; + acpi_status status; + acpi_handle dummy; - if (!adev || !adev->wakeup.flags.valid) + /* + * Evaluate and parse _PRT, if exists. This code allows parsing of + * _PRT objects within the scope of non-bridge devices. Note that + * _PRTs within the scope of a PCI bridge assume the bridge's + * subordinate bus number. + * + * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? + */ + status = acpi_get_handle(handle, METHOD_NAME__PRT, &dummy); + if (ACPI_SUCCESS(status)) { + unsigned char bus; + + bus = pci_dev->subordinate ? + pci_dev->subordinate->number : pci_dev->bus->number; + acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus); + } + + acpi_power_resource_register_device(dev, handle); + if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) return; device_set_wakeup_capable(dev, true); @@ -336,23 +357,30 @@ static void acpi_pci_wakeup_setup(struct device *dev) device_set_run_wake(dev, true); } -static void acpi_pci_wakeup_cleanup(struct device *dev) +static void pci_acpi_cleanup(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct pci_dev *pci_dev = to_pci_dev(dev); + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *adev; - if (adev && adev->wakeup.flags.valid) { + if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) { device_set_wakeup_capable(dev, false); device_set_run_wake(dev, false); pci_acpi_remove_pm_notifier(adev); } + acpi_power_resource_unregister_device(dev, handle); + + if (pci_dev->subordinate) + acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus), + pci_dev->subordinate->number); } static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, .find_device = acpi_pci_find_device, .find_bridge = acpi_pci_find_root_bridge, - .setup = acpi_pci_wakeup_setup, - .cleanup = acpi_pci_wakeup_cleanup, + .setup = pci_acpi_setup, + .cleanup = pci_acpi_cleanup, }; static int __init acpi_pci_init(void) -- cgit v1.2.3 From ae281795ec92d35dd1631401829124acab965b1f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 15 Jan 2013 13:23:53 +0100 Subject: ACPI / scan: Drop the second argument of acpi_bus_trim() All callers of acpi_bus_trim() pass 1 (true) as the second argument of it, so remove that argument entirely and change acpi_bus_trim() to always behave as though it were 1. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yinghai Lu Acked-by: Yasuaki Ishimatsu --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++-- drivers/pci/hotplug/sgi_hotplug.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 91b5ad875c5..22006f2d9dd 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -742,7 +742,7 @@ static int acpiphp_bus_add(struct acpiphp_func *func) /* this shouldn't be in here, so remove * the bus then re-add it... */ - ret_val = acpi_bus_trim(device, 1); + ret_val = acpi_bus_trim(device); dbg("acpi_bus_trim return %x\n", ret_val); } @@ -772,7 +772,7 @@ static int acpiphp_bus_trim(acpi_handle handle) return retval; } - retval = acpi_bus_trim(device, 1); + retval = acpi_bus_trim(device); if (retval) err("cannot remove from acpi list\n"); diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f3c419256d2..2e006ee5738 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -535,7 +535,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) ret = acpi_bus_get_device(chandle, &device); if (ACPI_SUCCESS(ret)) - acpi_bus_trim(device, 1); + acpi_bus_trim(device); } } -- cgit v1.2.3 From bc9b6407bd6df3ab7189e5622816bbc11ae9d2d8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Jan 2013 14:11:05 +0100 Subject: ACPI / PM: Rework the handling of devices depending on power resources Commit 0090def6 (ACPI: Add interface to register/unregister device to/from power resources) made it possible to indicate to the ACPI core that if the given device depends on any power resources, then it should be resumed as soon as all of the power resources required by it to transition to the D0 power state have been turned on. Unfortunately, however, this was a mistake, because all devices depending on power resources should be treated this way (i.e. they should be resumed when all power resources required by their D0 state have been turned on) and for the majority of those devices the ACPI core can figure out by itself which (physical) devices depend on what power resources. For this reason, replace the code added by commit 0090def6 with a new, much more straightforward, mechanism that will be used internally by the ACPI core and remove all references to that code from kernel subsystems using ACPI. For the cases when there are (physical) devices that should be resumed whenever a not directly related ACPI device node goes into D0 as a result of power resources configuration changes, like in the SATA case, add two new routines, acpi_dev_pm_add_dependent() and acpi_dev_pm_remove_dependent(), allowing subsystems to manage such dependencies. Convert the SATA subsystem to use the new functions accordingly. Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-acpi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 42736e213f2..e407c61559c 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -345,7 +345,6 @@ static void pci_acpi_setup(struct device *dev) acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus); } - acpi_power_resource_register_device(dev, handle); if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) return; @@ -368,7 +367,6 @@ static void pci_acpi_cleanup(struct device *dev) device_set_run_wake(dev, false); pci_acpi_remove_pm_notifier(adev); } - acpi_power_resource_unregister_device(dev, handle); if (pci_dev->subordinate) acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus), -- cgit v1.2.3 From b8bd759acd05281abf88cddef30c57313c109697 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 19 Jan 2013 01:27:35 +0100 Subject: ACPI / scan: Drop acpi_bus_add() and use acpi_bus_scan() instead The only difference between acpi_bus_scan() and acpi_bus_add() is the invocation of acpi_update_all_gpes() in the latter which in fact is unnecessary, because acpi_update_all_gpes() has already been called by acpi_scan_init() and the way it is implemented guarantees the next invocations of it to do nothing. For this reason, drop acpi_bus_add() and make all its callers use acpi_bus_scan() directly instead of it. Additionally, rearrange the code in acpi_scan_init() slightly to improve the visibility of the acpi_update_all_gpes() call in there. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++-- drivers/pci/hotplug/sgi_hotplug.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 22006f2d9dd..9e2b1f6dbe4 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -746,7 +746,7 @@ static int acpiphp_bus_add(struct acpiphp_func *func) dbg("acpi_bus_trim return %x\n", ret_val); } - ret_val = acpi_bus_add(func->handle); + ret_val = acpi_bus_scan(func->handle); if (!ret_val) ret_val = acpi_bus_get_device(func->handle, &device); @@ -1129,7 +1129,7 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) return; } - if (acpi_bus_add(handle)) { + if (acpi_bus_scan(handle)) { err("cannot add bridge to acpi list\n"); return; } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 2e006ee5738..ae606b3e991 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -447,9 +447,9 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { - ret = acpi_bus_add(chandle); + ret = acpi_bus_scan(chandle); if (ACPI_FAILURE(ret)) { - printk(KERN_ERR "%s: acpi_bus_add " + printk(KERN_ERR "%s: acpi_bus_scan " "failed (0x%x) for slot %d " "func %d\n", __func__, ret, (int)(adr>>16), -- cgit v1.2.3 From bfee26dba0f373ebe4e6f0b293d078b02f9f7f69 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 26 Jan 2013 00:27:44 +0100 Subject: ACPI / scan: Make it clear that acpi_bus_trim() cannot fail Since acpi_bus_trim() cannot fail, change its definition to a void function, so that its callers don't check the return value in vain and update the callers. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Yasuaki Ishimatsu Acked-by: Toshi Kani --- drivers/pci/hotplug/acpiphp_glue.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 9e2b1f6dbe4..d1a6f4a25da 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -742,8 +742,7 @@ static int acpiphp_bus_add(struct acpiphp_func *func) /* this shouldn't be in here, so remove * the bus then re-add it... */ - ret_val = acpi_bus_trim(device); - dbg("acpi_bus_trim return %x\n", ret_val); + acpi_bus_trim(device); } ret_val = acpi_bus_scan(func->handle); @@ -772,11 +771,8 @@ static int acpiphp_bus_trim(acpi_handle handle) return retval; } - retval = acpi_bus_trim(device); - if (retval) - err("cannot remove from acpi list\n"); - - return retval; + acpi_bus_trim(device); + return 0; } static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) -- cgit v1.2.3 From 3757b94802fb65d8f696597a74053cf21738da0b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Feb 2013 14:36:47 +0100 Subject: ACPI / hotplug: Fix concurrency issues and memory leaks This changeset is aimed at fixing a few different but related problems in the ACPI hotplug infrastructure. First of all, since notify handlers may be run in parallel with acpi_bus_scan(), acpi_bus_trim() and acpi_bus_hot_remove_device() and some of them are installed for ACPI handles that have no struct acpi_device objects attached (i.e. before those objects are created), those notify handlers have to take acpi_scan_lock to prevent races from taking place (e.g. a struct acpi_device is found to be present for the given ACPI handle, but right after that it is removed by acpi_bus_trim() running in parallel to the given notify handler). Moreover, since some of them call acpi_bus_scan() and acpi_bus_trim(), this leads to the conclusion that acpi_scan_lock should be acquired by the callers of these two funtions rather by these functions themselves. For these reasons, make all notify handlers that can handle device addition and eject events take acpi_scan_lock and remove the acpi_scan_lock locking from acpi_bus_scan() and acpi_bus_trim(). Accordingly, update all of their users to make sure that they are always called under acpi_scan_lock. Furthermore, since eject operations are carried out asynchronously with respect to the notify events that trigger them, with the help of acpi_bus_hot_remove_device(), even if notify handlers take the ACPI scan lock, it still is possible that, for example, acpi_bus_trim() will run between acpi_bus_hot_remove_device() and the notify handler that scheduled its execution and that acpi_bus_trim() will remove the device node passed to acpi_bus_hot_remove_device() for ejection. In that case, the struct acpi_device object obtained by acpi_bus_hot_remove_device() will be invalid and not-so-funny things will ensue. To protect agaist that, make the users of acpi_bus_hot_remove_device() run get_device() on ACPI device node objects that are about to be passed to it and make acpi_bus_hot_remove_device() run put_device() on them and check if their ACPI handles are not NULL (make acpi_device_unregister() clear the device nodes' ACPI handles for that check to work). Finally, observe that acpi_os_hotplug_execute() actually can fail, in which case its caller ought to free memory allocated for the context object to prevent leaks from happening. It also needs to run put_device() on the device node that it ran get_device() on previously in that case. Modify the code accordingly. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/pci/hotplug/acpiphp_glue.c | 6 ++++++ drivers/pci/hotplug/sgi_hotplug.c | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d1a6f4a25da..a951c22921d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1218,6 +1218,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) handle = hp_work->handle; type = hp_work->type; + acpi_scan_lock_acquire(); + if (acpi_bus_get_device(handle, &device)) { /* This bridge must have just been physically inserted */ handle_bridge_insertion(handle, type); @@ -1295,6 +1297,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) } out: + acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ } @@ -1341,6 +1344,8 @@ static void _handle_hotplug_event_func(struct work_struct *work) func = (struct acpiphp_func *)context; + acpi_scan_lock_acquire(); + switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ @@ -1371,6 +1376,7 @@ static void _handle_hotplug_event_func(struct work_struct *work) break; } + acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_func */ } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index ae606b3e991..574421bc2fa 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -425,6 +425,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) pdevice = NULL; } + acpi_scan_lock_acquire(); /* * Walk the rootbus node's immediate children looking for * the slot's device node(s). There can be more than @@ -458,6 +459,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) } } } + acpi_scan_lock_release(); } /* Call the driver for the new device */ @@ -508,6 +510,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) /* Get the rootbus node pointer */ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; + acpi_scan_lock_acquire(); /* * Walk the rootbus node's immediate children looking for * the slot's device node(s). There can be more than @@ -538,7 +541,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) acpi_bus_trim(device); } } - + acpi_scan_lock_release(); } /* Free the SN resources assigned to the Linux device.*/ -- cgit v1.2.3