* [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently @ 2014-01-27 0:37 Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 1/11] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki ` (13 more replies) 0 siblings, 14 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:37 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg Hi All, ACPIPHP can be simplified a bit on top of some PCI and ACPI changes merged recently and the following series of patches implements those simplifications: [1/11] Fix up two kerneldoc comments in acpiphp_glue.c. [2/11] Get rid of an unnecessary label in register_slot(). [3/11] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. [4/11] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). [5/11] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. [6/11] Drop acpiphp_bus_add() (which has only one user). [7/11] Drop crit_sect mutexes (that are redundant). [8/11] Clean up the usage of the slot variable in hotplug_event(). [9/11] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. [10/11] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. [11/11] Drop handle argument from the member functions of struct acpi_dock_ops. All of that is relateively straightforward, but I have some more intrusive changes on top of it in the works. They will be posted separately later this week. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 1/11] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki @ 2014-01-27 0:38 ` Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 2/11] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki ` (12 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:38 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Add proper kerneldoc comments describing acpiphp_enumerate_slots() and acpiphp_remove_slots(). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -986,9 +986,12 @@ static void handle_hotplug_event(acpi_ha acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -/* - * Create hotplug slots for the PCI bus. - * It should always return 0 to avoid skipping following notifiers. +/** + * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. + * @bus: PCI bus to enumerate the slots for. + * + * A "slot" is an object associated with a PCI device number. All functions + * (PCI devices) with the same bus and device number belong to the same slot. */ void acpiphp_enumerate_slots(struct pci_bus *bus) { @@ -1061,7 +1064,10 @@ void acpiphp_enumerate_slots(struct pci_ } } -/* Destroy hotplug slots associated with the PCI bus */ +/** + * acpiphp_remove_slots - Remove slot objects associated with a given bus. + * @bus: PCI bus to remove the slot objects for. + */ void acpiphp_remove_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 2/11] ACPI / hotplug / PCI: Simplify register_slot() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 1/11] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki @ 2014-01-27 0:38 ` Rafael J. Wysocki 2014-01-27 0:39 ` [PATCH 3/11] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki ` (11 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:38 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The err label in register_slot() is only jumped to from one place, so move the code under the label to that place and drop the label. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -316,8 +316,10 @@ static acpi_status register_slot(acpi_ha slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - status = AE_NO_MEMORY; - goto err; + mutex_lock(&acpiphp_context_lock); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + return AE_NO_MEMORY; } slot->bus = bridge->pci_bus; @@ -385,12 +387,6 @@ static acpi_status register_slot(acpi_ha } return AE_OK; - - err: - mutex_lock(&acpiphp_context_lock); - acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); - return status; } static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 3/11] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 1/11] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 2/11] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki @ 2014-01-27 0:39 ` Rafael J. Wysocki 2014-01-27 0:40 ` [PATCH 4/11] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki ` (10 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:39 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If trim_stale_devices() calls acpi_bus_trim() directly, we can save a potentially costly acpi_bus_get_device() invocation. After making that change acpiphp_bus_trim() would only be called from one place, so move the code from it to that place and drop it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -468,19 +468,6 @@ static unsigned char acpiphp_max_busnr(s } /** - * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. - * @handle: ACPI device object handle to start from. - */ -static void acpiphp_bus_trim(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) - acpi_bus_trim(adev); -} - -/** * acpiphp_bus_add - Scan ACPI namespace subtree. * @handle: ACPI object handle to start the scan from. */ @@ -638,8 +625,12 @@ static void disable_slot(struct acpiphp_ pci_dev_put(pdev); } - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_trim(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev; + + if (!acpi_bus_get_device(func_to_handle(func), &adev)) + acpi_bus_trim(adev); + } slot->flags &= (~SLOT_ENABLED); } @@ -711,11 +702,12 @@ static unsigned int get_slot_status(stru */ static void trim_stale_devices(struct pci_dev *dev) { - acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); struct pci_bus *bus = dev->subordinate; bool alive = false; - if (handle) { + if (adev) { + acpi_handle handle = adev->handle; acpi_status status; unsigned long long sta; @@ -731,8 +723,8 @@ static void trim_stale_devices(struct pc } if (!alive) { pci_stop_and_remove_bus_device(dev); - if (handle) - acpiphp_bus_trim(handle); + if (adev) + acpi_bus_trim(adev); } else if (bus) { struct pci_dev *child, *tmp; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 4/11] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (2 preceding siblings ...) 2014-01-27 0:39 ` [PATCH 3/11] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki @ 2014-01-27 0:40 ` Rafael J. Wysocki 2014-01-27 0:41 ` [PATCH 5/11] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki ` (9 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:40 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If a struct acpi_device pointer is passed to acpiphp_no_hotplug() instead of an ACPI handle, the function won't need to call acpi_bus_get_device(), which may be costly, any more. Then, trim_stale_devices() can call acpiphp_no_hotplug() passing the struct acpi_device object it already has directly to that function. Make those changes and update slot_no_hotplug() accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -635,11 +635,8 @@ static void disable_slot(struct acpiphp_ slot->flags &= (~SLOT_ENABLED); } -static bool acpiphp_no_hotplug(acpi_handle handle) +static bool acpiphp_no_hotplug(struct acpi_device *adev) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); return adev && adev->flags.no_hotplug; } @@ -647,10 +644,13 @@ static bool slot_no_hotplug(struct acpip { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - if (acpiphp_no_hotplug(func_to_handle(func))) - return true; + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = NULL; + acpi_bus_get_device(func_to_handle(func), &adev); + if (acpiphp_no_hotplug(adev)) + return true; + } return false; } @@ -707,13 +707,12 @@ static void trim_stale_devices(struct pc bool alive = false; if (adev) { - acpi_handle handle = adev->handle; acpi_status status; unsigned long long sta; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) - || acpiphp_no_hotplug(handle); + || acpiphp_no_hotplug(adev); } if (!alive) { u32 v; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 5/11] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (3 preceding siblings ...) 2014-01-27 0:40 ` [PATCH 4/11] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki @ 2014-01-27 0:41 ` Rafael J. Wysocki 2014-01-27 0:41 ` [PATCH 6/11] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki ` (8 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:41 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent modifications of the ACPI core making it create a struct acpi_device object for every namespace node representing a device regardless of the current status of that device the ACPIPHP code can store a struct acpi_device pointer instead of an ACPI handle in struct acpiphp_context. This immediately makes it possible to avoid making potentially costly calls to acpi_bus_get_device() in two places and allows some more simplifications to be made going forward. The reason why that is correct is because ACPIPHP only installs hotify handlers for namespace nodes that exist when acpiphp_enumerate_slots() is called for their parent bridge. That only happens if the parent bridge has an ACPI companion associated with it, which means that the ACPI namespace scope in question has been scanned already at that point. That, in turn, means that struct acpi_device objects have been created for all namespace nodes in that scope and pointers to those objects can be stored directly instead of their ACPI handles. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp.h | 9 +++++-- drivers/pci/hotplug/acpiphp_glue.c | 44 +++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 25 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -117,8 +117,8 @@ struct acpiphp_func { }; struct acpiphp_context { - acpi_handle handle; struct acpiphp_func func; + struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; @@ -128,9 +128,14 @@ static inline struct acpiphp_context *fu return container_of(func, struct acpiphp_context, func); } +static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) +{ + return func_to_context(func)->adev; +} + static inline acpi_handle func_to_handle(struct acpiphp_func *func) { - return func_to_context(func)->handle; + return func_to_acpi_device(func)->handle; } /* Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -73,11 +73,11 @@ static void acpiphp_context_handler(acpi /** * acpiphp_init_context - Create hotplug context and grab a reference to it. - * @handle: ACPI object handle to create the context for. + * @adev: ACPI device object to create the context for. * * Call under acpiphp_context_lock. */ -static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; acpi_status status; @@ -86,9 +86,9 @@ static struct acpiphp_context *acpiphp_i if (!context) return NULL; - context->handle = handle; + context->adev = adev; context->refcount = 1; - status = acpi_attach_data(handle, acpiphp_context_handler, context); + status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); if (ACPI_FAILURE(status)) { kfree(context); return NULL; @@ -118,7 +118,7 @@ static struct acpiphp_context *acpiphp_g /** * acpiphp_put_context - Drop a reference to ACPI hotplug context. - * @handle: ACPI object handle to put the context for. + * @context: ACPI hotplug context to drop a reference to. * * The context object is removed if there are no more references to it. * @@ -130,7 +130,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->handle, acpiphp_context_handler); + acpi_detach_data(context->adev->handle, acpiphp_context_handler); kfree(context); } @@ -265,6 +265,7 @@ static acpi_status register_slot(acpi_ha { struct acpiphp_bridge *bridge = data; struct acpiphp_context *context; + struct acpi_device *adev; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -284,12 +285,14 @@ static acpi_status register_slot(acpi_ha "can't evaluate _ADR (%#x)\n", status); return AE_OK; } + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; device = (adr >> 16) & 0xffff; function = adr & 0xffff; mutex_lock(&acpiphp_context_lock); - context = acpiphp_init_context(handle); + context = acpiphp_init_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); acpi_handle_err(handle, "No hotplug context\n"); @@ -625,12 +628,8 @@ static void disable_slot(struct acpiphp_ pci_dev_put(pdev); } - list_for_each_entry(func, &slot->funcs, sibling) { - struct acpi_device *adev; - - if (!acpi_bus_get_device(func_to_handle(func), &adev)) - acpi_bus_trim(adev); - } + list_for_each_entry(func, &slot->funcs, sibling) + acpi_bus_trim(func_to_acpi_device(func)); slot->flags &= (~SLOT_ENABLED); } @@ -644,13 +643,10 @@ static bool slot_no_hotplug(struct acpip { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(func_to_handle(func), &adev); - if (acpiphp_no_hotplug(adev)) + list_for_each_entry(func, &slot->funcs, sibling) + if (acpiphp_no_hotplug(func_to_acpi_device(func))) return true; - } + return false; } @@ -899,7 +895,7 @@ static void hotplug_event(acpi_handle ha static void hotplug_event_work(void *data, u32 type) { struct acpiphp_context *context = data; - acpi_handle handle = context->handle; + acpi_handle handle = context->adev->handle; acpi_scan_lock_acquire(); pci_lock_rescan_remove(); @@ -959,7 +955,7 @@ static void handle_hotplug_event(acpi_ha mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->handle != handle)) { + if (context && !WARN_ON(context->adev->handle != handle)) { get_bridge(context->func.parent); acpiphp_put_context(context); acpi_hotplug_execute(hotplug_event_work, context, type); @@ -983,16 +979,18 @@ static void handle_hotplug_event(acpi_ha void acpiphp_enumerate_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; + struct acpi_device *adev; acpi_handle handle; acpi_status status; if (acpiphp_disabled) return; - handle = ACPI_HANDLE(bus->bridge); - if (!handle) + adev = ACPI_COMPANION(bus->bridge); + if (!adev) return; + handle = adev->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (!bridge) { acpi_handle_err(handle, "No memory for bridge object\n"); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 6/11] ACPI / hotplug / PCI: Drop acpiphp_bus_add() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (4 preceding siblings ...) 2014-01-27 0:41 ` [PATCH 5/11] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki @ 2014-01-27 0:41 ` Rafael J. Wysocki 2014-01-27 0:42 ` [PATCH 7/11] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki ` (7 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:41 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> acpiphp_bus_add() is only called from one place, so move the code out of it into that place and drop it. Also make that code use func_to_acpi_device() to get the struct acpi_device pointer it needs instead of calling acpi_bus_get_device() which may be costly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -470,20 +470,6 @@ static unsigned char acpiphp_max_busnr(s return max; } -/** - * acpiphp_bus_add - Scan ACPI namespace subtree. - * @handle: ACPI object handle to start the scan from. - */ -static void acpiphp_bus_add(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_scan(handle); - acpi_bus_get_device(handle, &adev); - if (acpi_device_enumerated(adev)) - acpi_device_set_power(adev, ACPI_STATE_D0); -} - static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) { struct acpiphp_func *func; @@ -523,9 +509,13 @@ static int acpiphp_rescan_slot(struct ac { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); + acpi_bus_scan(adev->handle); + if (acpi_device_enumerated(adev)) + acpi_device_set_power(adev, ACPI_STATE_D0); + } return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 7/11] ACPI / hotplug / PCI: Drop crit_sect locking 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (5 preceding siblings ...) 2014-01-27 0:41 ` [PATCH 6/11] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki @ 2014-01-27 0:42 ` Rafael J. Wysocki 2014-01-27 0:43 ` [PATCH 8/11] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki ` (6 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:42 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent PCI core changes related to the rescan/remove locking, the code sections under crit_sect mutexes from ACPIPHP slot objects are always executed under the general PCI rescan/remove lock. For this reason, the crit_sect mutexes are simply redundant, so drop them. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 23 +++-------------------- 2 files changed, 3 insertions(+), 21 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -328,7 +328,6 @@ static acpi_status register_slot(acpi_ha slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); list_add_tail(&slot->node, &bridge->slots); @@ -741,7 +740,6 @@ static void acpiphp_check_bridge(struct struct pci_bus *bus = slot->bus; struct pci_dev *dev, *tmp; - mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ } else if (get_slot_status(slot) == ACPI_STA_ALL) { @@ -756,7 +754,6 @@ static void acpiphp_check_bridge(struct } else { disable_slot(slot); } - mutex_unlock(&slot->crit_sect); } } @@ -838,12 +835,8 @@ static void hotplug_event(acpi_handle ha } else { struct acpiphp_slot *slot = func->slot; - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - - mutex_lock(&slot->crit_sect); - enable_slot(slot); - mutex_unlock(&slot->crit_sect); + if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); } break; @@ -854,7 +847,6 @@ static void hotplug_event(acpi_handle ha acpiphp_check_bridge(bridge); } else { struct acpiphp_slot *slot = func->slot; - int ret; if (slot->flags & SLOT_IS_GOING_AWAY) break; @@ -863,10 +855,7 @@ static void hotplug_event(acpi_handle ha * Check if anything has changed in the slot and rescan * from the parent if that's the case. */ - mutex_lock(&slot->crit_sect); - ret = acpiphp_rescan_slot(slot); - mutex_unlock(&slot->crit_sect); - if (ret) + if (acpiphp_rescan_slot(slot)) acpiphp_check_bridge(func->parent); } break; @@ -1073,13 +1062,10 @@ int acpiphp_enable_slot(struct acpiphp_s if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - pci_unlock_rescan_remove(); return 0; } @@ -1095,8 +1081,6 @@ static int acpiphp_disable_and_eject_slo if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); - /* unconfigure all functions */ disable_slot(slot); @@ -1110,7 +1094,6 @@ static int acpiphp_disable_and_eject_slo break; } - mutex_unlock(&slot->crit_sect); return 0; } Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -93,7 +93,6 @@ struct acpiphp_slot { struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; - struct mutex crit_sect; u8 device; /* pci device# */ u32 flags; /* see below */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 8/11] ACPI / hotplug / PCI: Simplify hotplug_event() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (6 preceding siblings ...) 2014-01-27 0:42 ` [PATCH 7/11] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki @ 2014-01-27 0:43 ` Rafael J. Wysocki 2014-01-27 0:44 ` [PATCH 9/11] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki ` (5 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:43 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> A few lines of code can be cut from hotplug_event() by defining and initializing the slot variable at the top of the function, so do that. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -810,6 +810,7 @@ static void hotplug_event(acpi_handle ha { struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; + struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -830,14 +831,11 @@ static void hotplug_event(acpi_handle ha pr_debug("%s: Bus check notify on %s\n", __func__, objname); pr_debug("%s: re-enumerating slots under %s\n", __func__, objname); - if (bridge) { + if (bridge) acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; + else if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); - if (!(slot->flags & SLOT_IS_GOING_AWAY)) - enable_slot(slot); - } break; case ACPI_NOTIFY_DEVICE_CHECK: @@ -845,12 +843,7 @@ static void hotplug_event(acpi_handle ha pr_debug("%s: Device check notify on %s\n", __func__, objname); if (bridge) { acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - + } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { /* * Check if anything has changed in the slot and rescan * from the parent if that's the case. @@ -863,7 +856,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ pr_debug("%s: Device eject notify on %s\n", __func__, objname); - acpiphp_disable_and_eject_slot(func->slot); + acpiphp_disable_and_eject_slot(slot); break; } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 9/11] ACPI / hotplug / PCI: Simplify disable_slot() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (7 preceding siblings ...) 2014-01-27 0:43 ` [PATCH 8/11] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki @ 2014-01-27 0:44 ` Rafael J. Wysocki 2014-01-27 0:45 ` [PATCH 10/11] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki ` (4 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:44 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent PCI core changes related to the rescan/remove locking, the ACPIPHP's disable_slot() function is only called under the general PCI rescan/remove lock, so it doesn't have to use dev_in_slot() any more to avoid race conditions. Make it simply walk the devices on the bus and remove the ones in the slot being disabled. Then, drop dev_in_slot() which has no more users. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -579,32 +579,15 @@ static void __ref enable_slot(struct acp } } -/* return first device in slot, acquiring a reference on it */ -static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *dev; - struct pci_dev *ret = NULL; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot->device) { - ret = pci_dev_get(dev); - break; - } - up_read(&pci_bus_sem); - - return ret; -} - /** * disable_slot - disable a slot * @slot: ACPI PHP slot */ static void disable_slot(struct acpiphp_slot *slot) { + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *next; struct acpiphp_func *func; - struct pci_dev *pdev; /* * enable_slot() enumerates all functions in this device via @@ -612,10 +595,9 @@ static void disable_slot(struct acpiphp_ * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. */ - while ((pdev = dev_in_slot(slot))) { - pci_stop_and_remove_bus_device(pdev); - pci_dev_put(pdev); - } + list_for_each_entry_safe(dev, next, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + pci_stop_and_remove_bus_device(dev); list_for_each_entry(func, &slot->funcs, sibling) acpi_bus_trim(func_to_acpi_device(func)); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 10/11] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (8 preceding siblings ...) 2014-01-27 0:44 ` [PATCH 9/11] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki @ 2014-01-27 0:45 ` Rafael J. Wysocki 2014-01-27 0:46 ` [PATCH 11/11] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations Rafael J. Wysocki ` (3 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:45 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Make hotplug_event() use acpi_handle_debug() instead of an open-coded debug message printing and clean up the messages printed by it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -794,9 +794,6 @@ static void hotplug_event(acpi_handle ha struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; mutex_lock(&acpiphp_context_lock); bridge = context->bridge; @@ -805,14 +802,10 @@ static void hotplug_event(acpi_handle ha mutex_unlock(&acpiphp_context_lock); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ - pr_debug("%s: Bus check notify on %s\n", __func__, objname); - pr_debug("%s: re-enumerating slots under %s\n", - __func__, objname); + acpi_handle_debug(handle, "Bus check in %s()\n", __func__); if (bridge) acpiphp_check_bridge(bridge); else if (!(slot->flags & SLOT_IS_GOING_AWAY)) @@ -822,7 +815,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - pr_debug("%s: Device check notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Device check in %s()\n", __func__); if (bridge) { acpiphp_check_bridge(bridge); } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { @@ -837,7 +830,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - pr_debug("%s: Device eject notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Eject request in %s()\n", __func__); acpiphp_disable_and_eject_slot(slot); break; } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 11/11] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (9 preceding siblings ...) 2014-01-27 0:45 ` [PATCH 10/11] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki @ 2014-01-27 0:46 ` Rafael J. Wysocki 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (2 subsequent siblings) 13 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-27 0:46 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> None of the existing users of struct acpi_dock_ops actually needs the first argument of its member functions, so redefine those functions to take only two arguments, the event type and data pointer, and update the users of struct acpi_dock_ops accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/dock.c | 4 ++-- drivers/ata/libata-acpi.c | 8 ++++---- drivers/pci/hotplug/acpiphp_glue.c | 13 +++++++------ include/acpi/acpi_drivers.h | 6 +++--- 4 files changed, 16 insertions(+), 15 deletions(-) Index: linux-pm/include/acpi/acpi_drivers.h =================================================================== --- linux-pm.orig/include/acpi/acpi_drivers.h +++ linux-pm/include/acpi/acpi_drivers.h @@ -110,9 +110,9 @@ void pci_acpi_crs_quirks(void); Dock Station -------------------------------------------------------------------------- */ struct acpi_dock_ops { - acpi_notify_handler fixup; - acpi_notify_handler handler; - acpi_notify_handler uevent; + void (*handler)(u32 event_type, void *data); + void (*fixup)(u32 event_type, void *data); + void (*uevent)(u32 event_type, void *data); }; #ifdef CONFIG_ACPI_DOCK Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -63,7 +63,7 @@ static DEFINE_MUTEX(acpiphp_context_lock static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); -static void hotplug_event(acpi_handle handle, u32 type, void *data); +static void hotplug_event(u32 type, void *data); static void free_bridge(struct kref *kref); static void acpiphp_context_handler(acpi_handle handle, void *context) @@ -185,7 +185,7 @@ static void free_bridge(struct kref *kre * TBD - figure out a way to only call fixups for * systems that require them. */ -static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) +static void post_dock_fixups(u32 event, void *data) { struct acpiphp_context *context = data; struct pci_bus *bus = context->func.slot->bus; @@ -788,11 +788,12 @@ void acpiphp_check_host_bridge(acpi_hand static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); -static void hotplug_event(acpi_handle handle, u32 type, void *data) +static void hotplug_event(u32 type, void *data) { struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; + acpi_handle handle = context->adev->handle; struct acpiphp_bridge *bridge; mutex_lock(&acpiphp_context_lock); @@ -842,16 +843,16 @@ static void hotplug_event(acpi_handle ha static void hotplug_event_work(void *data, u32 type) { struct acpiphp_context *context = data; - acpi_handle handle = context->adev->handle; acpi_scan_lock_acquire(); pci_lock_rescan_remove(); - hotplug_event(handle, type, context); + hotplug_event(type, context); pci_unlock_rescan_remove(); acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); + acpi_evaluate_hotplug_ost(context->adev->handle, type, + ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); } Index: linux-pm/drivers/acpi/dock.c =================================================================== --- linux-pm.orig/drivers/acpi/dock.c +++ linux-pm/drivers/acpi/dock.c @@ -185,7 +185,7 @@ static void dock_release_hotplug(struct static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, enum dock_callback_type cb_type) { - acpi_notify_handler cb = NULL; + void (*cb)(u32, void *) = NULL; bool run = false; mutex_lock(&hotplug_lock); @@ -213,7 +213,7 @@ static void dock_hotplug_event(struct do return; if (cb) - cb(dd->handle, event, dd->hp_context); + cb(event, dd->hp_context); dock_release_hotplug(dd); } Index: linux-pm/drivers/ata/libata-acpi.c =================================================================== --- linux-pm.orig/drivers/ata/libata-acpi.c +++ linux-pm/drivers/ata/libata-acpi.c @@ -121,14 +121,14 @@ static void ata_acpi_handle_hotplug(stru ata_port_wait_eh(ap); } -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_notify_dock(u32 event, void *data) { struct ata_device *dev = data; ata_acpi_handle_hotplug(dev->link->ap, dev, event); } -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_notify_dock(u32 event, void *data) { struct ata_port *ap = data; @@ -154,12 +154,12 @@ static void ata_acpi_uevent(struct ata_p } } -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_uevent(u32 event, void *data) { ata_acpi_uevent(data, NULL, event); } -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_uevent(u32 event, void *data) { struct ata_device *dev = data; ata_acpi_uevent(dev->link->ap, dev, event); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (10 preceding siblings ...) 2014-01-27 0:46 ` [PATCH 11/11] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations Rafael J. Wysocki @ 2014-01-28 22:10 ` Rafael J. Wysocki 2014-01-28 22:12 ` [PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki ` (5 more replies) 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-02-11 0:19 ` [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Bjorn Helgaas 13 siblings, 6 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 22:10 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg Hi All, It looks like there's time for more adventurous stuff. :-) The following series is on top of the one I sent on Sunday: https://lkml.org/lkml/2014/1/26/191 The final outcome of the patches below is that all ACPI hotplug notifications for PCI devices and for core system things like CPU, memory, PCI roots etc., will be dispatched from acpi_bus_notify() and it is not necessary to install a separate hotplug notify handler for each device any more. [1/5] Attach ACPIPHP hotplug contexts to struct acpi_device objects. [2/5] Introduce wrappers for installing and removing hotplug notify handlers (those wrappers go away later on, but they are useful for separating changes). [3/5] Consolidate ACPI hotplug signaling for PCI and ACPI core. [4/5] Simplify notify handle registration wrapper. [5/5] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). The ACPIPHP part of this has been tested on Acer Aspire S5 with Thunderbolt hotplug, but if you have access to systems with hot-removable CPUs, PCI host bridges and such things, please check if the above changes don't break them. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki @ 2014-01-28 22:12 ` Rafael J. Wysocki 2014-01-28 22:13 ` [PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (4 subsequent siblings) 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 22:12 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to a theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). For this reason, modify the code to attach the ACPIPHP's device hotplug contexts to struct device objects representing hotplug devices. This also allows further consolidation of the ACPI hotplug code to be carried out in subsequent changesets. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 3 + drivers/pci/hotplug/acpiphp.h | 9 ++- drivers/pci/hotplug/acpiphp_glue.c | 99 ++++++++++++++++++++++--------------- include/acpi/acpi_bus.h | 11 ++++ 4 files changed, 80 insertions(+), 42 deletions(-) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -139,6 +139,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + void (*release)(struct acpi_hotplug_context *); +}; + +/* * ACPI Driver * ----------- */ @@ -331,6 +341,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -1063,6 +1063,9 @@ static void acpi_device_del_work_fn(stru mutex_unlock(&acpi_device_del_lock); acpi_device_del(adev); + if (adev->hp && adev->hp->release) + adev->hp->release(adev->hp); + /* * Drop references to all power resources that might have been * used by the device. Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -53,9 +53,13 @@ #include <linux/slab.h> #include <linux/acpi.h> +#include <asm/pgtable.h> + #include "../pci.h" #include "acpiphp.h" +#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) + static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); static DEFINE_MUTEX(acpiphp_context_lock); @@ -66,9 +70,9 @@ static void acpiphp_set_hpp_values(struc static void hotplug_event(u32 type, void *data); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) +static void acpiphp_free_context(struct acpi_hotplug_context *hp) { - /* Intentionally empty. */ + kfree(to_acpiphp_context(hp)); } /** @@ -80,39 +84,29 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; + context->hp.self = adev; + context->hp.release = acpiphp_free_context; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + adev->hp = &context->hp; return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpiphp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context = to_acpiphp_context(adev->hp); - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + context->refcount++; return context; } @@ -130,7 +124,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -395,9 +389,13 @@ static struct acpiphp_bridge *acpiphp_ha { struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return NULL; mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -793,7 +791,7 @@ static void hotplug_event(u32 type, void struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_bridge *bridge; mutex_lock(&acpiphp_context_lock); @@ -842,18 +840,39 @@ static void hotplug_event(u32 type, void static void hotplug_event_work(void *data, u32 type) { - struct acpiphp_context *context = data; + struct acpi_device *adev = data; + struct acpiphp_context *context; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; acpi_scan_lock_acquire(); - pci_lock_rescan_remove(); + /* + * The device object's ACPI handle cannot become invalid as long as we + * are holding acpi_scan_lock, but it might have become invalid before + * that lock was acquired. + */ + if (adev->handle == INVALID_ACPI_HANDLE) + goto out; - hotplug_event(type, context); + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(adev); + if (!context) { + mutex_unlock(&acpiphp_context_lock); + goto out; + } + get_bridge(context->func.parent); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + pci_lock_rescan_remove(); + hotplug_event(type, context); pci_unlock_rescan_remove(); - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); + ost_code = ACPI_OST_SC_SUCCESS; + + out: + acpi_evaluate_hotplug_ost(adev->handle, type, ost_code, NULL); + put_device(&adev->dev); + acpi_scan_lock_release(); } /** @@ -866,7 +885,8 @@ static void hotplug_event_work(void *dat */ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpi_device *adev; + acpi_status status; u32 ost_code = ACPI_OST_SC_SUCCESS; switch (type) { @@ -901,17 +921,16 @@ static void handle_hotplug_event(acpi_ha goto out; } - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->adev->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); - mutex_unlock(&acpiphp_context_lock); - return; - } - mutex_unlock(&acpiphp_context_lock); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + if (acpi_bus_get_device(handle, &adev)) + goto out; + + get_device(&adev->dev); + status = acpi_hotplug_execute(hotplug_event_work, adev, type); + if (ACPI_SUCCESS(status)) + return; + + put_device(&adev->dev); out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); @@ -967,7 +986,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); put_device(&bus->dev); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-01-28 22:12 ` [PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki @ 2014-01-28 22:13 ` Rafael J. Wysocki 2014-01-28 22:14 ` [PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki ` (3 subsequent siblings) 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 22:13 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Introduce a helper routine for installing acpi_hotplug_notify_cb() as an ACPI notify handler for the given ACPI namespace node and make acpi_scan_init_hotplug() use it. This is to make subsequent changes easier to follow. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 15 +++++++++++++-- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -523,6 +523,18 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1961,8 +1973,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); + acpi_install_hotplug_notify_handler(handle, handler); break; } } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -434,6 +434,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-01-28 22:12 ` [PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki 2014-01-28 22:13 ` [PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-01-28 22:14 ` Rafael J. Wysocki 2014-01-28 22:14 ` [PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (2 subsequent siblings) 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 22:14 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Use the same ACPI notify handler, acpi_hotplug_notify_cb() for both ACPI-based PCI hotplug (ACPIPHP) and the generic ACPI-based hotplug of devices. For PCI devices use the .hp.event() callback from their ACPI companions that points to acpiphp_hotplug_event(). For other devices (CPU, memory, containers, PCI host bridges) the generic ACPI-based device hotplug code is used. This allows code duplication between ACPIPHP and the ACPI core to be reduced significantly and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 85 ++++++++++++++++++---------- drivers/pci/hotplug/acpiphp_glue.c | 110 +++---------------------------------- include/acpi/acpi_bus.h | 1 3 files changed, 66 insertions(+), 130 deletions(-) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -145,6 +145,7 @@ struct acpi_scan_handler { struct acpi_hotplug_context { struct acpi_device *self; + int (*event)(struct acpi_device *, u32); void (*release)(struct acpi_hotplug_context *); }; Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -439,40 +439,44 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) goto out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; - } - if (!error) - ost_code = ACPI_OST_SC_SUCCESS; + if (adev->handler) + error = acpi_generic_hotplug_event(adev, src); + else if (adev->hp && adev->hp->event) + error = adev->hp->event(adev, src); + + if (error) + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); @@ -483,35 +487,58 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; - if (acpi_bus_get_device(handle, &adev)) - goto err_out; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + if (acpi_bus_get_device(handle, &adev)) + goto out; + get_device(&adev->dev); status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -519,7 +546,7 @@ static void acpi_hotplug_notify_cb(acpi_ put_device(&adev->dev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -53,18 +53,14 @@ #include <linux/slab.h> #include <linux/acpi.h> -#include <asm/pgtable.h> - #include "../pci.h" #include "acpiphp.h" -#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) - static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); static DEFINE_MUTEX(acpiphp_context_lock); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, void *data); @@ -91,6 +87,7 @@ static struct acpiphp_context *acpiphp_i context->hp.self = adev; context->hp.release = acpiphp_free_context; + context->hp.event = acpiphp_hotplug_event; context->refcount = 1; adev->hp = &context->hp; return context; @@ -373,14 +370,8 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } @@ -411,7 +402,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -420,13 +410,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -838,26 +823,15 @@ static void hotplug_event(u32 type, void put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { - struct acpi_device *adev = data; struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - - acpi_scan_lock_acquire(); - /* - * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it might have become invalid before - * that lock was acquired. - */ - if (adev->handle == INVALID_ACPI_HANDLE) - goto out; mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); - goto out; + return -ENODATA; } get_bridge(context->func.parent); acpiphp_put_context(context); @@ -867,73 +841,7 @@ static void hotplug_event_work(void *dat hotplug_event(type, context); pci_unlock_rescan_remove(); put_bridge(context->func.parent); - ost_code = ACPI_OST_SC_SUCCESS; - - out: - acpi_evaluate_hotplug_ost(adev->handle, type, ost_code, NULL); - put_device(&adev->dev); - acpi_scan_lock_release(); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) -{ - struct acpi_device *adev; - acpi_status status; - u32 ost_code = ACPI_OST_SC_SUCCESS; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - if (acpi_bus_get_device(handle, &adev)) - goto out; - - get_device(&adev->dev); - status = acpi_hotplug_execute(hotplug_event_work, adev, type); - if (ACPI_SUCCESS(status)) - return; - - put_device(&adev->dev); - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + return 0; } /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (2 preceding siblings ...) 2014-01-28 22:14 ` [PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki @ 2014-01-28 22:14 ` Rafael J. Wysocki 2014-01-28 22:16 ` [PATCH 5/5][RFT] ACPI / hotplug: Dispach hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 22:14 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Use the observation that the ACPI scan handler of the device object in acpi_hotplug_notify_cb() can be obtained from that device object's handler pointer and do not pass it as data to acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). That allows the second argument of acpi_install_hotplug_notify_handler() to be dropped, so do it and update its callers accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 23 ++++++++++++----------- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_bus.h | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - struct acpi_scan_handler *handler = data; u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (handler && !handler->hotplug.enabled) { - acpi_handle_err(handle, "Eject disabled\n"); - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto out; - } - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -539,6 +531,15 @@ static void acpi_hotplug_notify_cb(acpi_ if (acpi_bus_get_device(handle, &adev)) goto out; + if (type == ACPI_NOTIFY_EJECT_REQUEST) { + if (adev->handler && !adev->handler->hotplug.enabled) { + acpi_handle_err(handle, "Eject disabled\n"); + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + goto out; + } + acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); + } get_device(&adev->dev); status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -550,10 +551,10 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +void acpi_install_hotplug_notify_handler(acpi_handle handle) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, data); + acpi_hotplug_notify_cb, NULL); } void acpi_remove_hotplug_notify_handler(acpi_handle handle) @@ -2000,7 +2001,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_hotplug_notify_handler(handle, handler); + acpi_install_hotplug_notify_handler(handle); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -371,7 +371,7 @@ static acpi_status register_slot(acpi_ha /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle, NULL); + acpi_install_hotplug_notify_handler(handle); return AE_OK; } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -435,7 +435,7 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_install_hotplug_notify_handler(acpi_handle handle); void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 5/5][RFT] ACPI / hotplug: Dispach hotplug notifications from acpi_bus_notify() 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (3 preceding siblings ...) 2014-01-28 22:14 ` [PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-01-28 22:16 ` Rafael J. Wysocki 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 22:16 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_bus_notify() is executed on all notifications for all devices anyway, rename acpi_hotplug_notify_cb() to acpi_system_notify() and call it directly from acpi_bus_notify() instead of installing notify handlers pointing to it for all hotplug devices. This change reduces both the size and complexity of ACPI-base device hotplug code. Moreover, since acpi_system_notify() only does significant things for devices that either have an ACPI scan handler, or have a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this change shouldn't modify functionality, except for executing _OST with the ACPI_OST_SC_NON_SPECIFIC_FAILURE status code for devices that were not handled at all previously. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 42 ----------------------------------- drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 44 ------------------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 16 +++++-------- include/acpi/acpi_bus.h | 2 - 6 files changed, 10 insertions(+), 96 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -345,47 +345,7 @@ static void acpi_bus_notify(acpi_handle ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", type, handle)); - switch (type) { - - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - /* TBD: Exactly what does 'light' mean? */ - break; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ - break; - - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; - } - + acpi_system_notify(handle, type); acpi_bus_get_device(handle, &device); if (device) { driver = device->driver; Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -74,6 +74,7 @@ static inline void acpi_lpss_init(void) bool acpi_queue_hotplug_work(struct work_struct *work); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); +void acpi_system_notify(acpi_handle handle, u32 type); /* -------------------------------------------------------------------------- Device Node Initialization / Removal Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -485,7 +485,7 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) +void acpi_system_notify(acpi_handle handle, u32 type) { u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; @@ -551,18 +551,6 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} - -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); -} - static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1982,34 +1970,6 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) -{ - struct acpi_device_pnp pnp = {}; - struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; - - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { - handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_hotplug_notify_handler(handle); - break; - } - } - -out: - acpi_free_pnp_ids(&pnp); -} - static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2031,8 +1991,6 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -292,7 +292,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -300,8 +299,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + mutex_unlock(&acpiphp_context_lock); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -369,10 +374,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -409,9 +410,6 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -435,8 +435,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (4 preceding siblings ...) 2014-01-28 22:16 ` [PATCH 5/5][RFT] ACPI / hotplug: Dispach hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-01-28 23:57 ` Rafael J. Wysocki 2014-01-28 23:58 ` [Resend][PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki ` (5 more replies) 5 siblings, 6 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 23:57 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg On Tuesday, January 28, 2014 11:10:30 PM Rafael J. Wysocki wrote: > Hi All, > > It looks like there's time for more adventurous stuff. :-) > > The following series is on top of the one I sent on Sunday: > > https://lkml.org/lkml/2014/1/26/191 > > The final outcome of the patches below is that all ACPI hotplug notifications > for PCI devices and for core system things like CPU, memory, PCI roots etc., > will be dispatched from acpi_bus_notify() and it is not necessary to install a > separate hotplug notify handler for each device any more. > > [1/5] Attach ACPIPHP hotplug contexts to struct acpi_device objects. > [2/5] Introduce wrappers for installing and removing hotplug notify handlers > (those wrappers go away later on, but they are useful for separating > changes). > [3/5] Consolidate ACPI hotplug signaling for PCI and ACPI core. > [4/5] Simplify notify handle registration wrapper. > [5/5] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). Unfortunately, I realized that patches [3-5/5] were buggy. The bugs were kind of subtle and might not be easy to reproduce, but they were bugs anyway. :-) A respin of the whole series follows. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Resend][PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki @ 2014-01-28 23:58 ` Rafael J. Wysocki 2014-01-28 23:59 ` [Resend][PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (4 subsequent siblings) 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 23:58 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to a theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). For this reason, modify the code to attach the ACPIPHP's device hotplug contexts to struct device objects representing hotplug devices. This also allows further consolidation of the ACPI hotplug code to be carried out in subsequent changesets. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 3 + drivers/pci/hotplug/acpiphp.h | 9 ++- drivers/pci/hotplug/acpiphp_glue.c | 99 ++++++++++++++++++++++--------------- include/acpi/acpi_bus.h | 11 ++++ 4 files changed, 80 insertions(+), 42 deletions(-) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -139,6 +139,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + void (*release)(struct acpi_hotplug_context *); +}; + +/* * ACPI Driver * ----------- */ @@ -331,6 +341,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -1063,6 +1063,9 @@ static void acpi_device_del_work_fn(stru mutex_unlock(&acpi_device_del_lock); acpi_device_del(adev); + if (adev->hp && adev->hp->release) + adev->hp->release(adev->hp); + /* * Drop references to all power resources that might have been * used by the device. Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -53,9 +53,13 @@ #include <linux/slab.h> #include <linux/acpi.h> +#include <asm/pgtable.h> + #include "../pci.h" #include "acpiphp.h" +#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) + static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); static DEFINE_MUTEX(acpiphp_context_lock); @@ -66,9 +70,9 @@ static void acpiphp_set_hpp_values(struc static void hotplug_event(u32 type, void *data); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) +static void acpiphp_free_context(struct acpi_hotplug_context *hp) { - /* Intentionally empty. */ + kfree(to_acpiphp_context(hp)); } /** @@ -80,39 +84,29 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; + context->hp.self = adev; + context->hp.release = acpiphp_free_context; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + adev->hp = &context->hp; return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpiphp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context = to_acpiphp_context(adev->hp); - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + context->refcount++; return context; } @@ -130,7 +124,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -395,9 +389,13 @@ static struct acpiphp_bridge *acpiphp_ha { struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return NULL; mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -793,7 +791,7 @@ static void hotplug_event(u32 type, void struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_bridge *bridge; mutex_lock(&acpiphp_context_lock); @@ -842,18 +840,39 @@ static void hotplug_event(u32 type, void static void hotplug_event_work(void *data, u32 type) { - struct acpiphp_context *context = data; + struct acpi_device *adev = data; + struct acpiphp_context *context; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; acpi_scan_lock_acquire(); - pci_lock_rescan_remove(); + /* + * The device object's ACPI handle cannot become invalid as long as we + * are holding acpi_scan_lock, but it might have become invalid before + * that lock was acquired. + */ + if (adev->handle == INVALID_ACPI_HANDLE) + goto out; - hotplug_event(type, context); + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(adev); + if (!context) { + mutex_unlock(&acpiphp_context_lock); + goto out; + } + get_bridge(context->func.parent); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + pci_lock_rescan_remove(); + hotplug_event(type, context); pci_unlock_rescan_remove(); - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); + ost_code = ACPI_OST_SC_SUCCESS; + + out: + acpi_evaluate_hotplug_ost(adev->handle, type, ost_code, NULL); + put_device(&adev->dev); + acpi_scan_lock_release(); } /** @@ -866,7 +885,8 @@ static void hotplug_event_work(void *dat */ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpi_device *adev; + acpi_status status; u32 ost_code = ACPI_OST_SC_SUCCESS; switch (type) { @@ -901,17 +921,16 @@ static void handle_hotplug_event(acpi_ha goto out; } - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->adev->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); - mutex_unlock(&acpiphp_context_lock); - return; - } - mutex_unlock(&acpiphp_context_lock); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + if (acpi_bus_get_device(handle, &adev)) + goto out; + + get_device(&adev->dev); + status = acpi_hotplug_execute(hotplug_event_work, adev, type); + if (ACPI_SUCCESS(status)) + return; + + put_device(&adev->dev); out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); @@ -967,7 +986,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); put_device(&bus->dev); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Resend][PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-01-28 23:58 ` [Resend][PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki @ 2014-01-28 23:59 ` Rafael J. Wysocki 2014-01-28 23:59 ` [Update][PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki ` (3 subsequent siblings) 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 23:59 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Introduce a helper routine for installing acpi_hotplug_notify_cb() as an ACPI notify handler for the given ACPI namespace node and make acpi_scan_init_hotplug() use it. This is to make subsequent changes easier to follow. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 15 +++++++++++++-- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -523,6 +523,18 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1961,8 +1973,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); + acpi_install_hotplug_notify_handler(handle, handler); break; } } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -434,6 +434,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update][PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-01-28 23:58 ` [Resend][PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki 2014-01-28 23:59 ` [Resend][PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-01-28 23:59 ` Rafael J. Wysocki 2014-01-29 0:00 ` [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (2 subsequent siblings) 5 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-28 23:59 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Use the same ACPI notify handler, acpi_hotplug_notify_cb() for both ACPI-based PCI hotplug (ACPIPHP) and the generic ACPI-based hotplug of devices. For PCI devices use the .hp.event() callback from their ACPI companions that points to acpiphp_hotplug_event(). For other devices (CPU, memory, containers, PCI host bridges) the generic ACPI-based device hotplug code is used. This allows code duplication between ACPIPHP and the ACPI core to be reduced significantly and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 79 +++++++++++++++++--------- drivers/pci/hotplug/acpiphp_glue.c | 110 +++---------------------------------- include/acpi/acpi_bus.h | 1 3 files changed, 63 insertions(+), 127 deletions(-) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -145,6 +145,7 @@ struct acpi_scan_handler { struct acpi_hotplug_context { struct acpi_device *self; + int (*event)(struct acpi_device *, u32); void (*release)(struct acpi_hotplug_context *); }; Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -439,38 +439,42 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) goto out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; - } + if (adev->handler) + error = acpi_generic_hotplug_event(adev, src); + else if (adev->hp && adev->hp->event) + error = adev->hp->event(adev, src); + if (!error) ost_code = ACPI_OST_SC_SUCCESS; @@ -483,35 +487,58 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; - if (acpi_bus_get_device(handle, &adev)) - goto err_out; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + if (acpi_bus_get_device(handle, &adev)) + goto out; + get_device(&adev->dev); status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -519,7 +546,7 @@ static void acpi_hotplug_notify_cb(acpi_ put_device(&adev->dev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -53,18 +53,14 @@ #include <linux/slab.h> #include <linux/acpi.h> -#include <asm/pgtable.h> - #include "../pci.h" #include "acpiphp.h" -#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) - static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); static DEFINE_MUTEX(acpiphp_context_lock); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, void *data); @@ -91,6 +87,7 @@ static struct acpiphp_context *acpiphp_i context->hp.self = adev; context->hp.release = acpiphp_free_context; + context->hp.event = acpiphp_hotplug_event; context->refcount = 1; adev->hp = &context->hp; return context; @@ -373,14 +370,8 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } @@ -411,7 +402,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -420,13 +410,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -838,26 +823,15 @@ static void hotplug_event(u32 type, void put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { - struct acpi_device *adev = data; struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - - acpi_scan_lock_acquire(); - /* - * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it might have become invalid before - * that lock was acquired. - */ - if (adev->handle == INVALID_ACPI_HANDLE) - goto out; mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); - goto out; + return -ENODATA; } get_bridge(context->func.parent); acpiphp_put_context(context); @@ -867,73 +841,7 @@ static void hotplug_event_work(void *dat hotplug_event(type, context); pci_unlock_rescan_remove(); put_bridge(context->func.parent); - ost_code = ACPI_OST_SC_SUCCESS; - - out: - acpi_evaluate_hotplug_ost(adev->handle, type, ost_code, NULL); - put_device(&adev->dev); - acpi_scan_lock_release(); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) -{ - struct acpi_device *adev; - acpi_status status; - u32 ost_code = ACPI_OST_SC_SUCCESS; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - if (acpi_bus_get_device(handle, &adev)) - goto out; - - get_device(&adev->dev); - status = acpi_hotplug_execute(hotplug_event_work, adev, type); - if (ACPI_SUCCESS(status)) - return; - - put_device(&adev->dev); - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + return 0; } /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (2 preceding siblings ...) 2014-01-28 23:59 ` [Update][PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki @ 2014-01-29 0:00 ` Rafael J. Wysocki 2014-01-31 15:28 ` Mika Westerberg 2014-01-29 0:02 ` [Update][PATCH 5/5][RFT] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 5 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-29 0:00 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Use the observation that the ACPI scan handler of the device object in acpi_hotplug_notify_cb() can be obtained from that device object's handler pointer and do not pass it as data to acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). That allows the second argument of acpi_install_hotplug_notify_handler() to be dropped, so do it and update its callers accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 31 ++++++++++++++++++------------- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_bus.h | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - struct acpi_scan_handler *handler = data; u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (handler && !handler->hotplug.enabled) { - acpi_handle_err(handle, "Eject disabled\n"); - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto out; - } - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ goto out; } + mutex_lock(&acpi_scan_lock); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - if (acpi_bus_get_device(handle, &adev)) + if (acpi_bus_get_device(handle, &adev)) { + mutex_unlock(&acpi_scan_lock); goto out; - + } + if (type == ACPI_NOTIFY_EJECT_REQUEST) { + if (adev->handler && !adev->handler->hotplug.enabled) { + acpi_handle_err(handle, "Eject disabled\n"); + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + mutex_unlock(&acpi_scan_lock); + goto out; + } + acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); + } get_device(&adev->dev); + mutex_unlock(&acpi_scan_lock); status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) return; @@ -550,10 +555,10 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +void acpi_install_hotplug_notify_handler(acpi_handle handle) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, data); + acpi_hotplug_notify_cb, NULL); } void acpi_remove_hotplug_notify_handler(acpi_handle handle) @@ -2000,7 +2005,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_hotplug_notify_handler(handle, handler); + acpi_install_hotplug_notify_handler(handle); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -371,7 +371,7 @@ static acpi_status register_slot(acpi_ha /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle, NULL); + acpi_install_hotplug_notify_handler(handle); return AE_OK; } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -435,7 +435,7 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_install_hotplug_notify_handler(acpi_handle handle); void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-29 0:00 ` [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-01-31 15:28 ` Mika Westerberg 2014-01-31 15:42 ` Rafael J. Wysocki 0 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-01-31 15:28 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > Use the observation that the ACPI scan handler of the device object > in acpi_hotplug_notify_cb() can be obtained from that device object's > handler pointer and do not pass it as data to > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > That allows the second argument of acpi_install_hotplug_notify_handler() > to be dropped, so do it and update its callers accordingly. > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > --- > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > include/acpi/acpi_bus.h | 2 +- > 3 files changed, 20 insertions(+), 15 deletions(-) > > Index: linux-pm/drivers/acpi/scan.c > =================================================================== > --- linux-pm.orig/drivers/acpi/scan.c > +++ linux-pm/drivers/acpi/scan.c > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > { > - struct acpi_scan_handler *handler = data; > u32 ost_code = ACPI_OST_SC_SUCCESS; > struct acpi_device *adev; > acpi_status status; > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > case ACPI_NOTIFY_EJECT_REQUEST: > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > - if (handler && !handler->hotplug.enabled) { > - acpi_handle_err(handle, "Eject disabled\n"); > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > - goto out; > - } > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > break; > > case ACPI_NOTIFY_DEVICE_WAKE: > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > goto out; > } > > + mutex_lock(&acpi_scan_lock); This is weird. I'm testing against your test-next branch which has this patch included. If I remove locking here, TBT hotplug works fine. Otherwise I can see the first hotplug/unplug works but after that I cannot get any events anymore. > ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; > - if (acpi_bus_get_device(handle, &adev)) > + if (acpi_bus_get_device(handle, &adev)) { > + mutex_unlock(&acpi_scan_lock); > goto out; > - > + } > + if (type == ACPI_NOTIFY_EJECT_REQUEST) { > + if (adev->handler && !adev->handler->hotplug.enabled) { > + acpi_handle_err(handle, "Eject disabled\n"); > + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > + mutex_unlock(&acpi_scan_lock); > + goto out; > + } > + acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > + } > get_device(&adev->dev); > + mutex_unlock(&acpi_scan_lock); > status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); > if (ACPI_SUCCESS(status)) > return; ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 15:28 ` Mika Westerberg @ 2014-01-31 15:42 ` Rafael J. Wysocki 2014-01-31 15:40 ` Mika Westerberg 0 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-31 15:42 UTC (permalink / raw) To: Mika Westerberg Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Friday, January 31, 2014 05:28:36 PM Mika Westerberg wrote: > On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > Use the observation that the ACPI scan handler of the device object > > in acpi_hotplug_notify_cb() can be obtained from that device object's > > handler pointer and do not pass it as data to > > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > > > That allows the second argument of acpi_install_hotplug_notify_handler() > > to be dropped, so do it and update its callers accordingly. > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > --- > > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > > include/acpi/acpi_bus.h | 2 +- > > 3 files changed, 20 insertions(+), 15 deletions(-) > > > > Index: linux-pm/drivers/acpi/scan.c > > =================================================================== > > --- linux-pm.orig/drivers/acpi/scan.c > > +++ linux-pm/drivers/acpi/scan.c > > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > > { > > - struct acpi_scan_handler *handler = data; > > u32 ost_code = ACPI_OST_SC_SUCCESS; > > struct acpi_device *adev; > > acpi_status status; > > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > case ACPI_NOTIFY_EJECT_REQUEST: > > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > > - if (handler && !handler->hotplug.enabled) { > > - acpi_handle_err(handle, "Eject disabled\n"); > > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > > - goto out; > > - } > > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > > break; > > > > case ACPI_NOTIFY_DEVICE_WAKE: > > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > > goto out; > > } > > > > + mutex_lock(&acpi_scan_lock); > > This is weird. I'm testing against your test-next branch which has this > patch included. If I remove locking here, TBT hotplug works fine. Otherwise > I can see the first hotplug/unplug works but after that I cannot get any > events anymore. Weird indeed. I don't seem to be able to reproduce that on my Aspire S5. What system are you testing on? -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 15:42 ` Rafael J. Wysocki @ 2014-01-31 15:40 ` Mika Westerberg 2014-01-31 16:01 ` Mika Westerberg 0 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-01-31 15:40 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Fri, Jan 31, 2014 at 04:42:21PM +0100, Rafael J. Wysocki wrote: > On Friday, January 31, 2014 05:28:36 PM Mika Westerberg wrote: > > On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > Use the observation that the ACPI scan handler of the device object > > > in acpi_hotplug_notify_cb() can be obtained from that device object's > > > handler pointer and do not pass it as data to > > > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > > > > > That allows the second argument of acpi_install_hotplug_notify_handler() > > > to be dropped, so do it and update its callers accordingly. > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > --- > > > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > > > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > > > include/acpi/acpi_bus.h | 2 +- > > > 3 files changed, 20 insertions(+), 15 deletions(-) > > > > > > Index: linux-pm/drivers/acpi/scan.c > > > =================================================================== > > > --- linux-pm.orig/drivers/acpi/scan.c > > > +++ linux-pm/drivers/acpi/scan.c > > > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > > > > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > > > { > > > - struct acpi_scan_handler *handler = data; > > > u32 ost_code = ACPI_OST_SC_SUCCESS; > > > struct acpi_device *adev; > > > acpi_status status; > > > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > case ACPI_NOTIFY_EJECT_REQUEST: > > > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > > > - if (handler && !handler->hotplug.enabled) { > > > - acpi_handle_err(handle, "Eject disabled\n"); > > > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > > > - goto out; > > > - } > > > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > > > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > > > break; > > > > > > case ACPI_NOTIFY_DEVICE_WAKE: > > > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > > > goto out; > > > } > > > > > > + mutex_lock(&acpi_scan_lock); > > > > This is weird. I'm testing against your test-next branch which has this > > patch included. If I remove locking here, TBT hotplug works fine. Otherwise > > I can see the first hotplug/unplug works but after that I cannot get any > > events anymore. > > Weird indeed. I don't seem to be able to reproduce that on my Aspire S5. > > What system are you testing on? This is Intel NUC. Let me see if I can reproduce this on S5 with longer chain of devices. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 15:40 ` Mika Westerberg @ 2014-01-31 16:01 ` Mika Westerberg 2014-01-31 16:16 ` Rafael J. Wysocki 0 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-01-31 16:01 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Fri, Jan 31, 2014 at 05:40:11PM +0200, Mika Westerberg wrote: > On Fri, Jan 31, 2014 at 04:42:21PM +0100, Rafael J. Wysocki wrote: > > On Friday, January 31, 2014 05:28:36 PM Mika Westerberg wrote: > > > On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > > > Use the observation that the ACPI scan handler of the device object > > > > in acpi_hotplug_notify_cb() can be obtained from that device object's > > > > handler pointer and do not pass it as data to > > > > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > > > > > > > That allows the second argument of acpi_install_hotplug_notify_handler() > > > > to be dropped, so do it and update its callers accordingly. > > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > --- > > > > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > > > > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > > > > include/acpi/acpi_bus.h | 2 +- > > > > 3 files changed, 20 insertions(+), 15 deletions(-) > > > > > > > > Index: linux-pm/drivers/acpi/scan.c > > > > =================================================================== > > > > --- linux-pm.orig/drivers/acpi/scan.c > > > > +++ linux-pm/drivers/acpi/scan.c > > > > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > > > > > > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > > > > { > > > > - struct acpi_scan_handler *handler = data; > > > > u32 ost_code = ACPI_OST_SC_SUCCESS; > > > > struct acpi_device *adev; > > > > acpi_status status; > > > > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > > > case ACPI_NOTIFY_EJECT_REQUEST: > > > > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > > > > - if (handler && !handler->hotplug.enabled) { > > > > - acpi_handle_err(handle, "Eject disabled\n"); > > > > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > > > > - goto out; > > > > - } > > > > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > > > > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > > > > break; > > > > > > > > case ACPI_NOTIFY_DEVICE_WAKE: > > > > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > goto out; > > > > } > > > > > > > > + mutex_lock(&acpi_scan_lock); > > > > > > This is weird. I'm testing against your test-next branch which has this > > > patch included. If I remove locking here, TBT hotplug works fine. Otherwise > > > I can see the first hotplug/unplug works but after that I cannot get any > > > events anymore. > > > > Weird indeed. I don't seem to be able to reproduce that on my Aspire S5. > > > > What system are you testing on? > > This is Intel NUC. Let me see if I can reproduce this on S5 with longer > chain of devices. OK, so on S5 this works even with longer chain. However, exactly the same kernel image on NUC fails after first hotplug/unplug cycle. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 16:01 ` Mika Westerberg @ 2014-01-31 16:16 ` Rafael J. Wysocki 2014-01-31 17:09 ` Mika Westerberg 0 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-31 16:16 UTC (permalink / raw) To: Mika Westerberg Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Friday, January 31, 2014 06:01:57 PM Mika Westerberg wrote: > On Fri, Jan 31, 2014 at 05:40:11PM +0200, Mika Westerberg wrote: > > On Fri, Jan 31, 2014 at 04:42:21PM +0100, Rafael J. Wysocki wrote: > > > On Friday, January 31, 2014 05:28:36 PM Mika Westerberg wrote: > > > > On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > > > > > Use the observation that the ACPI scan handler of the device object > > > > > in acpi_hotplug_notify_cb() can be obtained from that device object's > > > > > handler pointer and do not pass it as data to > > > > > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > > > > > > > > > That allows the second argument of acpi_install_hotplug_notify_handler() > > > > > to be dropped, so do it and update its callers accordingly. > > > > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > --- > > > > > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > > > > > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > > > > > include/acpi/acpi_bus.h | 2 +- > > > > > 3 files changed, 20 insertions(+), 15 deletions(-) > > > > > > > > > > Index: linux-pm/drivers/acpi/scan.c > > > > > =================================================================== > > > > > --- linux-pm.orig/drivers/acpi/scan.c > > > > > +++ linux-pm/drivers/acpi/scan.c > > > > > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > > > > > > > > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > > > > > { > > > > > - struct acpi_scan_handler *handler = data; > > > > > u32 ost_code = ACPI_OST_SC_SUCCESS; > > > > > struct acpi_device *adev; > > > > > acpi_status status; > > > > > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > > > > > case ACPI_NOTIFY_EJECT_REQUEST: > > > > > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > > > > > - if (handler && !handler->hotplug.enabled) { > > > > > - acpi_handle_err(handle, "Eject disabled\n"); > > > > > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > > > > > - goto out; > > > > > - } > > > > > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > > > > > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > > > > > break; > > > > > > > > > > case ACPI_NOTIFY_DEVICE_WAKE: > > > > > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > goto out; > > > > > } > > > > > > > > > > + mutex_lock(&acpi_scan_lock); > > > > > > > > This is weird. I'm testing against your test-next branch which has this > > > > patch included. If I remove locking here, TBT hotplug works fine. Otherwise > > > > I can see the first hotplug/unplug works but after that I cannot get any > > > > events anymore. > > > > > > Weird indeed. I don't seem to be able to reproduce that on my Aspire S5. > > > > > > What system are you testing on? > > > > This is Intel NUC. Let me see if I can reproduce this on S5 with longer > > chain of devices. > > OK, so on S5 this works even with longer chain. However, exactly the same > kernel image on NUC fails after first hotplug/unplug cycle. Well, we need to figure out what happens there. Please add printks (1) before mutex_lock(), (2) before the if (type == ...) instruction, (3) before the acpi_evaluate_hotplug_ost() under the if () and (4) before the get_device() in acpi_notify_hotplug_cb() and check if they are all printed (on NUC). -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 16:16 ` Rafael J. Wysocki @ 2014-01-31 17:09 ` Mika Westerberg 2014-01-31 17:34 ` Rafael J. Wysocki 0 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-01-31 17:09 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Fri, Jan 31, 2014 at 05:16:03PM +0100, Rafael J. Wysocki wrote: > On Friday, January 31, 2014 06:01:57 PM Mika Westerberg wrote: > > On Fri, Jan 31, 2014 at 05:40:11PM +0200, Mika Westerberg wrote: > > > On Fri, Jan 31, 2014 at 04:42:21PM +0100, Rafael J. Wysocki wrote: > > > > On Friday, January 31, 2014 05:28:36 PM Mika Westerberg wrote: > > > > > On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > > > > > > > Use the observation that the ACPI scan handler of the device object > > > > > > in acpi_hotplug_notify_cb() can be obtained from that device object's > > > > > > handler pointer and do not pass it as data to > > > > > > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > > > > > > > > > > > That allows the second argument of acpi_install_hotplug_notify_handler() > > > > > > to be dropped, so do it and update its callers accordingly. > > > > > > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > --- > > > > > > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > > > > > > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > > > > > > include/acpi/acpi_bus.h | 2 +- > > > > > > 3 files changed, 20 insertions(+), 15 deletions(-) > > > > > > > > > > > > Index: linux-pm/drivers/acpi/scan.c > > > > > > =================================================================== > > > > > > --- linux-pm.orig/drivers/acpi/scan.c > > > > > > +++ linux-pm/drivers/acpi/scan.c > > > > > > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > > > > > > > > > > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > > > > > > { > > > > > > - struct acpi_scan_handler *handler = data; > > > > > > u32 ost_code = ACPI_OST_SC_SUCCESS; > > > > > > struct acpi_device *adev; > > > > > > acpi_status status; > > > > > > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > > > > > > > case ACPI_NOTIFY_EJECT_REQUEST: > > > > > > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > > > > > > - if (handler && !handler->hotplug.enabled) { > > > > > > - acpi_handle_err(handle, "Eject disabled\n"); > > > > > > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > > > > > > - goto out; > > > > > > - } > > > > > > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > > > > > > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > > > > > > break; > > > > > > > > > > > > case ACPI_NOTIFY_DEVICE_WAKE: > > > > > > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > goto out; > > > > > > } > > > > > > > > > > > > + mutex_lock(&acpi_scan_lock); > > > > > > > > > > This is weird. I'm testing against your test-next branch which has this > > > > > patch included. If I remove locking here, TBT hotplug works fine. Otherwise > > > > > I can see the first hotplug/unplug works but after that I cannot get any > > > > > events anymore. > > > > > > > > Weird indeed. I don't seem to be able to reproduce that on my Aspire S5. > > > > > > > > What system are you testing on? > > > > > > This is Intel NUC. Let me see if I can reproduce this on S5 with longer > > > chain of devices. > > > > OK, so on S5 this works even with longer chain. However, exactly the same > > kernel image on NUC fails after first hotplug/unplug cycle. > > Well, we need to figure out what happens there. > > Please add printks (1) before mutex_lock(), (2) before the if (type == ...) > instruction, (3) before the acpi_evaluate_hotplug_ost() under the if () and (4) > before the get_device() in acpi_notify_hotplug_cb() and check if they are all > printed (on NUC). Looks like something doesn't release that lock. I added printks what you suggested and after first hotplug/unplug last messages I get are: [ 64.914639] ACPI: \_SB_.PCI0.RP05: ACPI_NOTIFY_BUS_CHECK event [ 64.914640] ACPI: \_SB_.PCI0.RP05: BEFORE mutex_lock() Then running sysrq-w I get following task as blocked: [ 346.885950] SysRq : Show Blocked State [ 346.887733] task PC stack pid father [ 346.889535] kworker/0:0 D ffff880100241ae0 5280 4 2 0x00000000 [ 346.891355] Workqueue: kacpi_notify acpi_os_execute_deferred [ 346.893171] ffff8801003c7d30 0000000000000046 ffff880100241710 ffffffff81e10460 [ 346.895011] ffff8801003c7fd8 00000000000129c0 00000000000129c0 ffff880100241710 [ 346.896849] ffffffff81e5db70 ffffffff81e5db74 ffff880100241710 00000000ffffffff [ 346.898702] Call Trace: [ 346.900518] [<ffffffff81815bc4>] schedule_preempt_disabled+0x24/0x70 [ 346.902338] [<ffffffff818175f2>] __mutex_lock_slowpath+0x132/0x1b0 [ 346.904164] [<ffffffff8181768a>] mutex_lock+0x1a/0x2a [ 346.905993] [<ffffffff81324845>] acpi_hotplug_notify_cb+0x70/0x227 [ 346.907820] [<ffffffff813384f4>] acpi_ev_notify_dispatch+0x44/0x5c [ 346.909637] [<ffffffff8131fa8d>] acpi_os_execute_deferred+0xf/0x1b [ 346.911455] [<ffffffff8105e12a>] process_one_work+0x17a/0x440 [ 346.913285] [<ffffffff8105ed29>] worker_thread+0x119/0x390 [ 346.915121] [<ffffffff8105ec10>] ? manage_workers.isra.25+0x2a0/0x2a0 [ 346.916970] [<ffffffff81064dad>] kthread+0xcd/0xf0 [ 346.918809] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 [ 346.920653] [<ffffffff8181fefc>] ret_from_fork+0x7c/0xb0 [ 346.922501] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 [ 346.924351] kworker/u8:5 D ffff88006ea55860 4696 945 2 0x00000000 [ 346.926212] Workqueue: kacpi_hotplug acpi_hotplug_work_fn [ 346.928074] ffff88006de49a40 0000000000000046 ffff88006ea55490 ffff880100245490 [ 346.929978] ffff88006de49fd8 00000000000129c0 00000000000129c0 ffff88006ea55490 [ 346.931872] ffff88006de49ba0 7fffffffffffffff ffff88006de49b98 ffff88006ea55490 [ 346.933753] Call Trace: [ 346.935626] [<ffffffff81815794>] schedule+0x24/0x70 [ 346.937516] [<ffffffff81814a89>] schedule_timeout+0x1a9/0x2a0 [ 346.939415] [<ffffffff8107dda8>] ? __wake_up_common+0x58/0x90 [ 346.941312] [<ffffffff81816968>] wait_for_completion+0x98/0x100 [ 346.943222] [<ffffffff81071b70>] ? wake_up_state+0x10/0x10 [ 346.945133] [<ffffffff8105ba25>] flush_workqueue+0x115/0x5a0 [ 346.947054] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 [ 346.948986] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 [ 346.950904] [<ffffffff81320340>] acpi_os_wait_events_complete+0x1c/0x1e [ 346.952829] [<ffffffff8133a387>] acpi_remove_notify_handler+0x78/0x1ef [ 346.954748] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 [ 346.956669] [<ffffffff813226df>] acpi_remove_pm_notifier+0x39/0x5c [ 346.958592] [<ffffffff81309ab5>] pci_acpi_cleanup+0x25/0x50 [ 346.960508] [<ffffffff8132368c>] acpi_platform_notify_remove+0x44/0x53 [ 346.962427] [<ffffffff814426f2>] device_del+0x142/0x1b0 [ 346.964333] [<ffffffff812edcfa>] pci_remove_bus_device+0x7a/0x100 [ 346.966238] [<ffffffff812edd95>] pci_stop_and_remove_bus_device+0x15/0x20 [ 346.968140] [<ffffffff8130639e>] disable_slot+0x4e/0xa0 [ 346.970030] [<ffffffff813067b8>] acpiphp_check_bridge.part.10+0xe8/0xf0 [ 346.971911] [<ffffffff81306f92>] hotplug_event+0xf2/0x1a0 [ 346.973776] [<ffffffff813070a1>] acpiphp_hotplug_event+0x61/0xe0 [ 346.975630] [<ffffffff8132634e>] acpi_device_hotplug+0x37c/0x3c2 [ 346.977471] [<ffffffff81320359>] acpi_hotplug_work_fn+0x17/0x22 [ 346.979299] [<ffffffff8105e12a>] process_one_work+0x17a/0x440 [ 346.981122] [<ffffffff8105ed29>] worker_thread+0x119/0x390 [ 346.982956] [<ffffffff8105ec10>] ? manage_workers.isra.25+0x2a0/0x2a0 [ 346.984762] [<ffffffff81064dad>] kthread+0xcd/0xf0 [ 346.986581] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 [ 346.988419] [<ffffffff8181fefc>] ret_from_fork+0x7c/0xb0 [ 346.990221] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 I have to leave now but I can continue debugging tomorrow if needed. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 17:09 ` Mika Westerberg @ 2014-01-31 17:34 ` Rafael J. Wysocki 2014-02-02 0:12 ` Rafael J. Wysocki 0 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-31 17:34 UTC (permalink / raw) To: Mika Westerberg Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Friday, January 31, 2014 07:09:51 PM Mika Westerberg wrote: > On Fri, Jan 31, 2014 at 05:16:03PM +0100, Rafael J. Wysocki wrote: > > On Friday, January 31, 2014 06:01:57 PM Mika Westerberg wrote: > > > On Fri, Jan 31, 2014 at 05:40:11PM +0200, Mika Westerberg wrote: > > > > On Fri, Jan 31, 2014 at 04:42:21PM +0100, Rafael J. Wysocki wrote: > > > > > On Friday, January 31, 2014 05:28:36 PM Mika Westerberg wrote: > > > > > > On Wed, Jan 29, 2014 at 01:00:57AM +0100, Rafael J. Wysocki wrote: > > > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > > > > > > > > > Use the observation that the ACPI scan handler of the device object > > > > > > > in acpi_hotplug_notify_cb() can be obtained from that device object's > > > > > > > handler pointer and do not pass it as data to > > > > > > > acpi_install_hotplug_notify_handler() in acpi_scan_init_hotplug(). > > > > > > > > > > > > > > That allows the second argument of acpi_install_hotplug_notify_handler() > > > > > > > to be dropped, so do it and update its callers accordingly. > > > > > > > > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > > > > --- > > > > > > > drivers/acpi/scan.c | 31 ++++++++++++++++++------------- > > > > > > > drivers/pci/hotplug/acpiphp_glue.c | 2 +- > > > > > > > include/acpi/acpi_bus.h | 2 +- > > > > > > > 3 files changed, 20 insertions(+), 15 deletions(-) > > > > > > > > > > > > > > Index: linux-pm/drivers/acpi/scan.c > > > > > > > =================================================================== > > > > > > > --- linux-pm.orig/drivers/acpi/scan.c > > > > > > > +++ linux-pm/drivers/acpi/scan.c > > > > > > > @@ -487,7 +487,6 @@ static void acpi_device_hotplug(void *da > > > > > > > > > > > > > > static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) > > > > > > > { > > > > > > > - struct acpi_scan_handler *handler = data; > > > > > > > u32 ost_code = ACPI_OST_SC_SUCCESS; > > > > > > > struct acpi_device *adev; > > > > > > > acpi_status status; > > > > > > > @@ -503,13 +502,6 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > > > > > > > > > case ACPI_NOTIFY_EJECT_REQUEST: > > > > > > > acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); > > > > > > > - if (handler && !handler->hotplug.enabled) { > > > > > > > - acpi_handle_err(handle, "Eject disabled\n"); > > > > > > > - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; > > > > > > > - goto out; > > > > > > > - } > > > > > > > - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, > > > > > > > - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); > > > > > > > break; > > > > > > > > > > > > > > case ACPI_NOTIFY_DEVICE_WAKE: > > > > > > > @@ -535,11 +527,24 @@ static void acpi_hotplug_notify_cb(acpi_ > > > > > > > goto out; > > > > > > > } > > > > > > > > > > > > > > + mutex_lock(&acpi_scan_lock); > > > > > > > > > > > > This is weird. I'm testing against your test-next branch which has this > > > > > > patch included. If I remove locking here, TBT hotplug works fine. Otherwise > > > > > > I can see the first hotplug/unplug works but after that I cannot get any > > > > > > events anymore. > > > > > > > > > > Weird indeed. I don't seem to be able to reproduce that on my Aspire S5. > > > > > > > > > > What system are you testing on? > > > > > > > > This is Intel NUC. Let me see if I can reproduce this on S5 with longer > > > > chain of devices. > > > > > > OK, so on S5 this works even with longer chain. However, exactly the same > > > kernel image on NUC fails after first hotplug/unplug cycle. > > > > Well, we need to figure out what happens there. > > > > Please add printks (1) before mutex_lock(), (2) before the if (type == ...) > > instruction, (3) before the acpi_evaluate_hotplug_ost() under the if () and (4) > > before the get_device() in acpi_notify_hotplug_cb() and check if they are all > > printed (on NUC). > > Looks like something doesn't release that lock. I added printks what you > suggested and after first hotplug/unplug last messages I get are: > > [ 64.914639] ACPI: \_SB_.PCI0.RP05: ACPI_NOTIFY_BUS_CHECK event > [ 64.914640] ACPI: \_SB_.PCI0.RP05: BEFORE mutex_lock() > > Then running sysrq-w I get following task as blocked: > > [ 346.885950] SysRq : Show Blocked State > [ 346.887733] task PC stack pid father > [ 346.889535] kworker/0:0 D ffff880100241ae0 5280 4 2 0x00000000 > [ 346.891355] Workqueue: kacpi_notify acpi_os_execute_deferred > [ 346.893171] ffff8801003c7d30 0000000000000046 ffff880100241710 ffffffff81e10460 > [ 346.895011] ffff8801003c7fd8 00000000000129c0 00000000000129c0 ffff880100241710 > [ 346.896849] ffffffff81e5db70 ffffffff81e5db74 ffff880100241710 00000000ffffffff > [ 346.898702] Call Trace: > [ 346.900518] [<ffffffff81815bc4>] schedule_preempt_disabled+0x24/0x70 > [ 346.902338] [<ffffffff818175f2>] __mutex_lock_slowpath+0x132/0x1b0 > [ 346.904164] [<ffffffff8181768a>] mutex_lock+0x1a/0x2a > [ 346.905993] [<ffffffff81324845>] acpi_hotplug_notify_cb+0x70/0x227 > [ 346.907820] [<ffffffff813384f4>] acpi_ev_notify_dispatch+0x44/0x5c > [ 346.909637] [<ffffffff8131fa8d>] acpi_os_execute_deferred+0xf/0x1b > [ 346.911455] [<ffffffff8105e12a>] process_one_work+0x17a/0x440 > [ 346.913285] [<ffffffff8105ed29>] worker_thread+0x119/0x390 > [ 346.915121] [<ffffffff8105ec10>] ? manage_workers.isra.25+0x2a0/0x2a0 > [ 346.916970] [<ffffffff81064dad>] kthread+0xcd/0xf0 > [ 346.918809] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > [ 346.920653] [<ffffffff8181fefc>] ret_from_fork+0x7c/0xb0 > [ 346.922501] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > [ 346.924351] kworker/u8:5 D ffff88006ea55860 4696 945 2 0x00000000 > [ 346.926212] Workqueue: kacpi_hotplug acpi_hotplug_work_fn > [ 346.928074] ffff88006de49a40 0000000000000046 ffff88006ea55490 ffff880100245490 > [ 346.929978] ffff88006de49fd8 00000000000129c0 00000000000129c0 ffff88006ea55490 > [ 346.931872] ffff88006de49ba0 7fffffffffffffff ffff88006de49b98 ffff88006ea55490 > [ 346.933753] Call Trace: > [ 346.935626] [<ffffffff81815794>] schedule+0x24/0x70 > [ 346.937516] [<ffffffff81814a89>] schedule_timeout+0x1a9/0x2a0 > [ 346.939415] [<ffffffff8107dda8>] ? __wake_up_common+0x58/0x90 > [ 346.941312] [<ffffffff81816968>] wait_for_completion+0x98/0x100 > [ 346.943222] [<ffffffff81071b70>] ? wake_up_state+0x10/0x10 > [ 346.945133] [<ffffffff8105ba25>] flush_workqueue+0x115/0x5a0 > [ 346.947054] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 > [ 346.948986] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 > [ 346.950904] [<ffffffff81320340>] acpi_os_wait_events_complete+0x1c/0x1e > [ 346.952829] [<ffffffff8133a387>] acpi_remove_notify_handler+0x78/0x1ef > [ 346.954748] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 > [ 346.956669] [<ffffffff813226df>] acpi_remove_pm_notifier+0x39/0x5c > [ 346.958592] [<ffffffff81309ab5>] pci_acpi_cleanup+0x25/0x50 > [ 346.960508] [<ffffffff8132368c>] acpi_platform_notify_remove+0x44/0x53 > [ 346.962427] [<ffffffff814426f2>] device_del+0x142/0x1b0 > [ 346.964333] [<ffffffff812edcfa>] pci_remove_bus_device+0x7a/0x100 > [ 346.966238] [<ffffffff812edd95>] pci_stop_and_remove_bus_device+0x15/0x20 > [ 346.968140] [<ffffffff8130639e>] disable_slot+0x4e/0xa0 > [ 346.970030] [<ffffffff813067b8>] acpiphp_check_bridge.part.10+0xe8/0xf0 > [ 346.971911] [<ffffffff81306f92>] hotplug_event+0xf2/0x1a0 > [ 346.973776] [<ffffffff813070a1>] acpiphp_hotplug_event+0x61/0xe0 > [ 346.975630] [<ffffffff8132634e>] acpi_device_hotplug+0x37c/0x3c2 > [ 346.977471] [<ffffffff81320359>] acpi_hotplug_work_fn+0x17/0x22 > [ 346.979299] [<ffffffff8105e12a>] process_one_work+0x17a/0x440 > [ 346.981122] [<ffffffff8105ed29>] worker_thread+0x119/0x390 > [ 346.982956] [<ffffffff8105ec10>] ? manage_workers.isra.25+0x2a0/0x2a0 > [ 346.984762] [<ffffffff81064dad>] kthread+0xcd/0xf0 > [ 346.986581] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > [ 346.988419] [<ffffffff8181fefc>] ret_from_fork+0x7c/0xb0 > [ 346.990221] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > > I have to leave now but I can continue debugging tomorrow if needed. No need for now, I think I know what's happening. I'll follow up later. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-01-31 17:34 ` Rafael J. Wysocki @ 2014-02-02 0:12 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:12 UTC (permalink / raw) To: Mika Westerberg Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Friday, January 31, 2014 06:34:22 PM Rafael J. Wysocki wrote: > On Friday, January 31, 2014 07:09:51 PM Mika Westerberg wrote: > > On Fri, Jan 31, 2014 at 05:16:03PM +0100, Rafael J. Wysocki wrote: [...] > > > > [ 64.914639] ACPI: \_SB_.PCI0.RP05: ACPI_NOTIFY_BUS_CHECK event > > [ 64.914640] ACPI: \_SB_.PCI0.RP05: BEFORE mutex_lock() > > > > Then running sysrq-w I get following task as blocked: > > > > [ 346.885950] SysRq : Show Blocked State > > [ 346.887733] task PC stack pid father > > [ 346.889535] kworker/0:0 D ffff880100241ae0 5280 4 2 0x00000000 > > [ 346.891355] Workqueue: kacpi_notify acpi_os_execute_deferred > > [ 346.893171] ffff8801003c7d30 0000000000000046 ffff880100241710 ffffffff81e10460 > > [ 346.895011] ffff8801003c7fd8 00000000000129c0 00000000000129c0 ffff880100241710 > > [ 346.896849] ffffffff81e5db70 ffffffff81e5db74 ffff880100241710 00000000ffffffff > > [ 346.898702] Call Trace: > > [ 346.900518] [<ffffffff81815bc4>] schedule_preempt_disabled+0x24/0x70 > > [ 346.902338] [<ffffffff818175f2>] __mutex_lock_slowpath+0x132/0x1b0 > > [ 346.904164] [<ffffffff8181768a>] mutex_lock+0x1a/0x2a > > [ 346.905993] [<ffffffff81324845>] acpi_hotplug_notify_cb+0x70/0x227 > > [ 346.907820] [<ffffffff813384f4>] acpi_ev_notify_dispatch+0x44/0x5c > > [ 346.909637] [<ffffffff8131fa8d>] acpi_os_execute_deferred+0xf/0x1b > > [ 346.911455] [<ffffffff8105e12a>] process_one_work+0x17a/0x440 > > [ 346.913285] [<ffffffff8105ed29>] worker_thread+0x119/0x390 > > [ 346.915121] [<ffffffff8105ec10>] ? manage_workers.isra.25+0x2a0/0x2a0 > > [ 346.916970] [<ffffffff81064dad>] kthread+0xcd/0xf0 > > [ 346.918809] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > > [ 346.920653] [<ffffffff8181fefc>] ret_from_fork+0x7c/0xb0 > > [ 346.922501] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > > [ 346.924351] kworker/u8:5 D ffff88006ea55860 4696 945 2 0x00000000 > > [ 346.926212] Workqueue: kacpi_hotplug acpi_hotplug_work_fn > > [ 346.928074] ffff88006de49a40 0000000000000046 ffff88006ea55490 ffff880100245490 > > [ 346.929978] ffff88006de49fd8 00000000000129c0 00000000000129c0 ffff88006ea55490 > > [ 346.931872] ffff88006de49ba0 7fffffffffffffff ffff88006de49b98 ffff88006ea55490 > > [ 346.933753] Call Trace: > > [ 346.935626] [<ffffffff81815794>] schedule+0x24/0x70 > > [ 346.937516] [<ffffffff81814a89>] schedule_timeout+0x1a9/0x2a0 > > [ 346.939415] [<ffffffff8107dda8>] ? __wake_up_common+0x58/0x90 > > [ 346.941312] [<ffffffff81816968>] wait_for_completion+0x98/0x100 > > [ 346.943222] [<ffffffff81071b70>] ? wake_up_state+0x10/0x10 > > [ 346.945133] [<ffffffff8105ba25>] flush_workqueue+0x115/0x5a0 > > [ 346.947054] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 > > [ 346.948986] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 > > [ 346.950904] [<ffffffff81320340>] acpi_os_wait_events_complete+0x1c/0x1e > > [ 346.952829] [<ffffffff8133a387>] acpi_remove_notify_handler+0x78/0x1ef > > [ 346.954748] [<ffffffff81309b20>] ? acpi_pci_find_companion+0x40/0x40 > > [ 346.956669] [<ffffffff813226df>] acpi_remove_pm_notifier+0x39/0x5c > > [ 346.958592] [<ffffffff81309ab5>] pci_acpi_cleanup+0x25/0x50 > > [ 346.960508] [<ffffffff8132368c>] acpi_platform_notify_remove+0x44/0x53 > > [ 346.962427] [<ffffffff814426f2>] device_del+0x142/0x1b0 > > [ 346.964333] [<ffffffff812edcfa>] pci_remove_bus_device+0x7a/0x100 > > [ 346.966238] [<ffffffff812edd95>] pci_stop_and_remove_bus_device+0x15/0x20 > > [ 346.968140] [<ffffffff8130639e>] disable_slot+0x4e/0xa0 > > [ 346.970030] [<ffffffff813067b8>] acpiphp_check_bridge.part.10+0xe8/0xf0 > > [ 346.971911] [<ffffffff81306f92>] hotplug_event+0xf2/0x1a0 > > [ 346.973776] [<ffffffff813070a1>] acpiphp_hotplug_event+0x61/0xe0 > > [ 346.975630] [<ffffffff8132634e>] acpi_device_hotplug+0x37c/0x3c2 > > [ 346.977471] [<ffffffff81320359>] acpi_hotplug_work_fn+0x17/0x22 > > [ 346.979299] [<ffffffff8105e12a>] process_one_work+0x17a/0x440 > > [ 346.981122] [<ffffffff8105ed29>] worker_thread+0x119/0x390 > > [ 346.982956] [<ffffffff8105ec10>] ? manage_workers.isra.25+0x2a0/0x2a0 > > [ 346.984762] [<ffffffff81064dad>] kthread+0xcd/0xf0 > > [ 346.986581] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > > [ 346.988419] [<ffffffff8181fefc>] ret_from_fork+0x7c/0xb0 > > [ 346.990221] [<ffffffff81064ce0>] ? kthread_create_on_node+0x180/0x180 > > > > I have to leave now but I can continue debugging tomorrow if needed. > > No need for now, I think I know what's happening. I'll follow up later. acpi_remove_notify_handler() which is called from acpi_remove_pm_notifier() executes acpi_os_wait_events_complete() which does flush_workqueue(kacpi_notify_wq) and all that happens under acpi_scan_lock acquired by acpi_device_hotplug(). Now, acpi_hotplug_notify_cb() runs from kacpi_notify_wq, so effectively acpi_os_wait_events_complete() waits for it to return, so if it attempts to acquire acpi_scan_lock, it will deadlock. Which happens on the NUC. The good news is that we can use a different lock to eliminate the race I wanted to deal with using acpi_scan_lock, but that required me to rework the whole patchset. I'll send a new version shortly, but I need to update the ACPIPHP updates it is on top of. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update][PATCH 5/5][RFT] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (3 preceding siblings ...) 2014-01-29 0:00 ` [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-01-29 0:02 ` Rafael J. Wysocki 2014-01-30 15:28 ` [Update 2x][PATCH " Rafael J. Wysocki 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 5 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-29 0:02 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_bus_notify() is executed on all notifications for all devices anyway, rename acpi_hotplug_notify_cb() to acpi_system_notify() and call it directly from acpi_bus_notify() instead of installing notify handlers pointing to it for all hotplug devices. This change reduces both the size and complexity of ACPI-base device hotplug code. Moreover, since acpi_system_notify() only does significant things for devices that either have an ACPI scan handler, or have a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this change shouldn't modify functionality. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 42 ---------------------- drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 68 +++++++++---------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 16 +++----- include/acpi/acpi_bus.h | 2 - 6 files changed, 26 insertions(+), 104 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -345,47 +345,7 @@ static void acpi_bus_notify(acpi_handle ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", type, handle)); - switch (type) { - - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - /* TBD: Exactly what does 'light' mean? */ - break; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ - break; - - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; - } - + acpi_system_notify(handle, type); acpi_bus_get_device(handle, &device); if (device) { driver = device->driver; Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -74,6 +74,7 @@ static inline void acpi_lpss_init(void) bool acpi_queue_hotplug_work(struct work_struct *work); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); +void acpi_system_notify(acpi_handle handle, u32 type); /* -------------------------------------------------------------------------- Device Node Initialization / Removal Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -485,11 +485,11 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) +void acpi_system_notify(acpi_handle handle, u32 type) { u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; - acpi_status status; + bool execute_ost = true; switch (type) { case ACPI_NOTIFY_BUS_CHECK: @@ -543,28 +543,24 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); } - get_device(&adev->dev); - mutex_unlock(&acpi_scan_lock); - status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); - if (ACPI_SUCCESS(status)) - return; - - put_device(&adev->dev); + if (adev->handler || (adev->hp && adev->hp->event)) { + acpi_status status; - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); -} + get_device(&adev->dev); + mutex_unlock(&acpi_scan_lock); + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); + if (ACPI_SUCCESS(status)) + return; -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} + put_device(&adev->dev); + } else { + mutex_unlock(&acpi_scan_lock); + execute_ost = false; + } -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); + out: + if (execute_ost) + acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } static ssize_t real_power_state_show(struct device *dev, @@ -1986,34 +1982,6 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) -{ - struct acpi_device_pnp pnp = {}; - struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; - - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { - handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_hotplug_notify_handler(handle); - break; - } - } - -out: - acpi_free_pnp_ids(&pnp); -} - static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2035,8 +2003,6 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -292,7 +292,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -300,8 +299,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + mutex_unlock(&acpiphp_context_lock); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -369,10 +374,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -409,9 +410,6 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -435,8 +435,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update 2x][PATCH 5/5][RFT] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() 2014-01-29 0:02 ` [Update][PATCH 5/5][RFT] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-01-30 15:28 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-01-30 15:28 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_bus_notify() is executed on all notifications for all devices anyway, rename acpi_hotplug_notify_cb() to acpi_system_notify() and call it directly from acpi_bus_notify() instead of installing notify handlers pointing to it for all hotplug devices. This change reduces both the size and complexity of ACPI-base device hotplug code. Moreover, since acpi_system_notify() only does significant things for devices that either have an ACPI scan handler, or have a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this change shouldn't modify functionality. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- Well, I'm not sure why exactly I left the execute_ost variable in acpi_system_notify() in the previous version. Guess what, it's a good idea to review your own patches a couple of days after sending them out. :-) Rafael --- drivers/acpi/bus.c | 42 ------------------------ drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 64 ++++++++----------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 16 ++++----- include/acpi/acpi_bus.h | 2 - 6 files changed, 23 insertions(+), 103 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -345,47 +345,7 @@ static void acpi_bus_notify(acpi_handle ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", type, handle)); - switch (type) { - - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - /* TBD: Exactly what does 'light' mean? */ - break; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ - break; - - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; - } - + acpi_system_notify(handle, type); acpi_bus_get_device(handle, &device); if (device) { driver = device->driver; Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -74,6 +74,7 @@ static inline void acpi_lpss_init(void) bool acpi_queue_hotplug_work(struct work_struct *work); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); +void acpi_system_notify(acpi_handle handle, u32 type); /* -------------------------------------------------------------------------- Device Node Initialization / Removal Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -485,11 +485,10 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) +void acpi_system_notify(acpi_handle handle, u32 type) { u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; - acpi_status status; switch (type) { case ACPI_NOTIFY_BUS_CHECK: @@ -543,30 +542,25 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); } - get_device(&adev->dev); - mutex_unlock(&acpi_scan_lock); - status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); - if (ACPI_SUCCESS(status)) - return; + if (adev->handler || (adev->hp && adev->hp->event)) { + acpi_status status; - put_device(&adev->dev); + get_device(&adev->dev); + mutex_unlock(&acpi_scan_lock); + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); + if (ACPI_SUCCESS(status)) + return; + + put_device(&adev->dev); + } else { + mutex_unlock(&acpi_scan_lock); + return; + } out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} - -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); -} - static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1986,34 +1980,6 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) -{ - struct acpi_device_pnp pnp = {}; - struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; - - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { - handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_hotplug_notify_handler(handle); - break; - } - } - -out: - acpi_free_pnp_ids(&pnp); -} - static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2035,8 +2001,6 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -292,7 +292,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -300,8 +299,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + mutex_unlock(&acpiphp_context_lock); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -369,10 +374,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -409,9 +410,6 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -435,8 +435,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (4 preceding siblings ...) 2014-01-29 0:02 ` [Update][PATCH 5/5][RFT] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-02-02 0:52 ` Rafael J. Wysocki 2014-02-02 0:54 ` [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() Rafael J. Wysocki ` (6 more replies) 5 siblings, 7 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:52 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg On Wednesday, January 29, 2014 12:57:06 AM Rafael J. Wysocki wrote: > On Tuesday, January 28, 2014 11:10:30 PM Rafael J. Wysocki wrote: > > Hi All, > > > > It looks like there's time for more adventurous stuff. :-) > > > > The following series is on top of the one I sent on Sunday: > > > > https://lkml.org/lkml/2014/1/26/191 > > > > The final outcome of the patches below is that all ACPI hotplug notifications > > for PCI devices and for core system things like CPU, memory, PCI roots etc., > > will be dispatched from acpi_bus_notify() and it is not necessary to install a > > separate hotplug notify handler for each device any more. > > > > [1/5] Attach ACPIPHP hotplug contexts to struct acpi_device objects. > > [2/5] Introduce wrappers for installing and removing hotplug notify handlers > > (those wrappers go away later on, but they are useful for separating > > changes). > > [3/5] Consolidate ACPI hotplug signaling for PCI and ACPI core. > > [4/5] Simplify notify handle registration wrapper. > > [5/5] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). > > Unfortunately, I realized that patches [3-5/5] were buggy. The bugs were > kind of subtle and might not be easy to reproduce, but they were bugs anyway. :-) > > A respin of the whole series follows. After the Mika's testing it turned out that they were more buggy than I had though. Oh well. The following patchset is a reworked version of the previous one. Functionality-wise the final result should be very similar, but not exactly the same. [1/6] Fix a theoretical race condition in acpi_hotplug_notify_cb(). [2/6] Move the hotplug context lock definition to the ACPI core (from ACPIPHP). [3/6] Consolidate ACPI hotplug signaling for PCI and ACPI core (this is a combination of patches [1-3/5] from the previous series). [4/6] Rework the handling of eject requests in the ACPI core. [5/6] Simplify a routine for installing hotplug notify handlers. [6/6] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). This is on top of https://lkml.org/lkml/2014/2/1/123 which in turn is on top of the current mainline. For the adventurous all this stuff is on the test-next branch of linux-pm.git. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki @ 2014-02-02 0:54 ` Rafael J. Wysocki 2014-02-02 17:01 ` Rafael J. Wysocki 2014-02-02 0:55 ` [PATCH v2 2/6] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki ` (5 subsequent siblings) 6 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:54 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> There is a slight possibility for the ACPI device object pointed to by adev in acpi_hotplug_notify_cb() to become invalid between the acpi_bus_get_device() that it comes from and the subsequent get_device(). Namely, if acpi_scan_drop_device() runs concurrently with respect to acpi_hotplug_notify_cb() and acpi_device_del_list is not empty, acpi_device_del_work_fn() may delete the device object in question without waiting for the ACPI events workqueue to drain, which very well may happen right after a successful execution of acpi_bus_get_device() in acpi_hotplug_notify_cb(). To prevent that from happening, run acpi_bus_get_device() and the subsequent get_device() in acpi_hotplug_notify_cb() under acpi_device_del_lock, so that the deletion of the given device object cannot be queued up by acpi_scan_drop_device() between the two. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -41,6 +41,8 @@ static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); +static LIST_HEAD(acpi_device_del_list); +static DEFINE_MUTEX(acpi_device_del_lock); struct acpi_device_bus_id{ char bus_id[15]; @@ -488,9 +490,6 @@ static void acpi_hotplug_notify_cb(acpi_ struct acpi_device *adev; acpi_status status; - if (acpi_bus_get_device(handle, &adev)) - goto err_out; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); @@ -512,7 +511,13 @@ static void acpi_hotplug_notify_cb(acpi_ /* non-hotplug event; possibly handled by other handler */ return; } + mutex_lock(&acpi_device_del_lock); + if (acpi_bus_get_device(handle, &adev)) { + mutex_unlock(&acpi_device_del_lock); + goto err_out; + } get_device(&adev->dev); + mutex_unlock(&acpi_device_del_lock); status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) return; @@ -1042,9 +1047,6 @@ static void acpi_device_del(struct acpi_ device_del(&device->dev); } -static LIST_HEAD(acpi_device_del_list); -static DEFINE_MUTEX(acpi_device_del_lock); - static void acpi_device_del_work_fn(struct work_struct *work_not_used) { for (;;) { ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() 2014-02-02 0:54 ` [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() Rafael J. Wysocki @ 2014-02-02 17:01 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:01 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore On Sunday, February 02, 2014 01:54:02 AM Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > There is a slight possibility for the ACPI device object pointed to > by adev in acpi_hotplug_notify_cb() to become invalid between the > acpi_bus_get_device() that it comes from and the subsequent get_device(). > Namely, if acpi_scan_drop_device() runs concurrently with respect to > acpi_hotplug_notify_cb() and acpi_device_del_list is not empty, > acpi_device_del_work_fn() may delete the device object in question > without waiting for the ACPI events workqueue to drain, which very > well may happen right after a successful execution of > acpi_bus_get_device() in acpi_hotplug_notify_cb(). > > To prevent that from happening, run acpi_bus_get_device() and the > subsequent get_device() in acpi_hotplug_notify_cb() under > acpi_device_del_lock, so that the deletion of the given device > object cannot be queued up by acpi_scan_drop_device() between the > two. > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > --- > drivers/acpi/scan.c | 14 ++++++++------ > 1 file changed, 8 insertions(+), 6 deletions(-) > > Index: linux-pm/drivers/acpi/scan.c > =================================================================== > --- linux-pm.orig/drivers/acpi/scan.c > +++ linux-pm/drivers/acpi/scan.c > @@ -41,6 +41,8 @@ static DEFINE_MUTEX(acpi_scan_lock); > static LIST_HEAD(acpi_scan_handlers_list); > DEFINE_MUTEX(acpi_device_lock); > LIST_HEAD(acpi_wakeup_device_list); > +static LIST_HEAD(acpi_device_del_list); > +static DEFINE_MUTEX(acpi_device_del_lock); > > struct acpi_device_bus_id{ > char bus_id[15]; > @@ -488,9 +490,6 @@ static void acpi_hotplug_notify_cb(acpi_ > struct acpi_device *adev; > acpi_status status; > > - if (acpi_bus_get_device(handle, &adev)) > - goto err_out; > - > switch (type) { > case ACPI_NOTIFY_BUS_CHECK: > acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); > @@ -512,7 +511,13 @@ static void acpi_hotplug_notify_cb(acpi_ > /* non-hotplug event; possibly handled by other handler */ > return; > } > + mutex_lock(&acpi_device_del_lock); > + if (acpi_bus_get_device(handle, &adev)) { > + mutex_unlock(&acpi_device_del_lock); > + goto err_out; > + } > get_device(&adev->dev); > + mutex_unlock(&acpi_device_del_lock); > status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); > if (ACPI_SUCCESS(status)) > return; Well, that would have been good if it hand't been broken. :-( acpi_scan_drop_device() which acquires acpi_device_del_lock is called under the ACPICA's namespace mutex and acpi_bus_get_device() above acquires that mutex, so this leads to a classical ABBA deadlock scenario. Bummer. And I haven't been able to convince myself that what we're doing in acpi_hotplug_notify_cb() is actually safe without any locking. Not to mention acpi_bus_notify() for that matter. Moreover, the *only* safe way to do that I'm seeing at the moment is to call the get_device() under the ACPICA's namespace mutex, before it is released in acpi_get_data(). Of course, ACPICA will need to be modified slightly for that to be possible (sorry, Bob), but at least that *should* work, so I have a new version of this patchset doing just that. I'll send it out shortly. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 2/6] ACPI / hotplug / PCI: Define hotplug context lock in the core 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-02-02 0:54 ` [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() Rafael J. Wysocki @ 2014-02-02 0:55 ` Rafael J. Wysocki 2014-02-02 0:56 ` [PATCH v2 3/6] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki ` (4 subsequent siblings) 6 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:55 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Subsequent changes will require the ACPI core to acquire the lock protecting the ACPIPHP hotplug contexts, so move the definition of the lock to the core and change its name to be more generic. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 11 +++++++++ drivers/pci/hotplug/acpiphp_glue.c | 41 ++++++++++++++++++------------------- include/acpi/acpi_bus.h | 2 + 3 files changed, 33 insertions(+), 21 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -43,6 +43,7 @@ DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); static LIST_HEAD(acpi_device_del_list); static DEFINE_MUTEX(acpi_device_del_lock); +static DEFINE_MUTEX(acpi_hp_context_lock); struct acpi_device_bus_id{ char bus_id[15]; @@ -62,6 +63,16 @@ void acpi_scan_lock_release(void) } EXPORT_SYMBOL_GPL(acpi_scan_lock_release); +void acpi_lock_hp_context(void) +{ + mutex_lock(&acpi_hp_context_lock); +} + +void acpi_unlock_hp_context(void) +{ + mutex_unlock(&acpi_hp_context_lock); +} + int acpi_scan_add_handler(struct acpi_scan_handler *handler) { if (!handler || !handler->attach) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -58,7 +58,6 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static DEFINE_MUTEX(acpiphp_context_lock); static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); @@ -75,7 +74,7 @@ static void acpiphp_context_handler(acpi * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { @@ -100,7 +99,7 @@ static struct acpiphp_context *acpiphp_i * acpiphp_get_context - Get hotplug context and grab a reference to it. * @handle: ACPI object handle to get the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) { @@ -122,7 +121,7 @@ static struct acpiphp_context *acpiphp_g * * The context object is removed if there are no more references to it. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static void acpiphp_put_context(struct acpiphp_context *context) { @@ -151,7 +150,7 @@ static void free_bridge(struct kref *kre struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = container_of(kref, struct acpiphp_bridge, ref); @@ -175,7 +174,7 @@ static void free_bridge(struct kref *kre pci_dev_put(bridge->pci_dev); kfree(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /* @@ -291,17 +290,17 @@ static acpi_status register_slot(acpi_ha device = (adr >> 16) & 0xffff; function = adr & 0xffff; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_init_context(adev); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); acpi_handle_err(handle, "No hotplug context\n"); return AE_NOT_EXIST; } newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -319,9 +318,9 @@ static acpi_status register_slot(acpi_ha slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return AE_NO_MEMORY; } @@ -396,7 +395,7 @@ static struct acpiphp_bridge *acpiphp_ha struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (context) { bridge = context->bridge; @@ -405,7 +404,7 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return bridge; } @@ -796,12 +795,12 @@ static void hotplug_event(u32 type, void acpi_handle handle = context->adev->handle; struct acpiphp_bridge *bridge; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = context->bridge; if (bridge) get_bridge(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); pci_lock_rescan_remove(); @@ -902,16 +901,16 @@ static void handle_hotplug_event(acpi_ha goto out; } - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (context && !WARN_ON(context->adev->handle != handle)) { get_bridge(context->func.parent); acpiphp_put_context(context); acpi_hotplug_execute(hotplug_event_work, context, type); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return; } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; out: @@ -967,10 +966,10 @@ void acpiphp_enumerate_slots(struct pci_ * parent is going to be handled by pciehp, in which case this * bridge is not interesting to us either. */ - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); put_device(&bus->dev); pci_dev_put(bridge->pci_dev); kfree(bridge); @@ -980,7 +979,7 @@ void acpiphp_enumerate_slots(struct pci_ context->bridge = bridge; /* Get a reference to the parent bridge. */ get_bridge(context->func.parent); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /* must be added to the list prior to calling register_slot */ Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -402,6 +402,8 @@ static inline bool acpi_bus_can_wakeup(a void acpi_scan_lock_acquire(void); void acpi_scan_lock_release(void); +void acpi_lock_hp_context(void); +void acpi_unlock_hp_context(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); int acpi_bus_register_driver(struct acpi_driver *driver); void acpi_bus_unregister_driver(struct acpi_driver *driver); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 3/6] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-02-02 0:54 ` [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() Rafael J. Wysocki 2014-02-02 0:55 ` [PATCH v2 2/6] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki @ 2014-02-02 0:56 ` Rafael J. Wysocki 2014-02-02 0:57 ` [PATCH v2 4/6] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki ` (3 subsequent siblings) 6 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:56 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to a theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). In principle, this issue might be addressed by adding a non-empty release handler for ACPIPHP hotplug context objects analogous to acpi_scan_drop_device(), but that would duplicate the code in that function and in acpi_device_del_work_fn(). For this reason, it's better to modify ACPIPHP to attach its device hotplug contexts to struct device objects representing hotplug devices and make it use acpi_hotplug_notify_cb() as its notify handler. At the same time, acpi_device_hotplug() can be modified to dispatch the new .hp.event() callback pointing to acpiphp_hotplug_event() from ACPI device objects associated with PCI devices and use the generic ACPI device hotplug code for device objects with scan handlers attached to them. This allows the existing code duplication between ACPIPHP and the ACPI core to be reduced too and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 106 +++++++++++++++++++++------- drivers/pci/hotplug/acpiphp.h | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 136 +++++++------------------------------ include/acpi/acpi_bus.h | 22 +++++ 4 files changed, 136 insertions(+), 137 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -452,43 +452,61 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) - goto out; + goto err_out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; + if (adev->handler) { + error = acpi_generic_hotplug_event(adev, src); + } else { + int (*event)(struct acpi_device *, u32); + + acpi_lock_hp_context(); + event = adev->hp ? adev->hp->event : NULL; + acpi_unlock_hp_context(); + /* + * There may be additional notify handlers for device objects + * without the .event() callback, so ignore them here. + */ + if (event) + error = event(adev, src); + else + goto out; } if (!error) ost_code = ACPI_OST_SC_SUCCESS; - out: + err_out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + + out: put_device(&adev->dev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); @@ -496,8 +514,8 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -505,27 +523,50 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; mutex_lock(&acpi_device_del_lock); if (acpi_bus_get_device(handle, &adev)) { mutex_unlock(&acpi_device_del_lock); - goto err_out; + goto out; } get_device(&adev->dev); mutex_unlock(&acpi_device_del_lock); @@ -535,10 +576,22 @@ static void acpi_hotplug_notify_cb(acpi_ put_device(&adev->dev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1971,8 +2024,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); + acpi_install_hotplug_notify_handler(handle, handler); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -59,17 +59,12 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, void *data); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. @@ -79,39 +74,27 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context = to_acpiphp_context(adev->hp); - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + context->refcount++; return context; } @@ -129,7 +112,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -378,14 +361,8 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } @@ -394,9 +371,13 @@ static struct acpiphp_bridge *acpiphp_ha { struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return NULL; acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -412,7 +393,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -421,13 +401,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -792,7 +767,7 @@ static void hotplug_event(u32 type, void struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_bridge *bridge; acpi_lock_hp_context(); @@ -842,79 +817,24 @@ static void hotplug_event(u32 type, void put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) -{ - struct acpiphp_context *context = data; - - acpi_scan_lock_acquire(); - - hotplug_event(type, context); - - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->adev->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); + context = acpiphp_get_context(adev); + if (!context) { acpi_unlock_hp_context(); - return; + return -ENODATA; } + get_bridge(context->func.parent); + acpiphp_put_context(context); acpi_unlock_hp_context(); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + hotplug_event(type, context); + + put_bridge(context->func.parent); + return 0; } /** @@ -967,7 +887,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { acpi_unlock_hp_context(); put_device(&bus->dev); Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -137,6 +137,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + int (*event)(struct acpi_device *, u32); +}; + +/* * ACPI Driver * ----------- */ @@ -329,6 +339,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; @@ -351,6 +362,15 @@ static inline void acpi_set_device_statu *((u32 *)&adev->status) = sta; } +static inline void acpi_set_hp_context(struct acpi_device *adev, + struct acpi_hotplug_context *hp, + int (*event)(struct acpi_device *, u32)) +{ + hp->self = adev; + hp->event = event; + adev->hp = hp; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; @@ -423,6 +443,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 4/6] ACPI / hotplug / PCI: Rework the handling of eject requests 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (2 preceding siblings ...) 2014-02-02 0:56 ` [PATCH v2 3/6] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki @ 2014-02-02 0:57 ` Rafael J. Wysocki 2014-02-02 0:58 ` [PATCH v2 5/6] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (2 subsequent siblings) 6 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:57 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> To avoid the need to install a hotplug notify handler for each ACPI namespace node representing a device and having a matching scan handler, move the check whether or not the ejection of the given device is enabled through its scan handler from acpi_hotplug_notify_cb() to acpi_generic_hotplug_event(). Also, move the execution of ACPI_OST_SC_EJECT_IN_PROGRESS _OST to acpi_generic_hotplug_event(), because in acpi_hotplug_notify_cb() or in acpi_eject_store() we really don't know whether or not the eject is going to be in progress (for example, acpi_hotplug_execute() may still fail without queuing up the work item). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -461,6 +461,12 @@ static int acpi_generic_hotplug_event(st return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: + if (adev->handler && !adev->handler->hotplug.enabled) { + dev_info(&adev->dev, "Eject disabled\n"); + return -EPERM; + } + acpi_evaluate_hotplug_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); return acpi_scan_hot_remove(adev); } return -EINVAL; @@ -485,6 +491,10 @@ static void acpi_device_hotplug(void *da if (adev->handler) { error = acpi_generic_hotplug_event(adev, src); + if (error == -EPERM) { + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + goto err_out; + } } else { int (*event)(struct acpi_device *, u32); @@ -514,7 +524,6 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - struct acpi_scan_handler *handler = data; u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -530,13 +539,6 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (handler && !handler->hotplug.enabled) { - acpi_handle_err(handle, "Eject disabled\n"); - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto out; - } - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -637,8 +639,6 @@ acpi_eject_store(struct device *d, struc if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) return -ENODEV; - acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&acpi_device->dev); status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, ACPI_OST_EC_OSPM_EJECT); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 5/6] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (3 preceding siblings ...) 2014-02-02 0:57 ` [PATCH v2 4/6] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki @ 2014-02-02 0:58 ` Rafael J. Wysocki 2014-02-02 0:58 ` [PATCH v2 6/6] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 6 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:58 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_hotplug_notify_cb() does not use its data argument any more, the second argument of acpi_install_hotplug_notify_handler() can be dropped, so do that and update its callers accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 6 +++--- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_bus.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -582,10 +582,10 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +void acpi_install_hotplug_notify_handler(acpi_handle handle) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, data); + acpi_hotplug_notify_cb, NULL); } void acpi_remove_hotplug_notify_handler(acpi_handle handle) @@ -2024,7 +2024,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_hotplug_notify_handler(handle, handler); + acpi_install_hotplug_notify_handler(handle); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -362,7 +362,7 @@ static acpi_status register_slot(acpi_ha /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle, NULL); + acpi_install_hotplug_notify_handler(handle); return AE_OK; } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -443,7 +443,7 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_install_hotplug_notify_handler(acpi_handle handle); void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 6/6] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (4 preceding siblings ...) 2014-02-02 0:58 ` [PATCH v2 5/6] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-02-02 0:58 ` Rafael J. Wysocki 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 6 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:58 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_bus_notify() is executed on all notifications for all devices anyway, rename acpi_hotplug_notify_cb() to acpi_system_notify() and call it directly from acpi_bus_notify() instead of installing notify handlers pointing to it for all hotplug devices. This change reduces both the size and complexity of ACPI-based device hotplug code. Moreover, since acpi_system_notify() only does significant things for devices that either have an ACPI scan handler, or have a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this modification shouldn't change functionality. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 42 ------------------------------- drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 49 ++++--------------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 16 +++++------- include/acpi/acpi_bus.h | 2 - 6 files changed, 15 insertions(+), 96 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -346,47 +346,7 @@ static void acpi_bus_notify(acpi_handle ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", type, handle)); - switch (type) { - - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ - break; - - case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - /* TBD: Exactly what does 'light' mean? */ - break; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ - break; - - case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ - break; - - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; - } - + acpi_system_notify(handle, type); acpi_bus_get_device(handle, &device); if (device) { driver = device->driver; Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -74,6 +74,7 @@ static inline void acpi_lpss_init(void) bool acpi_queue_hotplug_work(struct work_struct *work); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); +void acpi_system_notify(acpi_handle handle, u32 type); /* -------------------------------------------------------------------------- Device Node Initialization / Removal Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -522,7 +522,7 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) +void acpi_system_notify(acpi_handle handle, u32 type) { u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; @@ -537,6 +537,11 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); + /* TBD: Exactly what does 'light' mean? */ + break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); break; @@ -582,18 +587,6 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} - -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); -} - static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2005,34 +1998,6 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) -{ - struct acpi_device_pnp pnp = {}; - struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; - - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { - handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_hotplug_notify_handler(handle); - break; - } - } - -out: - acpi_free_pnp_ids(&pnp); -} - static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2054,8 +2019,6 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -283,7 +283,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -291,8 +290,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + acpi_unlock_hp_context(); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -360,10 +365,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -400,9 +401,6 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -443,8 +443,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (5 preceding siblings ...) 2014-02-02 0:58 ` [PATCH v2 6/6] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-02-02 17:11 ` Rafael J. Wysocki 2014-02-02 17:12 ` [PATCH v3 1/7] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki ` (7 more replies) 6 siblings, 8 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:11 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore On Sunday, February 02, 2014 01:52:26 AM Rafael J. Wysocki wrote: > On Wednesday, January 29, 2014 12:57:06 AM Rafael J. Wysocki wrote: > > On Tuesday, January 28, 2014 11:10:30 PM Rafael J. Wysocki wrote: > > > Hi All, > > > > > > It looks like there's time for more adventurous stuff. :-) > > > > > > The following series is on top of the one I sent on Sunday: > > > > > > https://lkml.org/lkml/2014/1/26/191 > > > > > > The final outcome of the patches below is that all ACPI hotplug notifications > > > for PCI devices and for core system things like CPU, memory, PCI roots etc., > > > will be dispatched from acpi_bus_notify() and it is not necessary to install a > > > separate hotplug notify handler for each device any more. > > > > > > [1/5] Attach ACPIPHP hotplug contexts to struct acpi_device objects. > > > [2/5] Introduce wrappers for installing and removing hotplug notify handlers > > > (those wrappers go away later on, but they are useful for separating > > > changes). > > > [3/5] Consolidate ACPI hotplug signaling for PCI and ACPI core. > > > [4/5] Simplify notify handle registration wrapper. > > > [5/5] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). > > > > Unfortunately, I realized that patches [3-5/5] were buggy. The bugs were > > kind of subtle and might not be easy to reproduce, but they were bugs anyway. :-) > > > > A respin of the whole series follows. > > After the Mika's testing it turned out that they were more buggy than I had > though. Oh well. > > The following patchset is a reworked version of the previous one. Functionality-wise > the final result should be very similar, but not exactly the same. > > [1/6] Fix a theoretical race condition in acpi_hotplug_notify_cb(). > [2/6] Move the hotplug context lock definition to the ACPI core (from ACPIPHP). > [3/6] Consolidate ACPI hotplug signaling for PCI and ACPI core (this is a combination > of patches [1-3/5] from the previous series). > [4/6] Rework the handling of eject requests in the ACPI core. > [5/6] Simplify a routine for installing hotplug notify handlers. > [6/6] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). > > This is on top of https://lkml.org/lkml/2014/2/1/123 which in turn is on top of > the current mainline. > > For the adventurous all this stuff is on the test-next branch of linux-pm.git. As stated in the message at http://marc.info/?l=linux-acpi&m=139135963030012&w=4 , patch [1/6] was actaully wrong and the whole patchset had to be reworked for that reason. What follows is an entirely new version: [1/7] Add a new function to ACPICA allowing a callback to be executed under the namespace mutex after calling acpi_ns_get_attached_data(). [2/7] Use the new ACPICA's function to fix a couple of potential races related to ACPI notifies. [3/7] Same as [2/6] above. [4/7] Same as [3/6] above, rebased. [5/7] Same as [4/6] above. [6/7] Same as [5/6] above. [7/7] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). This actually is different from [6/6] above, although it serves the same purpose. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 1/7] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki @ 2014-02-02 17:12 ` Rafael J. Wysocki 2014-02-02 17:15 ` [PATCH v3 2/7] ACPI / hotplug: Fix potential races in notify handlers Rafael J. Wysocki ` (6 subsequent siblings) 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:12 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Introduce a new function, acpi_get_data_full(), working in analogy with acpi_get_data() except that it can execute a callback provided as its 4th argument right after acpi_ns_get_attached_data() has returned a success. That will allow Linux to reference count the object pointed to by *data before the namespace mutex is released so as to ensure that it will not be freed going forward until the reference to it acquired by acpi_get_data_full() is dropped. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/acpica/nsxfeval.c | 33 ++++++++++++++++++++++++++++++--- include/acpi/acpixf.h | 4 ++++ 2 files changed, 34 insertions(+), 3 deletions(-) Index: linux-pm/drivers/acpi/acpica/nsxfeval.c =================================================================== --- linux-pm.orig/drivers/acpi/acpica/nsxfeval.c +++ linux-pm/drivers/acpi/acpica/nsxfeval.c @@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data) /******************************************************************************* * - * FUNCTION: acpi_get_data + * FUNCTION: acpi_get_data_full * * PARAMETERS: obj_handle - Namespace node * handler - Handler used in call to attach_data * data - Where the data is returned + * callback - function to execute before returning * * RETURN: Status * - * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * DESCRIPTION: Retrieve data that was previously attached to a namespace node + * and execute a callback before returning. * ******************************************************************************/ acpi_status -acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) +acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler, + void **data, void (*callback)(void *)) { struct acpi_namespace_node *node; acpi_status status; @@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, ac } status = acpi_ns_get_attached_data(node, handler, data); + if (ACPI_SUCCESS(status) && callback) { + callback(*data); + } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); } +ACPI_EXPORT_SYMBOL(acpi_get_data_full) + +/******************************************************************************* + * + * FUNCTION: acpi_get_data + * + * PARAMETERS: obj_handle - Namespace node + * handler - Handler used in call to attach_data + * data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * + ******************************************************************************/ +acpi_status +acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) +{ + return acpi_get_data_full(obj_handle, handler, data, NULL); +} + ACPI_EXPORT_SYMBOL(acpi_get_data) Index: linux-pm/include/acpi/acpixf.h =================================================================== --- linux-pm.orig/include/acpi/acpixf.h +++ linux-pm/include/acpi/acpixf.h @@ -230,6 +230,10 @@ acpi_attach_data(acpi_handle object, acp acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); acpi_status +acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, + void (*callback)(void *)); + +acpi_status acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); acpi_status ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 2/7] ACPI / hotplug: Fix potential races in notify handlers 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-02-02 17:12 ` [PATCH v3 1/7] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki @ 2014-02-02 17:15 ` Rafael J. Wysocki 2014-02-02 17:16 ` [PATCH v3 3/7] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki ` (5 subsequent siblings) 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:15 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> There is a slight possibility for the ACPI device object pointed to by adev in acpi_hotplug_notify_cb() to become invalid between the acpi_bus_get_device() that it comes from and the subsequent dereference of that pointer under get_device(). Namely, if acpi_scan_drop_device() runs in parallel with acpi_hotplug_notify_cb(), acpi_device_del_work_fn() queued up by it may delete the device object in question right after a successful execution of acpi_bus_get_device() in acpi_bus_notify(). An analogous problem is present in acpi_bus_notify() where the device pointer coming from acpi_bus_get_device() may become invalid before it subsequent dereference in the "if" block. To prevent that from happening, introduce a new function, acpi_bus_get_acpi_device(), working analogously to acpi_bus_get_device() except that it will grab a reference to the ACPI device object returned by it and it will do that under the ACPICA's namespace mutex. Then, make both acpi_hotplug_notify_cb() and acpi_bus_notify() use acpi_bus_get_acpi_device() instead of acpi_bus_get_device() so as to ensure that the pointers used by them will not become stale at one point. In addition to that, introduce acpi_bus_put_acpi_device() as a wrapper around put_device() to be used along with acpi_bus_get_acpi_device() and make the (new) users of the latter use acpi_bus_put_acpi_device() too. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 4 +++- drivers/acpi/internal.h | 2 ++ drivers/acpi/scan.c | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 9 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -476,7 +476,7 @@ static void acpi_device_hotplug(void *da out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); - put_device(&adev->dev); + acpi_bus_put_acpi_device(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); } @@ -488,9 +488,6 @@ static void acpi_hotplug_notify_cb(acpi_ struct acpi_device *adev; acpi_status status; - if (acpi_bus_get_device(handle, &adev)) - goto err_out; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); @@ -512,12 +509,14 @@ static void acpi_hotplug_notify_cb(acpi_ /* non-hotplug event; possibly handled by other handler */ return; } - get_device(&adev->dev); + if (acpi_bus_get_acpi_device(handle, &adev)) + goto err_out; + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) return; - put_device(&adev->dev); + acpi_bus_put_acpi_device(adev); err_out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); @@ -1112,14 +1111,16 @@ static void acpi_scan_drop_device(acpi_h mutex_unlock(&acpi_device_del_lock); } -int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device, + void (*callback)(void *)) { acpi_status status; if (!device) return -EINVAL; - status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device); + status = acpi_get_data_full(handle, acpi_scan_drop_device, + (void **)device, callback); if (ACPI_FAILURE(status) || !*device) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", handle)); @@ -1127,8 +1128,29 @@ int acpi_bus_get_device(acpi_handle hand } return 0; } + +int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +{ + return acpi_get_device_data(handle, device, NULL); +} EXPORT_SYMBOL(acpi_bus_get_device); +static void get_acpi_device(void *dev) +{ + if (dev) + get_device(&((struct acpi_device *)dev)->dev); +} + +int acpi_bus_get_acpi_device(acpi_handle handle, struct acpi_device **adev_p) +{ + return acpi_get_device_data(handle, adev_p, get_acpi_device); +} + +void acpi_bus_put_acpi_device(struct acpi_device *adev) +{ + put_device(&adev->dev); +} + int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)) { Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -81,6 +81,8 @@ bool acpi_scan_is_offline(struct acpi_de #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) +int acpi_bus_get_acpi_device(acpi_handle handle, struct acpi_device **adev_p); +void acpi_bus_put_acpi_device(struct acpi_device *adev); int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -387,12 +387,14 @@ static void acpi_bus_notify(acpi_handle break; } - acpi_bus_get_device(handle, &device); + acpi_bus_get_acpi_device(handle, &device); if (device) { driver = device->driver; if (driver && driver->ops.notify && (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) driver->ops.notify(device, type); + + acpi_bus_put_acpi_device(device); } } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 3/7] ACPI / hotplug / PCI: Define hotplug context lock in the core 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-02-02 17:12 ` [PATCH v3 1/7] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki 2014-02-02 17:15 ` [PATCH v3 2/7] ACPI / hotplug: Fix potential races in notify handlers Rafael J. Wysocki @ 2014-02-02 17:16 ` Rafael J. Wysocki 2014-02-02 17:17 ` [PATCH v3 4/7] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki ` (4 subsequent siblings) 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:16 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Subsequent changes will require the ACPI core to acquire the lock protecting the ACPIPHP hotplug contexts, so move the definition of the lock to the core and change its name to be more generic. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 11 +++++++++ drivers/pci/hotplug/acpiphp_glue.c | 41 ++++++++++++++++++------------------- include/acpi/acpi_bus.h | 2 + 3 files changed, 33 insertions(+), 21 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); +static DEFINE_MUTEX(acpi_hp_context_lock); struct acpi_device_bus_id{ char bus_id[15]; @@ -60,6 +61,16 @@ void acpi_scan_lock_release(void) } EXPORT_SYMBOL_GPL(acpi_scan_lock_release); +void acpi_lock_hp_context(void) +{ + mutex_lock(&acpi_hp_context_lock); +} + +void acpi_unlock_hp_context(void) +{ + mutex_unlock(&acpi_hp_context_lock); +} + int acpi_scan_add_handler(struct acpi_scan_handler *handler) { if (!handler || !handler->attach) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -58,7 +58,6 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static DEFINE_MUTEX(acpiphp_context_lock); static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); @@ -75,7 +74,7 @@ static void acpiphp_context_handler(acpi * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { @@ -100,7 +99,7 @@ static struct acpiphp_context *acpiphp_i * acpiphp_get_context - Get hotplug context and grab a reference to it. * @handle: ACPI object handle to get the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) { @@ -122,7 +121,7 @@ static struct acpiphp_context *acpiphp_g * * The context object is removed if there are no more references to it. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static void acpiphp_put_context(struct acpiphp_context *context) { @@ -151,7 +150,7 @@ static void free_bridge(struct kref *kre struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = container_of(kref, struct acpiphp_bridge, ref); @@ -175,7 +174,7 @@ static void free_bridge(struct kref *kre pci_dev_put(bridge->pci_dev); kfree(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /* @@ -291,17 +290,17 @@ static acpi_status register_slot(acpi_ha device = (adr >> 16) & 0xffff; function = adr & 0xffff; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_init_context(adev); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); acpi_handle_err(handle, "No hotplug context\n"); return AE_NOT_EXIST; } newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -319,9 +318,9 @@ static acpi_status register_slot(acpi_ha slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return AE_NO_MEMORY; } @@ -396,7 +395,7 @@ static struct acpiphp_bridge *acpiphp_ha struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (context) { bridge = context->bridge; @@ -405,7 +404,7 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return bridge; } @@ -796,12 +795,12 @@ static void hotplug_event(u32 type, void acpi_handle handle = context->adev->handle; struct acpiphp_bridge *bridge; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = context->bridge; if (bridge) get_bridge(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); pci_lock_rescan_remove(); @@ -902,16 +901,16 @@ static void handle_hotplug_event(acpi_ha goto out; } - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (context && !WARN_ON(context->adev->handle != handle)) { get_bridge(context->func.parent); acpiphp_put_context(context); acpi_hotplug_execute(hotplug_event_work, context, type); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return; } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; out: @@ -967,10 +966,10 @@ void acpiphp_enumerate_slots(struct pci_ * parent is going to be handled by pciehp, in which case this * bridge is not interesting to us either. */ - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); put_device(&bus->dev); pci_dev_put(bridge->pci_dev); kfree(bridge); @@ -980,7 +979,7 @@ void acpiphp_enumerate_slots(struct pci_ context->bridge = bridge; /* Get a reference to the parent bridge. */ get_bridge(context->func.parent); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /* must be added to the list prior to calling register_slot */ Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -402,6 +402,8 @@ static inline bool acpi_bus_can_wakeup(a void acpi_scan_lock_acquire(void); void acpi_scan_lock_release(void); +void acpi_lock_hp_context(void); +void acpi_unlock_hp_context(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); int acpi_bus_register_driver(struct acpi_driver *driver); void acpi_bus_unregister_driver(struct acpi_driver *driver); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 4/7] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (2 preceding siblings ...) 2014-02-02 17:16 ` [PATCH v3 3/7] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki @ 2014-02-02 17:17 ` Rafael J. Wysocki 2014-02-02 17:18 ` [PATCH v3 5/7] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki ` (3 subsequent siblings) 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:17 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to a theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). In principle, this issue might be addressed by adding a non-empty release handler for ACPIPHP hotplug context objects analogous to acpi_scan_drop_device(), but that would duplicate the code in that function and in acpi_device_del_work_fn(). For this reason, it's better to modify ACPIPHP to attach its device hotplug contexts to struct device objects representing hotplug devices and make it use acpi_hotplug_notify_cb() as its notify handler. At the same time, acpi_device_hotplug() can be modified to dispatch the new .hp.event() callback pointing to acpiphp_hotplug_event() from ACPI device objects associated with PCI devices and use the generic ACPI device hotplug code for device objects with scan handlers attached to them. This allows the existing code duplication between ACPIPHP and the ACPI core to be reduced too and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 106 +++++++++++++++++++++------- drivers/pci/hotplug/acpiphp.h | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 136 +++++++------------------------------ include/acpi/acpi_bus.h | 22 +++++ 4 files changed, 136 insertions(+), 137 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -450,43 +450,61 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) - goto out; + goto err_out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; + if (adev->handler) { + error = acpi_generic_hotplug_event(adev, src); + } else { + int (*event)(struct acpi_device *, u32); + + acpi_lock_hp_context(); + event = adev->hp ? adev->hp->event : NULL; + acpi_unlock_hp_context(); + /* + * There may be additional notify handlers for device objects + * without the .event() callback, so ignore them here. + */ + if (event) + error = event(adev, src); + else + goto out; } if (!error) ost_code = ACPI_OST_SC_SUCCESS; - out: + err_out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + + out: acpi_bus_put_acpi_device(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); @@ -494,8 +512,8 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -503,25 +521,48 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; if (acpi_bus_get_acpi_device(handle, &adev)) - goto err_out; + goto out; status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -529,10 +570,22 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_bus_put_acpi_device(adev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1991,8 +2044,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); + acpi_install_hotplug_notify_handler(handle, handler); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -59,17 +59,12 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, void *data); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. @@ -79,39 +74,27 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context = to_acpiphp_context(adev->hp); - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + context->refcount++; return context; } @@ -129,7 +112,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -378,14 +361,8 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } @@ -394,9 +371,13 @@ static struct acpiphp_bridge *acpiphp_ha { struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return NULL; acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -412,7 +393,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -421,13 +401,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -792,7 +767,7 @@ static void hotplug_event(u32 type, void struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_bridge *bridge; acpi_lock_hp_context(); @@ -842,79 +817,24 @@ static void hotplug_event(u32 type, void put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) -{ - struct acpiphp_context *context = data; - - acpi_scan_lock_acquire(); - - hotplug_event(type, context); - - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->adev->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); + context = acpiphp_get_context(adev); + if (!context) { acpi_unlock_hp_context(); - return; + return -ENODATA; } + get_bridge(context->func.parent); + acpiphp_put_context(context); acpi_unlock_hp_context(); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + hotplug_event(type, context); + + put_bridge(context->func.parent); + return 0; } /** @@ -967,7 +887,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { acpi_unlock_hp_context(); put_device(&bus->dev); Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -137,6 +137,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + int (*event)(struct acpi_device *, u32); +}; + +/* * ACPI Driver * ----------- */ @@ -329,6 +339,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; @@ -351,6 +362,15 @@ static inline void acpi_set_device_statu *((u32 *)&adev->status) = sta; } +static inline void acpi_set_hp_context(struct acpi_device *adev, + struct acpi_hotplug_context *hp, + int (*event)(struct acpi_device *, u32)) +{ + hp->self = adev; + hp->event = event; + adev->hp = hp; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; @@ -423,6 +443,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 5/7] ACPI / hotplug / PCI: Rework the handling of eject requests 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (3 preceding siblings ...) 2014-02-02 17:17 ` [PATCH v3 4/7] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki @ 2014-02-02 17:18 ` Rafael J. Wysocki 2014-02-02 17:19 ` [PATCH v3 6/7] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (2 subsequent siblings) 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:18 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> To avoid the need to install a hotplug notify handler for each ACPI namespace node representing a device and having a matching scan handler, move the check whether or not the ejection of the given device is enabled through its scan handler from acpi_hotplug_notify_cb() to acpi_generic_hotplug_event(). Also, move the execution of ACPI_OST_SC_EJECT_IN_PROGRESS _OST to acpi_generic_hotplug_event(), because in acpi_hotplug_notify_cb() or in acpi_eject_store() we really don't know whether or not the eject is going to be in progress (for example, acpi_hotplug_execute() may still fail without queuing up the work item). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -459,6 +459,12 @@ static int acpi_generic_hotplug_event(st return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: + if (adev->handler && !adev->handler->hotplug.enabled) { + dev_info(&adev->dev, "Eject disabled\n"); + return -EPERM; + } + acpi_evaluate_hotplug_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); return acpi_scan_hot_remove(adev); } return -EINVAL; @@ -483,6 +489,10 @@ static void acpi_device_hotplug(void *da if (adev->handler) { error = acpi_generic_hotplug_event(adev, src); + if (error == -EPERM) { + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + goto err_out; + } } else { int (*event)(struct acpi_device *, u32); @@ -512,7 +522,6 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - struct acpi_scan_handler *handler = data; u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -528,13 +537,6 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (handler && !handler->hotplug.enabled) { - acpi_handle_err(handle, "Eject disabled\n"); - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto out; - } - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -631,8 +633,6 @@ acpi_eject_store(struct device *d, struc if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) return -ENODEV; - acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&acpi_device->dev); status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, ACPI_OST_EC_OSPM_EJECT); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 6/7] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (4 preceding siblings ...) 2014-02-02 17:18 ` [PATCH v3 5/7] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki @ 2014-02-02 17:19 ` Rafael J. Wysocki 2014-02-02 17:20 ` [PATCH v3 7/7] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-02-03 10:45 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Mika Westerberg 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:19 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_hotplug_notify_cb() does not use its data argument any more, the second argument of acpi_install_hotplug_notify_handler() can be dropped, so do that and update its callers accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 6 +++--- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_bus.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -576,10 +576,10 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +void acpi_install_hotplug_notify_handler(acpi_handle handle) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, data); + acpi_hotplug_notify_cb, NULL); } void acpi_remove_hotplug_notify_handler(acpi_handle handle) @@ -2044,7 +2044,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_hotplug_notify_handler(handle, handler); + acpi_install_hotplug_notify_handler(handle); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -362,7 +362,7 @@ static acpi_status register_slot(acpi_ha /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle, NULL); + acpi_install_hotplug_notify_handler(handle); return AE_OK; } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -443,7 +443,7 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_install_hotplug_notify_handler(acpi_handle handle); void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v3 7/7] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (5 preceding siblings ...) 2014-02-02 17:19 ` [PATCH v3 6/7] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-02-02 17:20 ` Rafael J. Wysocki 2014-02-03 10:45 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Mika Westerberg 7 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 17:20 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg, Robert Moore From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_bus_notify() is executed on all notifications for all devices anyway, make it execute acpi_device_hotplug() for all hotplug events instead of installing notify handlers pointing to the same function for all hotplug devices. This change reduces both the size and complexity of ACPI-based device hotplug code. Moreover, since acpi_device_hotplug() only does significant things for devices that have either an ACPI scan handler, or a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this modification shouldn't change functionality. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 60 +++++++++++++--------- drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 100 ------------------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 16 ++--- include/acpi/acpi_bus.h | 2 6 files changed, 46 insertions(+), 134 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -340,62 +340,76 @@ static void acpi_bus_osc_support(void) */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - struct acpi_device *device = NULL; + struct acpi_device *adev; struct acpi_driver *driver; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", - type, handle)); + acpi_status status; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); break; case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); break; case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ + acpi_handle_err(handle, "Device has suffered a power fault\n"); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto err; } - acpi_bus_get_acpi_device(handle, &device); - if (device) { - driver = device->driver; - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(device, type); + if (acpi_bus_get_acpi_device(handle, &adev)) + goto err; - acpi_bus_put_acpi_device(device); + driver = adev->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(adev, type); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + case ACPI_NOTIFY_EJECT_REQUEST: + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); + if (ACPI_SUCCESS(status)) + return; + default: + break; } + acpi_bus_put_acpi_device(adev); + return; + + err: + acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } /* -------------------------------------------------------------------------- Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) #endif bool acpi_queue_hotplug_work(struct work_struct *work); +void acpi_device_hotplug(void *data, u32 src); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); /* -------------------------------------------------------------------------- Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -470,7 +470,7 @@ static int acpi_generic_hotplug_event(st return -EINVAL; } -static void acpi_device_hotplug(void *data, u32 src) +void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; @@ -520,74 +520,6 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) -{ - u32 ost_code = ACPI_OST_SC_SUCCESS; - struct acpi_device *adev; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - if (acpi_bus_get_acpi_device(handle, &adev)) - goto out; - - status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); - if (ACPI_SUCCESS(status)) - return; - - acpi_bus_put_acpi_device(adev); - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); -} - -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} - -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); -} - static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2025,34 +1957,6 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) -{ - struct acpi_device_pnp pnp = {}; - struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; - - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { - handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_hotplug_notify_handler(handle); - break; - } - } - -out: - acpi_free_pnp_ids(&pnp); -} - static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2074,8 +1978,6 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -283,7 +283,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -291,8 +290,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + acpi_unlock_hp_context(); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -360,10 +365,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -400,9 +401,6 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -443,8 +443,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki ` (6 preceding siblings ...) 2014-02-02 17:20 ` [PATCH v3 7/7] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-02-03 10:45 ` Mika Westerberg 2014-02-03 21:51 ` Rafael J. Wysocki 7 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-02-03 10:45 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Robert Moore On Sun, Feb 02, 2014 at 06:11:19PM +0100, Rafael J. Wysocki wrote: > As stated in the message at http://marc.info/?l=linux-acpi&m=139135963030012&w=4 , > patch [1/6] was actaully wrong and the whole patchset had to be reworked for that > reason. What follows is an entirely new version: > > [1/7] Add a new function to ACPICA allowing a callback to be executed under the > namespace mutex after calling acpi_ns_get_attached_data(). > > [2/7] Use the new ACPICA's function to fix a couple of potential races related > to ACPI notifies. > > [3/7] Same as [2/6] above. > [4/7] Same as [3/6] above, rebased. > [5/7] Same as [4/6] above. > [6/7] Same as [5/6] above. > [7/7] Dispatch ACPI hotplug notifications for "core" devices and PCI from > acpi_bus_notify(). This actually is different from [6/6] above, although > it serves the same purpose. > On Intel NUC and DZ77RE-75K, Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug 2014-02-03 10:45 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Mika Westerberg @ 2014-02-03 21:51 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 21:51 UTC (permalink / raw) To: Mika Westerberg Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Robert Moore On Monday, February 03, 2014 12:45:11 PM Mika Westerberg wrote: > On Sun, Feb 02, 2014 at 06:11:19PM +0100, Rafael J. Wysocki wrote: > > As stated in the message at http://marc.info/?l=linux-acpi&m=139135963030012&w=4 , > > patch [1/6] was actaully wrong and the whole patchset had to be reworked for that > > reason. What follows is an entirely new version: > > > > [1/7] Add a new function to ACPICA allowing a callback to be executed under the > > namespace mutex after calling acpi_ns_get_attached_data(). > > > > [2/7] Use the new ACPICA's function to fix a couple of potential races related > > to ACPI notifies. > > > > [3/7] Same as [2/6] above. > > [4/7] Same as [3/6] above, rebased. > > [5/7] Same as [4/6] above. > > [6/7] Same as [5/6] above. > > [7/7] Dispatch ACPI hotplug notifications for "core" devices and PCI from > > acpi_bus_notify(). This actually is different from [6/6] above, although > > it serves the same purpose. > > > > On Intel NUC and DZ77RE-75K, > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Thanks a lot for testing! In the meantime, though, I found two more race conditions in ACPIPHP related to races with sysfs-triggered device remove. I have patches to fix them, but then I had to rebase this series (and the ACPIPHP one this is based on) on top of those fixes. I'm going to resend the two patchsets as one series including the fixes mentioned above. I tried to avoid sending out a series of 20+ patches, because then it's almost guaranteed that no one will look at them unless they happen to break things in testing, but I guess I have no choice but to do that at this point. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (11 preceding siblings ...) 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki @ 2014-02-02 0:19 ` Rafael J. Wysocki 2014-02-02 0:21 ` [PATCH v2 1/13] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki ` (14 more replies) 2014-02-11 0:19 ` [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Bjorn Helgaas 13 siblings, 15 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:19 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg On Monday, January 27, 2014 01:37:17 AM Rafael J. Wysocki wrote: > Hi All, > > ACPIPHP can be simplified a bit on top of some PCI and ACPI changes merged > recently and the following series of patches implements those simplifications: > > [1/11] Fix up two kerneldoc comments in acpiphp_glue.c. > [2/11] Get rid of an unnecessary label in register_slot(). > [3/11] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > [4/11] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > [5/11] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > [6/11] Drop acpiphp_bus_add() (which has only one user). > [7/11] Drop crit_sect mutexes (that are redundant). > [8/11] Clean up the usage of the slot variable in hotplug_event(). > [9/11] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > [10/11] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > [11/11] Drop handle argument from the member functions of struct acpi_dock_ops. > > All of that is relateively straightforward, but I have some more intrusive changes > on top of it in the works. They will be posted separately later this week. I've learned a couple of things since I sent this patchset. First, all bus->devices list walks that may remove PCI devices should be done in reverse order or they can crash if virtual functions are involved. Second, hotplug_event() (in acpiphp_glue.c) has to acquire pci_rescan_remove_lock by itself, because it may be called from multiple places and all of them need that lock to be held. That is done by patches [1-2/13] which I'm planning to push as fixes for 3.14-rc2. The rest is pretty much the same as last time except that the old patch [9/11] became [3/13] in this series and it has been changed so that the list is walked in reverse order. Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 1/13] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki @ 2014-02-02 0:21 ` Rafael J. Wysocki 2014-02-02 0:22 ` [PATCH v2 2/13] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() Rafael J. Wysocki ` (13 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:21 UTC (permalink / raw) To: ACPI Devel Maling List, Linux PCI Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> According to the changelog of commit 29ed1f29b68a (PCI: pciehp: Fix null pointer deref when hot-removing SR-IOV device) it is unsafe to walk the bus->devices list of a PCI bus and remove devices from it in direct order, because that may lead to NULL pointer dereferences related to virtual functions. For this reason, change all of the bus->devices list walks in acpiphp_glue.c during which devices may be removed to be carried out in reverse order. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -742,7 +742,7 @@ static void trim_stale_devices(struct pc /* The device is a bridge. so check the bus below it. */ pm_runtime_get_sync(&dev->dev); - list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) trim_stale_devices(child); pm_runtime_put(&dev->dev); @@ -773,8 +773,8 @@ static void acpiphp_check_bridge(struct ; /* do nothing */ } else if (get_slot_status(slot) == ACPI_STA_ALL) { /* remove stale devices if any */ - list_for_each_entry_safe(dev, tmp, &bus->devices, - bus_list) + list_for_each_entry_safe_reverse(dev, tmp, + &bus->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot->device) trim_stale_devices(dev); @@ -805,7 +805,7 @@ static void acpiphp_sanitize_bus(struct int i; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; - list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { struct resource *res = &dev->resource[i]; if ((res->flags & type_mask) && !res->start && ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 2/13] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-02-02 0:21 ` [PATCH v2 1/13] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki @ 2014-02-02 0:22 ` Rafael J. Wysocki 2014-02-02 0:23 ` [PATCH v2 3/13] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki ` (12 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:22 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Commit 9217a984671e (ACPI / hotplug / PCI: Use global PCI rescan-remove locking) modified ACPIPHP to protect its PCI device removal and addition code paths from races against sysfs-driven rescan and remove operations with the help of PCI rescan-remove locking. However, it overlooked the fact that hotplug_event_work() is not the only caller of hotplug_event() which may also be called by dock_hotplug_event() and that code path is missing the PCI rescan-remove locking. This means that, although the PCI rescan-remove lock is held as appropriate during the handling of events originating from handle_hotplug_event(), the ACPIPHP's operations resulting from dock events may still suffer the race conditions that commit 9217a984671e was supposed to eliminate. To address that problem, move the PCI rescan-remove locking from hotplug_event_work() to hotplug_event() so that it is used regardless of the way that function is invoked. Revamps: 9217a984671e (ACPI / hotplug / PCI: Use global PCI rescan-remove locking) Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -852,6 +852,7 @@ static void hotplug_event(acpi_handle ha mutex_unlock(&acpiphp_context_lock); + pci_lock_rescan_remove(); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { @@ -905,6 +906,7 @@ static void hotplug_event(acpi_handle ha break; } + pci_unlock_rescan_remove(); if (bridge) put_bridge(bridge); } @@ -915,11 +917,9 @@ static void hotplug_event_work(void *dat acpi_handle handle = context->handle; acpi_scan_lock_acquire(); - pci_lock_rescan_remove(); hotplug_event(handle, type, context); - pci_unlock_rescan_remove(); acpi_scan_lock_release(); acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 3/13] ACPI / hotplug / PCI: Simplify disable_slot() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-02-02 0:21 ` [PATCH v2 1/13] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki 2014-02-02 0:22 ` [PATCH v2 2/13] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() Rafael J. Wysocki @ 2014-02-02 0:23 ` Rafael J. Wysocki 2014-02-02 0:24 ` [PATCH v2 4/13] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki ` (11 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:23 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent PCI core changes related to the rescan/remove locking, the ACPIPHP's disable_slot() function is only called under the general PCI rescan/remove lock, so it doesn't have to use dev_in_slot() any more to avoid race conditions. Make it simply walk the devices on the bus and drop the ones in the slot being disabled and drop dev_in_slot() which has no more users. Moreover, to avoid problems described in the changelog of commit 29ed1f29b68a (PCI: pciehp: Fix null pointer deref when hot-removing SR-IOV device), make disable_slot() carry out the list walk in reverse order. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -604,32 +604,15 @@ static void __ref enable_slot(struct acp } } -/* return first device in slot, acquiring a reference on it */ -static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *dev; - struct pci_dev *ret = NULL; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot->device) { - ret = pci_dev_get(dev); - break; - } - up_read(&pci_bus_sem); - - return ret; -} - /** * disable_slot - disable a slot * @slot: ACPI PHP slot */ static void disable_slot(struct acpiphp_slot *slot) { + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *prev; struct acpiphp_func *func; - struct pci_dev *pdev; /* * enable_slot() enumerates all functions in this device via @@ -637,10 +620,9 @@ static void disable_slot(struct acpiphp_ * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. */ - while ((pdev = dev_in_slot(slot))) { - pci_stop_and_remove_bus_device(pdev); - pci_dev_put(pdev); - } + list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + pci_stop_and_remove_bus_device(dev); list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_trim(func_to_handle(func)); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 4/13] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (2 preceding siblings ...) 2014-02-02 0:23 ` [PATCH v2 3/13] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki @ 2014-02-02 0:24 ` Rafael J. Wysocki 2014-02-02 0:25 ` [PATCH v2 5/13] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki ` (10 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:24 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Add proper kerneldoc comments describing acpiphp_enumerate_slots() and acpiphp_remove_slots(). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -968,9 +968,12 @@ static void handle_hotplug_event(acpi_ha acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -/* - * Create hotplug slots for the PCI bus. - * It should always return 0 to avoid skipping following notifiers. +/** + * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. + * @bus: PCI bus to enumerate the slots for. + * + * A "slot" is an object associated with a PCI device number. All functions + * (PCI devices) with the same bus and device number belong to the same slot. */ void acpiphp_enumerate_slots(struct pci_bus *bus) { @@ -1043,7 +1046,10 @@ void acpiphp_enumerate_slots(struct pci_ } } -/* Destroy hotplug slots associated with the PCI bus */ +/** + * acpiphp_remove_slots - Remove slot objects associated with a given bus. + * @bus: PCI bus to remove the slot objects for. + */ void acpiphp_remove_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 5/13] ACPI / hotplug / PCI: Simplify register_slot() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (3 preceding siblings ...) 2014-02-02 0:24 ` [PATCH v2 4/13] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki @ 2014-02-02 0:25 ` Rafael J. Wysocki 2014-02-02 0:26 ` [PATCH v2 6/13] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki ` (9 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:25 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The err label in register_slot() is only jumped to from one place, so move the code under the label to that place and drop the label. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -316,8 +316,10 @@ static acpi_status register_slot(acpi_ha slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - status = AE_NO_MEMORY; - goto err; + mutex_lock(&acpiphp_context_lock); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + return AE_NO_MEMORY; } slot->bus = bridge->pci_bus; @@ -385,12 +387,6 @@ static acpi_status register_slot(acpi_ha } return AE_OK; - - err: - mutex_lock(&acpiphp_context_lock); - acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); - return status; } static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 6/13] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (4 preceding siblings ...) 2014-02-02 0:25 ` [PATCH v2 5/13] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki @ 2014-02-02 0:26 ` Rafael J. Wysocki 2014-02-02 0:27 ` [PATCH v2 7/13] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki ` (8 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:26 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If trim_stale_devices() calls acpi_bus_trim() directly, we can save a potentially costly acpi_bus_get_device() invocation. After making that change acpiphp_bus_trim() would only be called from one place, so move the code from it to that place and drop it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -468,19 +468,6 @@ static unsigned char acpiphp_max_busnr(s } /** - * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. - * @handle: ACPI device object handle to start from. - */ -static void acpiphp_bus_trim(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) - acpi_bus_trim(adev); -} - -/** * acpiphp_bus_add - Scan ACPI namespace subtree. * @handle: ACPI object handle to start the scan from. */ @@ -620,8 +607,12 @@ static void disable_slot(struct acpiphp_ if (PCI_SLOT(dev->devfn) == slot->device) pci_stop_and_remove_bus_device(dev); - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_trim(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev; + + if (!acpi_bus_get_device(func_to_handle(func), &adev)) + acpi_bus_trim(adev); + } slot->flags &= (~SLOT_ENABLED); } @@ -693,11 +684,12 @@ static unsigned int get_slot_status(stru */ static void trim_stale_devices(struct pci_dev *dev) { - acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); struct pci_bus *bus = dev->subordinate; bool alive = false; - if (handle) { + if (adev) { + acpi_handle handle = adev->handle; acpi_status status; unsigned long long sta; @@ -713,8 +705,8 @@ static void trim_stale_devices(struct pc } if (!alive) { pci_stop_and_remove_bus_device(dev); - if (handle) - acpiphp_bus_trim(handle); + if (adev) + acpi_bus_trim(adev); } else if (bus) { struct pci_dev *child, *tmp; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 7/13] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (5 preceding siblings ...) 2014-02-02 0:26 ` [PATCH v2 6/13] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki @ 2014-02-02 0:27 ` Rafael J. Wysocki 2014-02-02 0:27 ` [PATCH v2 8/13] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki ` (7 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:27 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If a struct acpi_device pointer is passed to acpiphp_no_hotplug() instead of an ACPI handle, the function won't need to call acpi_bus_get_device(), which may be costly, any more. Then, trim_stale_devices() can call acpiphp_no_hotplug() passing the struct acpi_device object it already has directly to that function. Make those changes and update slot_no_hotplug() accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -617,11 +617,8 @@ static void disable_slot(struct acpiphp_ slot->flags &= (~SLOT_ENABLED); } -static bool acpiphp_no_hotplug(acpi_handle handle) +static bool acpiphp_no_hotplug(struct acpi_device *adev) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); return adev && adev->flags.no_hotplug; } @@ -629,10 +626,13 @@ static bool slot_no_hotplug(struct acpip { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - if (acpiphp_no_hotplug(func_to_handle(func))) - return true; + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = NULL; + acpi_bus_get_device(func_to_handle(func), &adev); + if (acpiphp_no_hotplug(adev)) + return true; + } return false; } @@ -689,13 +689,12 @@ static void trim_stale_devices(struct pc bool alive = false; if (adev) { - acpi_handle handle = adev->handle; acpi_status status; unsigned long long sta; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) - || acpiphp_no_hotplug(handle); + || acpiphp_no_hotplug(adev); } if (!alive) { u32 v; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 8/13] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (6 preceding siblings ...) 2014-02-02 0:27 ` [PATCH v2 7/13] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki @ 2014-02-02 0:27 ` Rafael J. Wysocki 2014-02-02 0:28 ` [PATCH v2 9/13] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki ` (6 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:27 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent modifications of the ACPI core making it create a struct acpi_device object for every namespace node representing a device regardless of the current status of that device the ACPIPHP code can store a struct acpi_device pointer instead of an ACPI handle in struct acpiphp_context. This immediately makes it possible to avoid making potentially costly calls to acpi_bus_get_device() in two places and allows some more simplifications to be made going forward. The reason why that is correct is because ACPIPHP only installs hotify handlers for namespace nodes that exist when acpiphp_enumerate_slots() is called for their parent bridge. That only happens if the parent bridge has an ACPI companion associated with it, which means that the ACPI namespace scope in question has been scanned already at that point. That, in turn, means that struct acpi_device objects have been created for all namespace nodes in that scope and pointers to those objects can be stored directly instead of their ACPI handles. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp.h | 9 +++++-- drivers/pci/hotplug/acpiphp_glue.c | 44 +++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 25 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -117,8 +117,8 @@ struct acpiphp_func { }; struct acpiphp_context { - acpi_handle handle; struct acpiphp_func func; + struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; @@ -128,9 +128,14 @@ static inline struct acpiphp_context *fu return container_of(func, struct acpiphp_context, func); } +static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) +{ + return func_to_context(func)->adev; +} + static inline acpi_handle func_to_handle(struct acpiphp_func *func) { - return func_to_context(func)->handle; + return func_to_acpi_device(func)->handle; } /* Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -73,11 +73,11 @@ static void acpiphp_context_handler(acpi /** * acpiphp_init_context - Create hotplug context and grab a reference to it. - * @handle: ACPI object handle to create the context for. + * @adev: ACPI device object to create the context for. * * Call under acpiphp_context_lock. */ -static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; acpi_status status; @@ -86,9 +86,9 @@ static struct acpiphp_context *acpiphp_i if (!context) return NULL; - context->handle = handle; + context->adev = adev; context->refcount = 1; - status = acpi_attach_data(handle, acpiphp_context_handler, context); + status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); if (ACPI_FAILURE(status)) { kfree(context); return NULL; @@ -118,7 +118,7 @@ static struct acpiphp_context *acpiphp_g /** * acpiphp_put_context - Drop a reference to ACPI hotplug context. - * @handle: ACPI object handle to put the context for. + * @context: ACPI hotplug context to drop a reference to. * * The context object is removed if there are no more references to it. * @@ -130,7 +130,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->handle, acpiphp_context_handler); + acpi_detach_data(context->adev->handle, acpiphp_context_handler); kfree(context); } @@ -265,6 +265,7 @@ static acpi_status register_slot(acpi_ha { struct acpiphp_bridge *bridge = data; struct acpiphp_context *context; + struct acpi_device *adev; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -284,12 +285,14 @@ static acpi_status register_slot(acpi_ha "can't evaluate _ADR (%#x)\n", status); return AE_OK; } + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; device = (adr >> 16) & 0xffff; function = adr & 0xffff; mutex_lock(&acpiphp_context_lock); - context = acpiphp_init_context(handle); + context = acpiphp_init_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); acpi_handle_err(handle, "No hotplug context\n"); @@ -607,12 +610,8 @@ static void disable_slot(struct acpiphp_ if (PCI_SLOT(dev->devfn) == slot->device) pci_stop_and_remove_bus_device(dev); - list_for_each_entry(func, &slot->funcs, sibling) { - struct acpi_device *adev; - - if (!acpi_bus_get_device(func_to_handle(func), &adev)) - acpi_bus_trim(adev); - } + list_for_each_entry(func, &slot->funcs, sibling) + acpi_bus_trim(func_to_acpi_device(func)); slot->flags &= (~SLOT_ENABLED); } @@ -626,13 +625,10 @@ static bool slot_no_hotplug(struct acpip { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(func_to_handle(func), &adev); - if (acpiphp_no_hotplug(adev)) + list_for_each_entry(func, &slot->funcs, sibling) + if (acpiphp_no_hotplug(func_to_acpi_device(func))) return true; - } + return false; } @@ -883,7 +879,7 @@ static void hotplug_event(acpi_handle ha static void hotplug_event_work(void *data, u32 type) { struct acpiphp_context *context = data; - acpi_handle handle = context->handle; + acpi_handle handle = context->adev->handle; acpi_scan_lock_acquire(); @@ -941,7 +937,7 @@ static void handle_hotplug_event(acpi_ha mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->handle != handle)) { + if (context && !WARN_ON(context->adev->handle != handle)) { get_bridge(context->func.parent); acpiphp_put_context(context); acpi_hotplug_execute(hotplug_event_work, context, type); @@ -965,16 +961,18 @@ static void handle_hotplug_event(acpi_ha void acpiphp_enumerate_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; + struct acpi_device *adev; acpi_handle handle; acpi_status status; if (acpiphp_disabled) return; - handle = ACPI_HANDLE(bus->bridge); - if (!handle) + adev = ACPI_COMPANION(bus->bridge); + if (!adev) return; + handle = adev->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (!bridge) { acpi_handle_err(handle, "No memory for bridge object\n"); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 9/13] ACPI / hotplug / PCI: Drop acpiphp_bus_add() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (7 preceding siblings ...) 2014-02-02 0:27 ` [PATCH v2 8/13] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki @ 2014-02-02 0:28 ` Rafael J. Wysocki 2014-02-02 0:29 ` [PATCH v2 10/13] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki ` (5 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:28 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> acpiphp_bus_add() is only called from one place, so move the code out of it into that place and drop it. Also make that code use func_to_acpi_device() to get the struct acpi_device pointer it needs instead of calling acpi_bus_get_device() which may be costly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -470,20 +470,6 @@ static unsigned char acpiphp_max_busnr(s return max; } -/** - * acpiphp_bus_add - Scan ACPI namespace subtree. - * @handle: ACPI object handle to start the scan from. - */ -static void acpiphp_bus_add(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_scan(handle); - acpi_bus_get_device(handle, &adev); - if (acpi_device_enumerated(adev)) - acpi_device_set_power(adev, ACPI_STATE_D0); -} - static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) { struct acpiphp_func *func; @@ -523,9 +509,13 @@ static int acpiphp_rescan_slot(struct ac { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); + acpi_bus_scan(adev->handle); + if (acpi_device_enumerated(adev)) + acpi_device_set_power(adev, ACPI_STATE_D0); + } return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 10/13] ACPI / hotplug / PCI: Drop crit_sect locking 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (8 preceding siblings ...) 2014-02-02 0:28 ` [PATCH v2 9/13] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki @ 2014-02-02 0:29 ` Rafael J. Wysocki 2014-02-02 0:30 ` [PATCH v2 11/13] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki ` (4 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:29 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent PCI core changes related to the rescan/remove locking, the code sections under crit_sect mutexes from ACPIPHP slot objects are always executed under the general PCI rescan/remove lock. For this reason, the crit_sect mutexes are simply redundant, so drop them. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 23 +++-------------------- 2 files changed, 3 insertions(+), 21 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -328,7 +328,6 @@ static acpi_status register_slot(acpi_ha slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); list_add_tail(&slot->node, &bridge->slots); @@ -723,7 +722,6 @@ static void acpiphp_check_bridge(struct struct pci_bus *bus = slot->bus; struct pci_dev *dev, *tmp; - mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ } else if (get_slot_status(slot) == ACPI_STA_ALL) { @@ -738,7 +736,6 @@ static void acpiphp_check_bridge(struct } else { disable_slot(slot); } - mutex_unlock(&slot->crit_sect); } } @@ -821,12 +818,8 @@ static void hotplug_event(acpi_handle ha } else { struct acpiphp_slot *slot = func->slot; - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - - mutex_lock(&slot->crit_sect); - enable_slot(slot); - mutex_unlock(&slot->crit_sect); + if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); } break; @@ -837,7 +830,6 @@ static void hotplug_event(acpi_handle ha acpiphp_check_bridge(bridge); } else { struct acpiphp_slot *slot = func->slot; - int ret; if (slot->flags & SLOT_IS_GOING_AWAY) break; @@ -846,10 +838,7 @@ static void hotplug_event(acpi_handle ha * Check if anything has changed in the slot and rescan * from the parent if that's the case. */ - mutex_lock(&slot->crit_sect); - ret = acpiphp_rescan_slot(slot); - mutex_unlock(&slot->crit_sect); - if (ret) + if (acpiphp_rescan_slot(slot)) acpiphp_check_bridge(func->parent); } break; @@ -1055,13 +1044,10 @@ int acpiphp_enable_slot(struct acpiphp_s if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - pci_unlock_rescan_remove(); return 0; } @@ -1077,8 +1063,6 @@ static int acpiphp_disable_and_eject_slo if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); - /* unconfigure all functions */ disable_slot(slot); @@ -1092,7 +1076,6 @@ static int acpiphp_disable_and_eject_slo break; } - mutex_unlock(&slot->crit_sect); return 0; } Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -93,7 +93,6 @@ struct acpiphp_slot { struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; - struct mutex crit_sect; u8 device; /* pci device# */ u32 flags; /* see below */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 11/13] ACPI / hotplug / PCI: Simplify hotplug_event() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (9 preceding siblings ...) 2014-02-02 0:29 ` [PATCH v2 10/13] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki @ 2014-02-02 0:30 ` Rafael J. Wysocki 2014-02-02 0:31 ` [PATCH v2 12/13] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki ` (3 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:30 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> A few lines of code can be cut from hotplug_event() by defining and initializing the slot variable at the top of the function, so do that. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -792,6 +792,7 @@ static void hotplug_event(acpi_handle ha { struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; + struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -813,14 +814,11 @@ static void hotplug_event(acpi_handle ha pr_debug("%s: Bus check notify on %s\n", __func__, objname); pr_debug("%s: re-enumerating slots under %s\n", __func__, objname); - if (bridge) { + if (bridge) acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; + else if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); - if (!(slot->flags & SLOT_IS_GOING_AWAY)) - enable_slot(slot); - } break; case ACPI_NOTIFY_DEVICE_CHECK: @@ -828,12 +826,7 @@ static void hotplug_event(acpi_handle ha pr_debug("%s: Device check notify on %s\n", __func__, objname); if (bridge) { acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - + } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { /* * Check if anything has changed in the slot and rescan * from the parent if that's the case. @@ -846,7 +839,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ pr_debug("%s: Device eject notify on %s\n", __func__, objname); - acpiphp_disable_and_eject_slot(func->slot); + acpiphp_disable_and_eject_slot(slot); break; } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 12/13] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (10 preceding siblings ...) 2014-02-02 0:30 ` [PATCH v2 11/13] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki @ 2014-02-02 0:31 ` Rafael J. Wysocki 2014-02-02 0:31 ` [PATCH v2 13/13] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations Rafael J. Wysocki ` (2 subsequent siblings) 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:31 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Make hotplug_event() use acpi_handle_debug() instead of an open-coded debug message printing and clean up the messages printed by it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -794,9 +794,6 @@ static void hotplug_event(acpi_handle ha struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; mutex_lock(&acpiphp_context_lock); bridge = context->bridge; @@ -806,14 +803,11 @@ static void hotplug_event(acpi_handle ha mutex_unlock(&acpiphp_context_lock); pci_lock_rescan_remove(); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ - pr_debug("%s: Bus check notify on %s\n", __func__, objname); - pr_debug("%s: re-enumerating slots under %s\n", - __func__, objname); + acpi_handle_debug(handle, "Bus check in %s()\n", __func__); if (bridge) acpiphp_check_bridge(bridge); else if (!(slot->flags & SLOT_IS_GOING_AWAY)) @@ -823,7 +817,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - pr_debug("%s: Device check notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Device check in %s()\n", __func__); if (bridge) { acpiphp_check_bridge(bridge); } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { @@ -838,7 +832,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - pr_debug("%s: Device eject notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Eject request in %s()\n", __func__); acpiphp_disable_and_eject_slot(slot); break; } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 13/13] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (11 preceding siblings ...) 2014-02-02 0:31 ` [PATCH v2 12/13] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki @ 2014-02-02 0:31 ` Rafael J. Wysocki 2014-02-03 1:47 ` [PATCH] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock Rafael J. Wysocki 2014-02-03 10:44 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Mika Westerberg 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-02 0:31 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> None of the existing users of struct acpi_dock_ops actually needs the first argument of its member functions, so redefine those functions to take only two arguments, the event type and data pointer, and update the users of struct acpi_dock_ops accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/dock.c | 4 ++-- drivers/ata/libata-acpi.c | 8 ++++---- drivers/pci/hotplug/acpiphp_glue.c | 13 +++++++------ include/acpi/acpi_drivers.h | 6 +++--- 4 files changed, 16 insertions(+), 15 deletions(-) Index: linux-pm/include/acpi/acpi_drivers.h =================================================================== --- linux-pm.orig/include/acpi/acpi_drivers.h +++ linux-pm/include/acpi/acpi_drivers.h @@ -110,9 +110,9 @@ void pci_acpi_crs_quirks(void); Dock Station -------------------------------------------------------------------------- */ struct acpi_dock_ops { - acpi_notify_handler fixup; - acpi_notify_handler handler; - acpi_notify_handler uevent; + void (*handler)(u32 event_type, void *data); + void (*fixup)(u32 event_type, void *data); + void (*uevent)(u32 event_type, void *data); }; #ifdef CONFIG_ACPI_DOCK Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -63,7 +63,7 @@ static DEFINE_MUTEX(acpiphp_context_lock static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); -static void hotplug_event(acpi_handle handle, u32 type, void *data); +static void hotplug_event(u32 type, void *data); static void free_bridge(struct kref *kref); static void acpiphp_context_handler(acpi_handle handle, void *context) @@ -185,7 +185,7 @@ static void free_bridge(struct kref *kre * TBD - figure out a way to only call fixups for * systems that require them. */ -static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) +static void post_dock_fixups(u32 event, void *data) { struct acpiphp_context *context = data; struct pci_bus *bus = context->func.slot->bus; @@ -788,11 +788,12 @@ void acpiphp_check_host_bridge(acpi_hand static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); -static void hotplug_event(acpi_handle handle, u32 type, void *data) +static void hotplug_event(u32 type, void *data) { struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; + acpi_handle handle = context->adev->handle; struct acpiphp_bridge *bridge; mutex_lock(&acpiphp_context_lock); @@ -845,14 +846,14 @@ static void hotplug_event(acpi_handle ha static void hotplug_event_work(void *data, u32 type) { struct acpiphp_context *context = data; - acpi_handle handle = context->adev->handle; acpi_scan_lock_acquire(); - hotplug_event(handle, type, context); + hotplug_event(type, context); acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); + acpi_evaluate_hotplug_ost(context->adev->handle, type, + ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); } Index: linux-pm/drivers/acpi/dock.c =================================================================== --- linux-pm.orig/drivers/acpi/dock.c +++ linux-pm/drivers/acpi/dock.c @@ -185,7 +185,7 @@ static void dock_release_hotplug(struct static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, enum dock_callback_type cb_type) { - acpi_notify_handler cb = NULL; + void (*cb)(u32, void *) = NULL; bool run = false; mutex_lock(&hotplug_lock); @@ -213,7 +213,7 @@ static void dock_hotplug_event(struct do return; if (cb) - cb(dd->handle, event, dd->hp_context); + cb(event, dd->hp_context); dock_release_hotplug(dd); } Index: linux-pm/drivers/ata/libata-acpi.c =================================================================== --- linux-pm.orig/drivers/ata/libata-acpi.c +++ linux-pm/drivers/ata/libata-acpi.c @@ -121,14 +121,14 @@ static void ata_acpi_handle_hotplug(stru ata_port_wait_eh(ap); } -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_notify_dock(u32 event, void *data) { struct ata_device *dev = data; ata_acpi_handle_hotplug(dev->link->ap, dev, event); } -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_notify_dock(u32 event, void *data) { struct ata_port *ap = data; @@ -154,12 +154,12 @@ static void ata_acpi_uevent(struct ata_p } } -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_uevent(u32 event, void *data) { ata_acpi_uevent(data, NULL, event); } -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_uevent(u32 event, void *data) { struct ata_device *dev = data; ata_acpi_uevent(dev->link->ap, dev, event); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (12 preceding siblings ...) 2014-02-02 0:31 ` [PATCH v2 13/13] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations Rafael J. Wysocki @ 2014-02-03 1:47 ` Rafael J. Wysocki 2014-02-03 10:44 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Mika Westerberg 14 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 1:47 UTC (permalink / raw) To: ACPI Devel Maling List, Linux PCI Cc: Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Mika Westerberg From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpiphp_check_bridge() called by acpiphp_check_host_bridge() does things that require PCI rescan-remove locking around it, make acpiphp_check_host_bridge() use that locking. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- One more thing I overlooked in the PCI rescan-remove locking patchset. I just found it sitting there in a dark dusty corner and staring at me in horror when I approached it with a vacuum cleaner ... Anyway, 3.14-rc2 material on top of patches [1-2/13] from this series: https://lkml.org/lkml/2014/2/1/123 Thanks, Rafael --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++++ 1 file changed, 4 insertions(+) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -829,7 +829,11 @@ void acpiphp_check_host_bridge(acpi_hand bridge = acpiphp_handle_to_bridge(handle); if (bridge) { + pci_lock_rescan_remove(); + acpiphp_check_bridge(bridge); + + pci_unlock_rescan_remove(); put_bridge(bridge); } } ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (13 preceding siblings ...) 2014-02-03 1:47 ` [PATCH] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock Rafael J. Wysocki @ 2014-02-03 10:44 ` Mika Westerberg 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki 14 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-02-03 10:44 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Sun, Feb 02, 2014 at 01:19:33AM +0100, Rafael J. Wysocki wrote: > On Monday, January 27, 2014 01:37:17 AM Rafael J. Wysocki wrote: > > Hi All, > > > > ACPIPHP can be simplified a bit on top of some PCI and ACPI changes merged > > recently and the following series of patches implements those simplifications: > > > > [1/11] Fix up two kerneldoc comments in acpiphp_glue.c. > > [2/11] Get rid of an unnecessary label in register_slot(). > > [3/11] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > > [4/11] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > > [5/11] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > > [6/11] Drop acpiphp_bus_add() (which has only one user). > > [7/11] Drop crit_sect mutexes (that are redundant). > > [8/11] Clean up the usage of the slot variable in hotplug_event(). > > [9/11] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > > [10/11] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > > [11/11] Drop handle argument from the member functions of struct acpi_dock_ops. > > > > All of that is relateively straightforward, but I have some more intrusive changes > > on top of it in the works. They will be posted separately later this week. > > I've learned a couple of things since I sent this patchset. First, all > bus->devices list walks that may remove PCI devices should be done in reverse > order or they can crash if virtual functions are involved. Second, hotplug_event() > (in acpiphp_glue.c) has to acquire pci_rescan_remove_lock by itself, because it > may be called from multiple places and all of them need that lock to be held. > That is done by patches [1-2/13] which I'm planning to push as fixes for 3.14-rc2. > > The rest is pretty much the same as last time except that the old patch [9/11] > became [3/13] in this series and it has been changed so that the list is walked in > reverse order. On Intel NUC and DZ77RE-75K, Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core 2014-02-03 10:44 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Mika Westerberg @ 2014-02-03 23:12 ` Rafael J. Wysocki 2014-02-03 23:14 ` [PATCH 1/24][Resend] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki ` (24 more replies) 0 siblings, 25 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:12 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Monday, February 03, 2014 12:44:08 PM Mika Westerberg wrote: > On Sun, Feb 02, 2014 at 01:19:33AM +0100, Rafael J. Wysocki wrote: > > On Monday, January 27, 2014 01:37:17 AM Rafael J. Wysocki wrote: > > > Hi All, > > > > > > ACPIPHP can be simplified a bit on top of some PCI and ACPI changes merged > > > recently and the following series of patches implements those simplifications: > > > > > > [1/11] Fix up two kerneldoc comments in acpiphp_glue.c. > > > [2/11] Get rid of an unnecessary label in register_slot(). > > > [3/11] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > > > [4/11] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > > > [5/11] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > > > [6/11] Drop acpiphp_bus_add() (which has only one user). > > > [7/11] Drop crit_sect mutexes (that are redundant). > > > [8/11] Clean up the usage of the slot variable in hotplug_event(). > > > [9/11] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > > > [10/11] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > > > [11/11] Drop handle argument from the member functions of struct acpi_dock_ops. > > > > > > All of that is relateively straightforward, but I have some more intrusive changes > > > on top of it in the works. They will be posted separately later this week. > > > > I've learned a couple of things since I sent this patchset. First, all > > bus->devices list walks that may remove PCI devices should be done in reverse > > order or they can crash if virtual functions are involved. Second, hotplug_event() > > (in acpiphp_glue.c) has to acquire pci_rescan_remove_lock by itself, because it > > may be called from multiple places and all of them need that lock to be held. > > That is done by patches [1-2/13] which I'm planning to push as fixes for 3.14-rc2. > > > > The rest is pretty much the same as last time except that the old patch [9/11] > > became [3/13] in this series and it has been changed so that the list is walked in > > reverse order. > > On Intel NUC and DZ77RE-75K, > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Thanks! As I said previously, I have found two concurrency-related bugs more in ACPIPHP and I needed to put fixes for those bugs at the top of the series (after previous [1-2/13] and the patch at https://patchwork.kernel.org/patch/3567701/). For this reason, I also had to rebase the ACPI/PCI hotplug consolidation patchset (https://lkml.org/lkml/2014/2/2/87) which got a few additional cosmetic changes too. The following is a combination of the two series with one patch dropped (it would conflict with [4-5/24]) and a few patches added. It is on top of 3.14-rc1. Patches [1-5/24], that are regarded as 3.14-rc2 material, are on the bleeding-edge branch of linux-pm.git. The remaining patches will show up in bleeding-edge shortly. [1/24] Remove entries from bus->devices in reverse order (in ACPIPHP). [2/24] Move PCI rescan-remove locking to hotplug_event(). [3/24] Scan root bus under the PCI rescan-remove lock [4/24] Fix race in handle_hotplug_event() related to concurrent bridge removal. [5/24] Fix race in hotplug_event() related to dock events and concurrent bridge removal. [6/24] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. [7/24] Fix up two kerneldoc comments in acpiphp_glue.c. [8/24] Get rid of an unnecessary label in register_slot(). [9/24] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. [10/24] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). [11/24] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. [12/24] Drop acpiphp_bus_add() (which has only one user). [13/24] Drop crit_sect mutexes (that are redundant). [14/24] Clean up the usage of the slot variable in hotplug_event(). [15/24] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. [16/24] Do not pass ACPI handle to hotplug_event(). [17/24] Add a new function to ACPICA allowing a callback to be executed under the namespace mutex after calling acpi_ns_get_attached_data(). [18/24] Use the new ACPICA's function to fix a couple of potential races related to ACPI notifies. [19/24] Move the hotplug context lock definition to the ACPI core (from ACPIPHP). [20/24] Consolidate ACPI hotplug signaling for PCI and ACPI core. [21/24] Rework the handling of eject requests in the ACPI core. [22/24] Simplify a routine for installing hotplug notify handlers. [23/24] Dispatch ACPI hotplug notifications for "core" devices and PCI from acpi_bus_notify(). [24/24] Pass struct acpi_device pointer to acpiphp_check_host_bridge(). Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 1/24][Resend] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki @ 2014-02-03 23:14 ` Rafael J. Wysocki 2014-02-03 23:15 ` [PATCH 2/24][Resend] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() Rafael J. Wysocki ` (23 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:14 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> According to the changelog of commit 29ed1f29b68a (PCI: pciehp: Fix null pointer deref when hot-removing SR-IOV device) it is unsafe to walk the bus->devices list of a PCI bus and remove devices from it in direct order, because that may lead to NULL pointer dereferences related to virtual functions. For this reason, change all of the bus->devices list walks in acpiphp_glue.c during which devices may be removed to be carried out in reverse order. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -742,7 +742,7 @@ static void trim_stale_devices(struct pc /* The device is a bridge. so check the bus below it. */ pm_runtime_get_sync(&dev->dev); - list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) trim_stale_devices(child); pm_runtime_put(&dev->dev); @@ -773,8 +773,8 @@ static void acpiphp_check_bridge(struct ; /* do nothing */ } else if (get_slot_status(slot) == ACPI_STA_ALL) { /* remove stale devices if any */ - list_for_each_entry_safe(dev, tmp, &bus->devices, - bus_list) + list_for_each_entry_safe_reverse(dev, tmp, + &bus->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot->device) trim_stale_devices(dev); @@ -805,7 +805,7 @@ static void acpiphp_sanitize_bus(struct int i; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; - list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { struct resource *res = &dev->resource[i]; if ((res->flags & type_mask) && !res->start && ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 2/24][Resend] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki 2014-02-03 23:14 ` [PATCH 1/24][Resend] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki @ 2014-02-03 23:15 ` Rafael J. Wysocki 2014-02-03 23:16 ` [PATCH 3/24][Resend] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock Rafael J. Wysocki ` (22 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:15 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Commit 9217a984671e (ACPI / hotplug / PCI: Use global PCI rescan-remove locking) modified ACPIPHP to protect its PCI device removal and addition code paths from races against sysfs-driven rescan and remove operations with the help of PCI rescan-remove locking. However, it overlooked the fact that hotplug_event_work() is not the only caller of hotplug_event() which may also be called by dock_hotplug_event() and that code path is missing the PCI rescan-remove locking. This means that, although the PCI rescan-remove lock is held as appropriate during the handling of events originating from handle_hotplug_event(), the ACPIPHP's operations resulting from dock events may still suffer the race conditions that commit 9217a984671e was supposed to eliminate. To address that problem, move the PCI rescan-remove locking from hotplug_event_work() to hotplug_event() so that it is used regardless of the way that function is invoked. Revamps: 9217a984671e (ACPI / hotplug / PCI: Use global PCI rescan-remove locking) Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -852,6 +852,7 @@ static void hotplug_event(acpi_handle ha mutex_unlock(&acpiphp_context_lock); + pci_lock_rescan_remove(); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { @@ -905,6 +906,7 @@ static void hotplug_event(acpi_handle ha break; } + pci_unlock_rescan_remove(); if (bridge) put_bridge(bridge); } @@ -915,11 +917,9 @@ static void hotplug_event_work(void *dat acpi_handle handle = context->handle; acpi_scan_lock_acquire(); - pci_lock_rescan_remove(); hotplug_event(handle, type, context); - pci_unlock_rescan_remove(); acpi_scan_lock_release(); acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 3/24][Resend] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki 2014-02-03 23:14 ` [PATCH 1/24][Resend] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki 2014-02-03 23:15 ` [PATCH 2/24][Resend] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() Rafael J. Wysocki @ 2014-02-03 23:16 ` Rafael J. Wysocki 2014-02-03 23:18 ` [PATCH 4/24][New] ACPI / hotplug / PCI: Fix bridge removal race in handle_hotplug_event() Rafael J. Wysocki ` (21 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:16 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpiphp_check_bridge() called by acpiphp_check_host_bridge() does things that require PCI rescan-remove locking around it, make acpiphp_check_host_bridge() use that locking. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++++ 1 file changed, 4 insertions(+) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -829,7 +829,11 @@ void acpiphp_check_host_bridge(acpi_hand bridge = acpiphp_handle_to_bridge(handle); if (bridge) { + pci_lock_rescan_remove(); + acpiphp_check_bridge(bridge); + + pci_unlock_rescan_remove(); put_bridge(bridge); } } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 4/24][New] ACPI / hotplug / PCI: Fix bridge removal race in handle_hotplug_event() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (2 preceding siblings ...) 2014-02-03 23:16 ` [PATCH 3/24][Resend] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock Rafael J. Wysocki @ 2014-02-03 23:18 ` Rafael J. Wysocki 2014-02-03 23:18 ` [PATCH 5/24][New] ACPI / hotplug / PCI: Fix bridge removal race vs dock events Rafael J. Wysocki ` (20 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:18 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If a PCI bridge with an ACPIPHP context attached is removed via sysfs, the code path executed as a result is the following: pci_stop_and_remove_bus_device_locked pci_remove_bus pcibios_remove_bus acpi_pci_remove_bus acpiphp_remove_slots cleanup_bridge put_bridge free_bridge acpiphp_put_context (for each child, under context lock) kfree (child context) Now, if a hotplug notify is dispatched for one of the bridge's children and the timing is such that handle_hotplug_event() for that notify is executed while free_bridge() above is running, the get_bridge(context->func.parent) in handle_hotplug_event() will not really help, because it is too late to prevent the bridge from going away and the child's context may be freed before hotplug_event_work() scheduled from handle_hotplug_event() dereferences the pointer to it passed via the data argument. That will cause a kernel crash to happpen in hotplug_event_work(). To prevent that from happening, make handle_hotplug_event() check the is_going_away flag of the function's parent bridge (under acpiphp_context_lock) and bail out if it's set. Also, make cleanup_bridge() set the bridge's is_going_away flag under acpiphp_context_lock so that it cannot be changed between the check and the subsequent get_bridge(context->func.parent) in handle_hotplug_event(). Then, in the above scenario, handle_hotplug_event() will notice that context->func.parent->is_going_away is already set and it will exit immediately preventing the crash from happening. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -441,7 +441,9 @@ static void cleanup_bridge(struct acpiph list_del(&bridge->list); mutex_unlock(&bridge_mutex); + mutex_lock(&acpiphp_context_lock); bridge->is_going_away = true; + mutex_unlock(&acpiphp_context_lock); } /** @@ -941,6 +943,7 @@ static void handle_hotplug_event(acpi_ha { struct acpiphp_context *context; u32 ost_code = ACPI_OST_SC_SUCCESS; + acpi_status status; switch (type) { case ACPI_NOTIFY_BUS_CHECK: @@ -976,13 +979,20 @@ static void handle_hotplug_event(acpi_ha mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); + if (!context || WARN_ON(context->handle != handle) + || context->func.parent->is_going_away) + goto err_out; + + get_bridge(context->func.parent); + acpiphp_put_context(context); + status = acpi_hotplug_execute(hotplug_event_work, context, type); + if (ACPI_SUCCESS(status)) { mutex_unlock(&acpiphp_context_lock); return; } + put_bridge(context->func.parent); + + err_out: mutex_unlock(&acpiphp_context_lock); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 5/24][New] ACPI / hotplug / PCI: Fix bridge removal race vs dock events 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (3 preceding siblings ...) 2014-02-03 23:18 ` [PATCH 4/24][New] ACPI / hotplug / PCI: Fix bridge removal race in handle_hotplug_event() Rafael J. Wysocki @ 2014-02-03 23:18 ` Rafael J. Wysocki 2014-02-03 23:20 ` [PATCH 6/24][Resend] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki ` (19 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:18 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If a PCI bridge with an ACPIPHP context attached is removed via sysfs, the code path executed as a result is the following: pci_stop_and_remove_bus_device_locked pci_remove_bus pcibios_remove_bus acpi_pci_remove_bus acpiphp_remove_slots cleanup_bridge unregister_hotplug_dock_device (drops dock references to the bridge) put_bridge free_bridge acpiphp_put_context (for each child, under context lock) kfree (context) Now, if a dock event affecting one of the bridge's child devices occurs (roughly at the same time), it will lead to the following code path: acpi_dock_deferred_cb dock_notify handle_eject_request hot_remove_dock_devices dock_hotplug_event hotplug_event (dereferences context) That may lead to a kernel crash in hotplug_event() if it is executed after the last kfree() in the bridge removal code path. To prevent that from happening, add a wrapper around hotplug_event() called dock_event() and point the .handler pointer in acpiphp_dock_ops to it. Make that wrapper retrieve the device's ACPIPHP context using acpiphp_get_context() (instead of taking it from the data argument) under acpiphp_context_lock and check if the parent bridge's is_going_away flag is set. If that flag is set, it will return immediately and if it is not set it will grab a reference to the device's parent bridge before executing hotplug_event(). Then, in the above scenario, the reference to the parent bridge held by dock_event() will prevent free_bridge() from being executed for it until hotplug_event() returns. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -210,10 +210,29 @@ static void post_dock_fixups(acpi_handle } } +static void dock_event(acpi_handle handle, u32 type, void *data) +{ + struct acpiphp_context *context; + + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (!context || WARN_ON(context->handle != handle) + || context->func.parent->is_going_away) { + mutex_unlock(&acpiphp_context_lock); + return; + } + get_bridge(context->func.parent); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + + hotplug_event(handle, type, data); + + put_bridge(context->func.parent); +} static const struct acpi_dock_ops acpiphp_dock_ops = { .fixup = post_dock_fixups, - .handler = hotplug_event, + .handler = dock_event, }; /* Check whether the PCI device is managed by native PCIe hotplug driver */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 6/24][Resend] ACPI / hotplug / PCI: Simplify disable_slot() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (4 preceding siblings ...) 2014-02-03 23:18 ` [PATCH 5/24][New] ACPI / hotplug / PCI: Fix bridge removal race vs dock events Rafael J. Wysocki @ 2014-02-03 23:20 ` Rafael J. Wysocki 2014-02-03 23:21 ` [PATCH 7/24][Resend] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki ` (18 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:20 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent PCI core changes related to the rescan/remove locking, the ACPIPHP's disable_slot() function is only called under the general PCI rescan/remove lock, so it doesn't have to use dev_in_slot() any more to avoid race conditions. Make it simply walk the devices on the bus and drop the ones in the slot being disabled and drop dev_in_slot() which has no more users. Moreover, to avoid problems described in the changelog of commit 29ed1f29b68a (PCI: pciehp: Fix null pointer deref when hot-removing SR-IOV device), make disable_slot() carry out the list walk in reverse order. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -625,32 +625,15 @@ static void __ref enable_slot(struct acp } } -/* return first device in slot, acquiring a reference on it */ -static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *dev; - struct pci_dev *ret = NULL; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot->device) { - ret = pci_dev_get(dev); - break; - } - up_read(&pci_bus_sem); - - return ret; -} - /** * disable_slot - disable a slot * @slot: ACPI PHP slot */ static void disable_slot(struct acpiphp_slot *slot) { + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *prev; struct acpiphp_func *func; - struct pci_dev *pdev; /* * enable_slot() enumerates all functions in this device via @@ -658,10 +641,9 @@ static void disable_slot(struct acpiphp_ * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. */ - while ((pdev = dev_in_slot(slot))) { - pci_stop_and_remove_bus_device(pdev); - pci_dev_put(pdev); - } + list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + pci_stop_and_remove_bus_device(dev); list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_trim(func_to_handle(func)); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 7/24][Resend] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (5 preceding siblings ...) 2014-02-03 23:20 ` [PATCH 6/24][Resend] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki @ 2014-02-03 23:21 ` Rafael J. Wysocki 2014-02-03 23:22 ` [PATCH 8/24][Resend] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki ` (17 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:21 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Add proper kerneldoc comments describing acpiphp_enumerate_slots() and acpiphp_remove_slots(). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -1001,9 +1001,12 @@ static void handle_hotplug_event(acpi_ha acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -/* - * Create hotplug slots for the PCI bus. - * It should always return 0 to avoid skipping following notifiers. +/** + * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. + * @bus: PCI bus to enumerate the slots for. + * + * A "slot" is an object associated with a PCI device number. All functions + * (PCI devices) with the same bus and device number belong to the same slot. */ void acpiphp_enumerate_slots(struct pci_bus *bus) { @@ -1076,7 +1079,10 @@ void acpiphp_enumerate_slots(struct pci_ } } -/* Destroy hotplug slots associated with the PCI bus */ +/** + * acpiphp_remove_slots - Remove slot objects associated with a given bus. + * @bus: PCI bus to remove the slot objects for. + */ void acpiphp_remove_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 8/24][Resend] ACPI / hotplug / PCI: Simplify register_slot() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (6 preceding siblings ...) 2014-02-03 23:21 ` [PATCH 7/24][Resend] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki @ 2014-02-03 23:22 ` Rafael J. Wysocki 2014-02-03 23:23 ` [PATCH 9/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki ` (16 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:22 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The err label in register_slot() is only jumped to from one place, so move the code under the label to that place and drop the label. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -335,8 +335,10 @@ static acpi_status register_slot(acpi_ha slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - status = AE_NO_MEMORY; - goto err; + mutex_lock(&acpiphp_context_lock); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + return AE_NO_MEMORY; } slot->bus = bridge->pci_bus; @@ -404,12 +406,6 @@ static acpi_status register_slot(acpi_ha } return AE_OK; - - err: - mutex_lock(&acpiphp_context_lock); - acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); - return status; } static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 9/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (7 preceding siblings ...) 2014-02-03 23:22 ` [PATCH 8/24][Resend] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki @ 2014-02-03 23:23 ` Rafael J. Wysocki 2014-02-03 23:24 ` [PATCH 10/24][Resend] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki ` (15 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:23 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If trim_stale_devices() calls acpi_bus_trim() directly, we can save a potentially costly acpi_bus_get_device() invocation. After making that change acpiphp_bus_trim() would only be called from one place, so move the code from it to that place and drop it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -489,19 +489,6 @@ static unsigned char acpiphp_max_busnr(s } /** - * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. - * @handle: ACPI device object handle to start from. - */ -static void acpiphp_bus_trim(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) - acpi_bus_trim(adev); -} - -/** * acpiphp_bus_add - Scan ACPI namespace subtree. * @handle: ACPI object handle to start the scan from. */ @@ -641,8 +628,12 @@ static void disable_slot(struct acpiphp_ if (PCI_SLOT(dev->devfn) == slot->device) pci_stop_and_remove_bus_device(dev); - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_trim(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev; + + if (!acpi_bus_get_device(func_to_handle(func), &adev)) + acpi_bus_trim(adev); + } slot->flags &= (~SLOT_ENABLED); } @@ -714,11 +705,12 @@ static unsigned int get_slot_status(stru */ static void trim_stale_devices(struct pci_dev *dev) { - acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); struct pci_bus *bus = dev->subordinate; bool alive = false; - if (handle) { + if (adev) { + acpi_handle handle = adev->handle; acpi_status status; unsigned long long sta; @@ -734,8 +726,8 @@ static void trim_stale_devices(struct pc } if (!alive) { pci_stop_and_remove_bus_device(dev); - if (handle) - acpiphp_bus_trim(handle); + if (adev) + acpi_bus_trim(adev); } else if (bus) { struct pci_dev *child, *tmp; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 10/24][Resend] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (8 preceding siblings ...) 2014-02-03 23:23 ` [PATCH 9/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki @ 2014-02-03 23:24 ` Rafael J. Wysocki 2014-02-03 23:25 ` [PATCH 11/24][Update] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki ` (14 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:24 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> If a struct acpi_device pointer is passed to acpiphp_no_hotplug() instead of an ACPI handle, the function won't need to call acpi_bus_get_device(), which may be costly, any more. Then, trim_stale_devices() can call acpiphp_no_hotplug() passing the struct acpi_device object it already has directly to that function. Make those changes and update slot_no_hotplug() accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -638,11 +638,8 @@ static void disable_slot(struct acpiphp_ slot->flags &= (~SLOT_ENABLED); } -static bool acpiphp_no_hotplug(acpi_handle handle) +static bool acpiphp_no_hotplug(struct acpi_device *adev) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); return adev && adev->flags.no_hotplug; } @@ -650,10 +647,13 @@ static bool slot_no_hotplug(struct acpip { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - if (acpiphp_no_hotplug(func_to_handle(func))) - return true; + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = NULL; + acpi_bus_get_device(func_to_handle(func), &adev); + if (acpiphp_no_hotplug(adev)) + return true; + } return false; } @@ -710,13 +710,12 @@ static void trim_stale_devices(struct pc bool alive = false; if (adev) { - acpi_handle handle = adev->handle; acpi_status status; unsigned long long sta; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) - || acpiphp_no_hotplug(handle); + || acpiphp_no_hotplug(adev); } if (!alive) { u32 v; ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 11/24][Update] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (9 preceding siblings ...) 2014-02-03 23:24 ` [PATCH 10/24][Resend] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki @ 2014-02-03 23:25 ` Rafael J. Wysocki 2014-02-03 23:26 ` [PATCH 12/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki ` (13 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:25 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent modifications of the ACPI core making it create a struct acpi_device object for every namespace node representing a device regardless of the current status of that device the ACPIPHP code can store a struct acpi_device pointer instead of an ACPI handle in struct acpiphp_context. This immediately makes it possible to avoid making potentially costly calls to acpi_bus_get_device() in two places and allows some more simplifications to be made going forward. The reason why that is correct is because ACPIPHP only installs hotify handlers for namespace nodes that exist when acpiphp_enumerate_slots() is called for their parent bridge. That only happens if the parent bridge has an ACPI companion associated with it, which means that the ACPI namespace scope in question has been scanned already at that point. That, in turn, means that struct acpi_device objects have been created for all namespace nodes in that scope and pointers to those objects can be stored directly instead of their ACPI handles. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp.h | 9 +++++-- drivers/pci/hotplug/acpiphp_glue.c | 46 +++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 26 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -117,8 +117,8 @@ struct acpiphp_func { }; struct acpiphp_context { - acpi_handle handle; struct acpiphp_func func; + struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; @@ -128,9 +128,14 @@ static inline struct acpiphp_context *fu return container_of(func, struct acpiphp_context, func); } +static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) +{ + return func_to_context(func)->adev; +} + static inline acpi_handle func_to_handle(struct acpiphp_func *func) { - return func_to_context(func)->handle; + return func_to_acpi_device(func)->handle; } /* Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -73,11 +73,11 @@ static void acpiphp_context_handler(acpi /** * acpiphp_init_context - Create hotplug context and grab a reference to it. - * @handle: ACPI object handle to create the context for. + * @adev: ACPI device object to create the context for. * * Call under acpiphp_context_lock. */ -static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; acpi_status status; @@ -86,9 +86,9 @@ static struct acpiphp_context *acpiphp_i if (!context) return NULL; - context->handle = handle; + context->adev = adev; context->refcount = 1; - status = acpi_attach_data(handle, acpiphp_context_handler, context); + status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); if (ACPI_FAILURE(status)) { kfree(context); return NULL; @@ -118,7 +118,7 @@ static struct acpiphp_context *acpiphp_g /** * acpiphp_put_context - Drop a reference to ACPI hotplug context. - * @handle: ACPI object handle to put the context for. + * @context: ACPI hotplug context to drop a reference to. * * The context object is removed if there are no more references to it. * @@ -130,7 +130,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->handle, acpiphp_context_handler); + acpi_detach_data(context->adev->handle, acpiphp_context_handler); kfree(context); } @@ -216,7 +216,7 @@ static void dock_event(acpi_handle handl mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->handle != handle) + if (!context || WARN_ON(context->adev->handle != handle) || context->func.parent->is_going_away) { mutex_unlock(&acpiphp_context_lock); return; @@ -284,6 +284,7 @@ static acpi_status register_slot(acpi_ha { struct acpiphp_bridge *bridge = data; struct acpiphp_context *context; + struct acpi_device *adev; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -303,12 +304,14 @@ static acpi_status register_slot(acpi_ha "can't evaluate _ADR (%#x)\n", status); return AE_OK; } + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; device = (adr >> 16) & 0xffff; function = adr & 0xffff; mutex_lock(&acpiphp_context_lock); - context = acpiphp_init_context(handle); + context = acpiphp_init_context(adev); if (!context) { mutex_unlock(&acpiphp_context_lock); acpi_handle_err(handle, "No hotplug context\n"); @@ -628,12 +631,8 @@ static void disable_slot(struct acpiphp_ if (PCI_SLOT(dev->devfn) == slot->device) pci_stop_and_remove_bus_device(dev); - list_for_each_entry(func, &slot->funcs, sibling) { - struct acpi_device *adev; - - if (!acpi_bus_get_device(func_to_handle(func), &adev)) - acpi_bus_trim(adev); - } + list_for_each_entry(func, &slot->funcs, sibling) + acpi_bus_trim(func_to_acpi_device(func)); slot->flags &= (~SLOT_ENABLED); } @@ -647,13 +646,10 @@ static bool slot_no_hotplug(struct acpip { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(func_to_handle(func), &adev); - if (acpiphp_no_hotplug(adev)) + list_for_each_entry(func, &slot->funcs, sibling) + if (acpiphp_no_hotplug(func_to_acpi_device(func))) return true; - } + return false; } @@ -908,7 +904,7 @@ static void hotplug_event(acpi_handle ha static void hotplug_event_work(void *data, u32 type) { struct acpiphp_context *context = data; - acpi_handle handle = context->handle; + acpi_handle handle = context->adev->handle; acpi_scan_lock_acquire(); @@ -967,7 +963,7 @@ static void handle_hotplug_event(acpi_ha mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->handle != handle) + if (!context || WARN_ON(context->adev->handle != handle) || context->func.parent->is_going_away) goto err_out; @@ -998,16 +994,18 @@ static void handle_hotplug_event(acpi_ha void acpiphp_enumerate_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; + struct acpi_device *adev; acpi_handle handle; acpi_status status; if (acpiphp_disabled) return; - handle = ACPI_HANDLE(bus->bridge); - if (!handle) + adev = ACPI_COMPANION(bus->bridge); + if (!adev) return; + handle = adev->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (!bridge) { acpi_handle_err(handle, "No memory for bridge object\n"); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 12/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_add() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (10 preceding siblings ...) 2014-02-03 23:25 ` [PATCH 11/24][Update] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki @ 2014-02-03 23:26 ` Rafael J. Wysocki 2014-02-03 23:27 ` [PATCH 13/24][Resend] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki ` (12 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:26 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> acpiphp_bus_add() is only called from one place, so move the code out of it into that place and drop it. Also make that code use func_to_acpi_device() to get the struct acpi_device pointer it needs instead of calling acpi_bus_get_device() which may be costly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -491,20 +491,6 @@ static unsigned char acpiphp_max_busnr(s return max; } -/** - * acpiphp_bus_add - Scan ACPI namespace subtree. - * @handle: ACPI object handle to start the scan from. - */ -static void acpiphp_bus_add(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_scan(handle); - acpi_bus_get_device(handle, &adev); - if (acpi_device_enumerated(adev)) - acpi_device_set_power(adev, ACPI_STATE_D0); -} - static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) { struct acpiphp_func *func; @@ -544,9 +530,13 @@ static int acpiphp_rescan_slot(struct ac { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); + acpi_bus_scan(adev->handle); + if (acpi_device_enumerated(adev)) + acpi_device_set_power(adev, ACPI_STATE_D0); + } return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 13/24][Resend] ACPI / hotplug / PCI: Drop crit_sect locking 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (11 preceding siblings ...) 2014-02-03 23:26 ` [PATCH 12/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki @ 2014-02-03 23:27 ` Rafael J. Wysocki 2014-02-03 23:33 ` [PATCH 14/24][Update] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki ` (11 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:27 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> After recent PCI core changes related to the rescan/remove locking, the code sections under crit_sect mutexes from ACPIPHP slot objects are always executed under the general PCI rescan/remove lock. For this reason, the crit_sect mutexes are simply redundant, so drop them. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 23 +++-------------------- 2 files changed, 3 insertions(+), 21 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -347,7 +347,6 @@ static acpi_status register_slot(acpi_ha slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); list_add_tail(&slot->node, &bridge->slots); @@ -744,7 +743,6 @@ static void acpiphp_check_bridge(struct struct pci_bus *bus = slot->bus; struct pci_dev *dev, *tmp; - mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ } else if (get_slot_status(slot) == ACPI_STA_ALL) { @@ -759,7 +757,6 @@ static void acpiphp_check_bridge(struct } else { disable_slot(slot); } - mutex_unlock(&slot->crit_sect); } } @@ -846,12 +843,8 @@ static void hotplug_event(acpi_handle ha } else { struct acpiphp_slot *slot = func->slot; - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - - mutex_lock(&slot->crit_sect); - enable_slot(slot); - mutex_unlock(&slot->crit_sect); + if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); } break; @@ -862,7 +855,6 @@ static void hotplug_event(acpi_handle ha acpiphp_check_bridge(bridge); } else { struct acpiphp_slot *slot = func->slot; - int ret; if (slot->flags & SLOT_IS_GOING_AWAY) break; @@ -871,10 +863,7 @@ static void hotplug_event(acpi_handle ha * Check if anything has changed in the slot and rescan * from the parent if that's the case. */ - mutex_lock(&slot->crit_sect); - ret = acpiphp_rescan_slot(slot); - mutex_unlock(&slot->crit_sect); - if (ret) + if (acpiphp_rescan_slot(slot)) acpiphp_check_bridge(func->parent); } break; @@ -1088,13 +1077,10 @@ int acpiphp_enable_slot(struct acpiphp_s if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - pci_unlock_rescan_remove(); return 0; } @@ -1110,8 +1096,6 @@ static int acpiphp_disable_and_eject_slo if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); - /* unconfigure all functions */ disable_slot(slot); @@ -1125,7 +1109,6 @@ static int acpiphp_disable_and_eject_slo break; } - mutex_unlock(&slot->crit_sect); return 0; } Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -93,7 +93,6 @@ struct acpiphp_slot { struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; - struct mutex crit_sect; u8 device; /* pci device# */ u32 flags; /* see below */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 14/24][Update] ACPI / hotplug / PCI: Simplify hotplug_event() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (12 preceding siblings ...) 2014-02-03 23:27 ` [PATCH 13/24][Resend] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki @ 2014-02-03 23:33 ` Rafael J. Wysocki 2014-02-03 23:33 ` [PATCH 15/24][Resend] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki ` (10 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:33 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> A few lines of code can be cut from hotplug_event() by defining and initializing the slot variable at the top of the function, so do that. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -817,6 +817,7 @@ static void hotplug_event(acpi_handle ha { struct acpiphp_context *context = data; struct acpiphp_func *func = &context->func; + struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -838,14 +839,11 @@ static void hotplug_event(acpi_handle ha pr_debug("%s: Bus check notify on %s\n", __func__, objname); pr_debug("%s: re-enumerating slots under %s\n", __func__, objname); - if (bridge) { + if (bridge) acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; + else if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); - if (!(slot->flags & SLOT_IS_GOING_AWAY)) - enable_slot(slot); - } break; case ACPI_NOTIFY_DEVICE_CHECK: @@ -853,12 +851,7 @@ static void hotplug_event(acpi_handle ha pr_debug("%s: Device check notify on %s\n", __func__, objname); if (bridge) { acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - + } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { /* * Check if anything has changed in the slot and rescan * from the parent if that's the case. @@ -871,7 +864,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ pr_debug("%s: Device eject notify on %s\n", __func__, objname); - acpiphp_disable_and_eject_slot(func->slot); + acpiphp_disable_and_eject_slot(slot); break; } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 15/24][Resend] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (13 preceding siblings ...) 2014-02-03 23:33 ` [PATCH 14/24][Update] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki @ 2014-02-03 23:33 ` Rafael J. Wysocki 2014-02-03 23:34 ` [PATCH 16/24][New] ACPI / hotplug / PCI: Do not pass ACPI handle to hotplug_event() Rafael J. Wysocki ` (9 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:33 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Make hotplug_event() use acpi_handle_debug() instead of an open-coded debug message printing and clean up the messages printed by it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -819,9 +819,6 @@ static void hotplug_event(acpi_handle ha struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; mutex_lock(&acpiphp_context_lock); bridge = context->bridge; @@ -831,14 +828,11 @@ static void hotplug_event(acpi_handle ha mutex_unlock(&acpiphp_context_lock); pci_lock_rescan_remove(); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ - pr_debug("%s: Bus check notify on %s\n", __func__, objname); - pr_debug("%s: re-enumerating slots under %s\n", - __func__, objname); + acpi_handle_debug(handle, "Bus check in %s()\n", __func__); if (bridge) acpiphp_check_bridge(bridge); else if (!(slot->flags & SLOT_IS_GOING_AWAY)) @@ -848,7 +842,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - pr_debug("%s: Device check notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Device check in %s()\n", __func__); if (bridge) { acpiphp_check_bridge(bridge); } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { @@ -863,7 +857,7 @@ static void hotplug_event(acpi_handle ha case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - pr_debug("%s: Device eject notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Eject request in %s()\n", __func__); acpiphp_disable_and_eject_slot(slot); break; } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 16/24][New] ACPI / hotplug / PCI: Do not pass ACPI handle to hotplug_event() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (14 preceding siblings ...) 2014-02-03 23:33 ` [PATCH 15/24][Resend] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki @ 2014-02-03 23:34 ` Rafael J. Wysocki 2014-02-03 23:34 ` [PATCH 17/24][Resend] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki ` (8 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:34 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since hotplug_event() can get the ACPI handle needed for debug printouts from its context argument, there's no need to pass the handle to it. Moreover, the second argument's type may be changed to (struct acpiphp_context *), because that's what is always passed to hotplug_event() as the second argument anyway. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/pci/hotplug/acpiphp_glue.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -63,7 +63,7 @@ static DEFINE_MUTEX(acpiphp_context_lock static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); -static void hotplug_event(acpi_handle handle, u32 type, void *data); +static void hotplug_event(u32 type, struct acpiphp_context *context); static void free_bridge(struct kref *kref); static void acpiphp_context_handler(acpi_handle handle, void *context) @@ -225,7 +225,7 @@ static void dock_event(acpi_handle handl acpiphp_put_context(context); mutex_unlock(&acpiphp_context_lock); - hotplug_event(handle, type, data); + hotplug_event(type, context); put_bridge(context->func.parent); } @@ -813,9 +813,9 @@ void acpiphp_check_host_bridge(acpi_hand static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); -static void hotplug_event(acpi_handle handle, u32 type, void *data) +static void hotplug_event(u32 type, struct acpiphp_context *context) { - struct acpiphp_context *context = data; + acpi_handle handle = context->adev->handle; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; @@ -870,14 +870,14 @@ static void hotplug_event(acpi_handle ha static void hotplug_event_work(void *data, u32 type) { struct acpiphp_context *context = data; - acpi_handle handle = context->adev->handle; acpi_scan_lock_acquire(); - hotplug_event(handle, type, context); + hotplug_event(type, context); acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); + acpi_evaluate_hotplug_ost(context->adev->handle, type, + ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); } ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 17/24][Resend] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (15 preceding siblings ...) 2014-02-03 23:34 ` [PATCH 16/24][New] ACPI / hotplug / PCI: Do not pass ACPI handle to hotplug_event() Rafael J. Wysocki @ 2014-02-03 23:34 ` Rafael J. Wysocki 2014-02-03 23:36 ` [PATCH 18/24][Update] ACPI / hotplug: Fix potential race in acpi_bus_notify() Rafael J. Wysocki ` (7 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:34 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Introduce a new function, acpi_get_data_full(), working in analogy with acpi_get_data() except that it can execute a callback provided as its 4th argument right after acpi_ns_get_attached_data() has returned a success. That will allow Linux to reference count the object pointed to by *data before the namespace mutex is released so as to ensure that it will not be freed going forward until the reference to it acquired by acpi_get_data_full() is dropped. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/acpi/acpica/nsxfeval.c | 33 ++++++++++++++++++++++++++++++--- include/acpi/acpixf.h | 4 ++++ 2 files changed, 34 insertions(+), 3 deletions(-) Index: linux-pm/drivers/acpi/acpica/nsxfeval.c =================================================================== --- linux-pm.orig/drivers/acpi/acpica/nsxfeval.c +++ linux-pm/drivers/acpi/acpica/nsxfeval.c @@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data) /******************************************************************************* * - * FUNCTION: acpi_get_data + * FUNCTION: acpi_get_data_full * * PARAMETERS: obj_handle - Namespace node * handler - Handler used in call to attach_data * data - Where the data is returned + * callback - function to execute before returning * * RETURN: Status * - * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * DESCRIPTION: Retrieve data that was previously attached to a namespace node + * and execute a callback before returning. * ******************************************************************************/ acpi_status -acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) +acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler, + void **data, void (*callback)(void *)) { struct acpi_namespace_node *node; acpi_status status; @@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, ac } status = acpi_ns_get_attached_data(node, handler, data); + if (ACPI_SUCCESS(status) && callback) { + callback(*data); + } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); } +ACPI_EXPORT_SYMBOL(acpi_get_data_full) + +/******************************************************************************* + * + * FUNCTION: acpi_get_data + * + * PARAMETERS: obj_handle - Namespace node + * handler - Handler used in call to attach_data + * data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * + ******************************************************************************/ +acpi_status +acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) +{ + return acpi_get_data_full(obj_handle, handler, data, NULL); +} + ACPI_EXPORT_SYMBOL(acpi_get_data) Index: linux-pm/include/acpi/acpixf.h =================================================================== --- linux-pm.orig/include/acpi/acpixf.h +++ linux-pm/include/acpi/acpixf.h @@ -230,6 +230,10 @@ acpi_attach_data(acpi_handle object, acp acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); acpi_status +acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, + void (*callback)(void *)); + +acpi_status acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); acpi_status ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 18/24][Update] ACPI / hotplug: Fix potential race in acpi_bus_notify() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (16 preceding siblings ...) 2014-02-03 23:34 ` [PATCH 17/24][Resend] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki @ 2014-02-03 23:36 ` Rafael J. Wysocki 2014-02-03 23:36 ` [PATCH 19/24][Update] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki ` (6 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:36 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> There is a slight possibility for the ACPI device object pointed to by adev in acpi_hotplug_notify_cb() to become invalid between the acpi_bus_get_device() that it comes from and the subsequent dereference of that pointer under get_device(). Namely, if acpi_scan_drop_device() runs in parallel with acpi_hotplug_notify_cb(), acpi_device_del_work_fn() queued up by it may delete the device object in question right after a successful execution of acpi_bus_get_device() in acpi_bus_notify(). An analogous problem is present in acpi_bus_notify() where the device pointer coming from acpi_bus_get_device() may become invalid before it subsequent dereference in the "if" block. To prevent that from happening, introduce a new function, acpi_bus_get_acpi_device(), working analogously to acpi_bus_get_device() except that it will grab a reference to the ACPI device object returned by it and it will do that under the ACPICA's namespace mutex. Then, make both acpi_hotplug_notify_cb() and acpi_bus_notify() use acpi_bus_get_acpi_device() instead of acpi_bus_get_device() so as to ensure that the pointers used by them will not become stale at one point. In addition to that, introduce acpi_bus_put_acpi_device() as a wrapper around put_device() to be used along with acpi_bus_get_acpi_device() and make the (new) users of the latter use acpi_bus_put_acpi_device() too. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 6 ++++-- drivers/acpi/scan.c | 42 ++++++++++++++++++++++++++++++++++-------- include/acpi/acpi_bus.h | 2 ++ 3 files changed, 40 insertions(+), 10 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -476,7 +476,7 @@ static void acpi_device_hotplug(void *da out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); - put_device(&adev->dev); + acpi_bus_put_acpi_device(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); } @@ -488,9 +488,6 @@ static void acpi_hotplug_notify_cb(acpi_ struct acpi_device *adev; acpi_status status; - if (acpi_bus_get_device(handle, &adev)) - goto err_out; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); @@ -512,12 +509,15 @@ static void acpi_hotplug_notify_cb(acpi_ /* non-hotplug event; possibly handled by other handler */ return; } - get_device(&adev->dev); + adev = acpi_bus_get_acpi_device(handle); + if (!adev) + goto err_out; + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) return; - put_device(&adev->dev); + acpi_bus_put_acpi_device(adev); err_out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); @@ -1112,14 +1112,16 @@ static void acpi_scan_drop_device(acpi_h mutex_unlock(&acpi_device_del_lock); } -int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device, + void (*callback)(void *)) { acpi_status status; if (!device) return -EINVAL; - status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device); + status = acpi_get_data_full(handle, acpi_scan_drop_device, + (void **)device, callback); if (ACPI_FAILURE(status) || !*device) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", handle)); @@ -1127,8 +1129,32 @@ int acpi_bus_get_device(acpi_handle hand } return 0; } + +int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +{ + return acpi_get_device_data(handle, device, NULL); +} EXPORT_SYMBOL(acpi_bus_get_device); +static void get_acpi_device(void *dev) +{ + if (dev) + get_device(&((struct acpi_device *)dev)->dev); +} + +struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle) +{ + struct acpi_device *adev = NULL; + + acpi_get_device_data(handle, &adev, get_acpi_device); + return adev; +} + +void acpi_bus_put_acpi_device(struct acpi_device *adev) +{ + put_device(&adev->dev); +} + int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)) { Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -340,7 +340,7 @@ static void acpi_bus_osc_support(void) */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - struct acpi_device *device = NULL; + struct acpi_device *device; struct acpi_driver *driver; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", @@ -387,12 +387,14 @@ static void acpi_bus_notify(acpi_handle break; } - acpi_bus_get_device(handle, &device); + device = acpi_bus_get_acpi_device(handle); if (device) { driver = device->driver; if (driver && driver->ops.notify && (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) driver->ops.notify(device, type); + + acpi_bus_put_acpi_device(device); } } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -381,6 +381,8 @@ extern int unregister_acpi_notifier(stru */ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); +struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle); +void acpi_bus_put_acpi_device(struct acpi_device *adev); acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 19/24][Update] ACPI / hotplug / PCI: Define hotplug context lock in the core 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (17 preceding siblings ...) 2014-02-03 23:36 ` [PATCH 18/24][Update] ACPI / hotplug: Fix potential race in acpi_bus_notify() Rafael J. Wysocki @ 2014-02-03 23:36 ` Rafael J. Wysocki 2014-02-03 23:37 ` [PATCH 20/24][Update] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki ` (5 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:36 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Subsequent changes will require the ACPI core to acquire the lock protecting the ACPIPHP hotplug contexts, so move the definition of the lock to the core and change its name to be more generic. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 11 +++++++ drivers/pci/hotplug/acpiphp_glue.c | 51 ++++++++++++++++++------------------- include/acpi/acpi_bus.h | 2 + 3 files changed, 38 insertions(+), 26 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); +static DEFINE_MUTEX(acpi_hp_context_lock); struct acpi_device_bus_id{ char bus_id[15]; @@ -60,6 +61,16 @@ void acpi_scan_lock_release(void) } EXPORT_SYMBOL_GPL(acpi_scan_lock_release); +void acpi_lock_hp_context(void) +{ + mutex_lock(&acpi_hp_context_lock); +} + +void acpi_unlock_hp_context(void) +{ + mutex_unlock(&acpi_hp_context_lock); +} + int acpi_scan_add_handler(struct acpi_scan_handler *handler) { if (!handler || !handler->attach) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -58,7 +58,6 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static DEFINE_MUTEX(acpiphp_context_lock); static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); @@ -75,7 +74,7 @@ static void acpiphp_context_handler(acpi * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { @@ -100,7 +99,7 @@ static struct acpiphp_context *acpiphp_i * acpiphp_get_context - Get hotplug context and grab a reference to it. * @handle: ACPI object handle to get the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) { @@ -122,7 +121,7 @@ static struct acpiphp_context *acpiphp_g * * The context object is removed if there are no more references to it. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static void acpiphp_put_context(struct acpiphp_context *context) { @@ -151,7 +150,7 @@ static void free_bridge(struct kref *kre struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = container_of(kref, struct acpiphp_bridge, ref); @@ -175,7 +174,7 @@ static void free_bridge(struct kref *kre pci_dev_put(bridge->pci_dev); kfree(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /* @@ -214,16 +213,16 @@ static void dock_event(acpi_handle handl { struct acpiphp_context *context; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (!context || WARN_ON(context->adev->handle != handle) || context->func.parent->is_going_away) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return; } get_bridge(context->func.parent); acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); hotplug_event(type, context); @@ -310,17 +309,17 @@ static acpi_status register_slot(acpi_ha device = (adr >> 16) & 0xffff; function = adr & 0xffff; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_init_context(adev); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); acpi_handle_err(handle, "No hotplug context\n"); return AE_NOT_EXIST; } newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -338,9 +337,9 @@ static acpi_status register_slot(acpi_ha slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return AE_NO_MEMORY; } @@ -415,7 +414,7 @@ static struct acpiphp_bridge *acpiphp_ha struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (context) { bridge = context->bridge; @@ -424,7 +423,7 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return bridge; } @@ -458,9 +457,9 @@ static void cleanup_bridge(struct acpiph list_del(&bridge->list); mutex_unlock(&bridge_mutex); - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge->is_going_away = true; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /** @@ -820,12 +819,12 @@ static void hotplug_event(u32 type, stru struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = context->bridge; if (bridge) get_bridge(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); pci_lock_rescan_remove(); @@ -927,7 +926,7 @@ static void handle_hotplug_event(acpi_ha goto out; } - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (!context || WARN_ON(context->adev->handle != handle) || context->func.parent->is_going_away) @@ -937,13 +936,13 @@ static void handle_hotplug_event(acpi_ha acpiphp_put_context(context); status = acpi_hotplug_execute(hotplug_event_work, context, type); if (ACPI_SUCCESS(status)) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return; } put_bridge(context->func.parent); err_out: - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; out: @@ -999,10 +998,10 @@ void acpiphp_enumerate_slots(struct pci_ * parent is going to be handled by pciehp, in which case this * bridge is not interesting to us either. */ - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); context = acpiphp_get_context(handle); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); put_device(&bus->dev); pci_dev_put(bridge->pci_dev); kfree(bridge); @@ -1012,7 +1011,7 @@ void acpiphp_enumerate_slots(struct pci_ context->bridge = bridge; /* Get a reference to the parent bridge. */ get_bridge(context->func.parent); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /* must be added to the list prior to calling register_slot */ Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -404,6 +404,8 @@ static inline bool acpi_bus_can_wakeup(a void acpi_scan_lock_acquire(void); void acpi_scan_lock_release(void); +void acpi_lock_hp_context(void); +void acpi_unlock_hp_context(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); int acpi_bus_register_driver(struct acpi_driver *driver); void acpi_bus_unregister_driver(struct acpi_driver *driver); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 20/24][Update] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (18 preceding siblings ...) 2014-02-03 23:36 ` [PATCH 19/24][Update] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki @ 2014-02-03 23:37 ` Rafael J. Wysocki 2014-02-06 13:07 ` [Update][PATCH 20/24] " Rafael J. Wysocki 2014-02-03 23:38 ` [PATCH 21/24][Resend] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki ` (4 subsequent siblings) 24 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:37 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to a theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). In principle, this issue might be addressed by adding a non-empty release handler for ACPIPHP hotplug context objects analogous to acpi_scan_drop_device(), but that would duplicate the code in that function and in acpi_device_del_work_fn(). For this reason, it's better to modify ACPIPHP to attach its device hotplug contexts to struct device objects representing hotplug devices and make it use acpi_hotplug_notify_cb() as its notify handler. At the same time, acpi_device_hotplug() can be modified to dispatch the new .hp.event() callback pointing to acpiphp_hotplug_event() from ACPI device objects associated with PCI devices and use the generic ACPI device hotplug code for device objects with scan handlers attached to them. This allows the existing code duplication between ACPIPHP and the ACPI core to be reduced too and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/scan.c | 106 +++++++++++++++++------ drivers/pci/hotplug/acpiphp.h | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 164 +++++++------------------------------ include/acpi/acpi_bus.h | 22 ++++ 4 files changed, 142 insertions(+), 159 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -450,43 +450,61 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) - goto out; + goto err_out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; + if (adev->handler) { + error = acpi_generic_hotplug_event(adev, src); + } else { + int (*event)(struct acpi_device *, u32); + + acpi_lock_hp_context(); + event = adev->hp ? adev->hp->event : NULL; + acpi_unlock_hp_context(); + /* + * There may be additional notify handlers for device objects + * without the .event() callback, so ignore them here. + */ + if (event) + error = event(adev, src); + else + goto out; } if (!error) ost_code = ACPI_OST_SC_SUCCESS; - out: + err_out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + + out: acpi_bus_put_acpi_device(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); @@ -494,8 +512,8 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -503,26 +521,49 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; adev = acpi_bus_get_acpi_device(handle); if (!adev) - goto err_out; + goto out; status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -530,10 +571,22 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_bus_put_acpi_device(adev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1995,8 +2048,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); + acpi_install_hotplug_notify_handler(handle, handler); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -59,17 +59,12 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, struct acpiphp_context *context); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. @@ -79,39 +74,27 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context = to_acpiphp_context(adev->hp); - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + context->refcount++; return context; } @@ -129,7 +112,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -211,22 +194,13 @@ static void post_dock_fixups(acpi_handle static void dock_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpi_device *adev; - acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->adev->handle != handle) - || context->func.parent->is_going_away) { - acpi_unlock_hp_context(); - return; + adev = acpi_bus_get_acpi_device(handle); + if (adev) { + acpiphp_hotplug_event(adev, type); + acpi_bus_put_acpi_device(adev); } - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_unlock_hp_context(); - - hotplug_event(type, context); - - put_bridge(context->func.parent); } static const struct acpi_dock_ops acpiphp_dock_ops = { @@ -397,25 +371,23 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { + struct acpi_device *adev = acpi_bus_get_acpi_device(handle); struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + if (!adev) + return NULL; + acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -424,6 +396,7 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } acpi_unlock_hp_context(); + acpi_bus_put_acpi_device(adev); return bridge; } @@ -431,7 +404,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -440,13 +412,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -814,7 +781,7 @@ static int acpiphp_disable_and_eject_slo static void hotplug_event(u32 type, struct acpiphp_context *context) { - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; @@ -866,87 +833,24 @@ static void hotplug_event(u32 type, stru put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) -{ - struct acpiphp_context *context = data; - - acpi_scan_lock_acquire(); - - hotplug_event(type, context); - - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->adev->handle != handle) - || context->func.parent->is_going_away) - goto err_out; - - get_bridge(context->func.parent); - acpiphp_put_context(context); - status = acpi_hotplug_execute(hotplug_event_work, context, type); - if (ACPI_SUCCESS(status)) { + context = acpiphp_get_context(adev); + if (!context || context->func.parent->is_going_away) { acpi_unlock_hp_context(); - return; + return -ENODATA; } - put_bridge(context->func.parent); - - err_out: + get_bridge(context->func.parent); + acpiphp_put_context(context); acpi_unlock_hp_context(); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + hotplug_event(type, context); + + put_bridge(context->func.parent); + return 0; } /** @@ -999,7 +903,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { acpi_unlock_hp_context(); put_device(&bus->dev); Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -137,6 +137,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + int (*event)(struct acpi_device *, u32); +}; + +/* * ACPI Driver * ----------- */ @@ -329,6 +339,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; @@ -351,6 +362,15 @@ static inline void acpi_set_device_statu *((u32 *)&adev->status) = sta; } +static inline void acpi_set_hp_context(struct acpi_device *adev, + struct acpi_hotplug_context *hp, + int (*event)(struct acpi_device *, u32)) +{ + hp->self = adev; + hp->event = event; + adev->hp = hp; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; @@ -425,6 +445,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update][PATCH 20/24] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-02-03 23:37 ` [PATCH 20/24][Update] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki @ 2014-02-06 13:07 ` Rafael J. Wysocki 2014-02-06 23:35 ` [Update 2x][PATCH " Rafael J. Wysocki 0 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-06 13:07 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to the theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). In principle, this issue might be addressed by adding a non-empty release handler for ACPIPHP hotplug context objects analogous to acpi_scan_drop_device(), but that would duplicate the code in that function and in acpi_device_del_work_fn(). For this reason, it's better to modify ACPIPHP to attach its device hotplug contexts to struct device objects representing hotplug devices and make it use acpi_hotplug_notify_cb() as its notify handler. At the same time, acpi_device_hotplug() can be modified to dispatch the new .hp.event() callback pointing to acpiphp_hotplug_event() from ACPI device objects associated with PCI devices or use the generic ACPI device hotplug code for device objects with matching scan handlers. This allows the existing code duplication between ACPIPHP and the ACPI core to be reduced too and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- The previous version would cause hotplug notifications to be ignored for devices with matching scan handlers, but without any scan handlers attached to them, so the would not get any hotplug notifications after acpi_bus_trim(). The fix is to introduce a flag meaning "this device should get hotplug notifications" and set it when we know there's a matching scan handler for a device. Thanks, Rafael --- drivers/acpi/scan.c | 137 ++++++++++++++++++++---------- drivers/pci/hotplug/acpiphp.h | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 164 +++++++------------------------------ include/acpi/acpi_bus.h | 25 +++++ 4 files changed, 154 insertions(+), 181 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -450,43 +450,61 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) - goto out; + goto err_out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; + if (adev->flags.hotplug_notify) { + error = acpi_generic_hotplug_event(adev, src); + } else { + int (*event)(struct acpi_device *, u32); + + acpi_lock_hp_context(); + event = adev->hp ? adev->hp->event : NULL; + acpi_unlock_hp_context(); + /* + * There may be additional notify handlers for device objects + * without the .event() callback, so ignore them here. + */ + if (event) + error = event(adev, src); + else + goto out; } if (!error) ost_code = ACPI_OST_SC_SUCCESS; - out: + err_out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + + out: acpi_bus_put_acpi_device(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); @@ -494,8 +512,8 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -503,26 +521,49 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; adev = acpi_bus_get_acpi_device(handle); if (!adev) - goto err_out; + goto out; status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -530,10 +571,22 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_bus_put_acpi_device(adev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1976,33 +2029,21 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) +static void acpi_scan_init_hotplug(struct acpi_device *adev) { - struct acpi_device_pnp pnp = {}; struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - if (!pnp.type.hardware_id) - goto out; + list_for_each_entry(hwid, &adev->pnp.ids, list) { + struct acpi_scan_handler *handler; - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); - break; - } - } + if (!handler) + continue; -out: - acpi_free_pnp_ids(&pnp); + acpi_install_hotplug_notify_handler(adev->handle, handler); + adev->flags.hotplug_notify = true; + break; + } } static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, @@ -2026,12 +2067,12 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; + acpi_scan_init_hotplug(device); + out: if (!*return_value) *return_value = device; Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -59,17 +59,12 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, struct acpiphp_context *context); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. @@ -79,39 +74,27 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context = to_acpiphp_context(adev->hp); - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + context->refcount++; return context; } @@ -129,7 +112,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -211,22 +194,13 @@ static void post_dock_fixups(acpi_handle static void dock_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpi_device *adev; - acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->adev->handle != handle) - || context->func.parent->is_going_away) { - acpi_unlock_hp_context(); - return; + adev = acpi_bus_get_acpi_device(handle); + if (adev) { + acpiphp_hotplug_event(adev, type); + acpi_bus_put_acpi_device(adev); } - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_unlock_hp_context(); - - hotplug_event(type, context); - - put_bridge(context->func.parent); } static const struct acpi_dock_ops acpiphp_dock_ops = { @@ -397,25 +371,23 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { + struct acpi_device *adev = acpi_bus_get_acpi_device(handle); struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + if (!adev) + return NULL; + acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -424,6 +396,7 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } acpi_unlock_hp_context(); + acpi_bus_put_acpi_device(adev); return bridge; } @@ -431,7 +404,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -440,13 +412,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -814,7 +781,7 @@ static int acpiphp_disable_and_eject_slo static void hotplug_event(u32 type, struct acpiphp_context *context) { - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; @@ -866,87 +833,24 @@ static void hotplug_event(u32 type, stru put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) -{ - struct acpiphp_context *context = data; - - acpi_scan_lock_acquire(); - - hotplug_event(type, context); - - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->adev->handle != handle) - || context->func.parent->is_going_away) - goto err_out; - - get_bridge(context->func.parent); - acpiphp_put_context(context); - status = acpi_hotplug_execute(hotplug_event_work, context, type); - if (ACPI_SUCCESS(status)) { + context = acpiphp_get_context(adev); + if (!context || context->func.parent->is_going_away) { acpi_unlock_hp_context(); - return; + return -ENODATA; } - put_bridge(context->func.parent); - - err_out: + get_bridge(context->func.parent); + acpiphp_put_context(context); acpi_unlock_hp_context(); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + hotplug_event(type, context); + + put_bridge(context->func.parent); + return 0; } /** @@ -999,7 +903,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { acpi_unlock_hp_context(); put_device(&bus->dev); Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -137,6 +137,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + int (*event)(struct acpi_device *, u32); +}; + +/* * ACPI Driver * ----------- */ @@ -190,7 +200,8 @@ struct acpi_device_flags { u32 initialized:1; u32 visited:1; u32 no_hotplug:1; - u32 reserved:24; + u32 hotplug_notify:1; + u32 reserved:23; }; /* File System */ @@ -329,6 +340,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; @@ -351,6 +363,15 @@ static inline void acpi_set_device_statu *((u32 *)&adev->status) = sta; } +static inline void acpi_set_hp_context(struct acpi_device *adev, + struct acpi_hotplug_context *hp, + int (*event)(struct acpi_device *, u32)) +{ + hp->self = adev; + hp->event = event; + adev->hp = hp; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; @@ -425,6 +446,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update 2x][PATCH 20/24] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug 2014-02-06 13:07 ` [Update][PATCH 20/24] " Rafael J. Wysocki @ 2014-02-06 23:35 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-06 23:35 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to the theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). In principle, this issue might be addressed by adding a non-empty release handler for ACPIPHP hotplug context objects analogous to acpi_scan_drop_device(), but that would duplicate the code in that function and in acpi_device_del_work_fn(). For this reason, it's better to modify ACPIPHP to attach its device hotplug contexts to struct device objects representing hotplug devices and make it use acpi_hotplug_notify_cb() as its notify handler. At the same time, acpi_device_hotplug() can be modified to dispatch the new .hp.event() callback pointing to acpiphp_hotplug_event() from ACPI device objects associated with PCI devices or use the generic ACPI device hotplug code for device objects with matching scan handlers. This allows the existing code duplication between ACPIPHP and the ACPI core to be reduced too and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- This update fixes the bug reported here: https://lkml.org/lkml/2014/2/6/212 None of the other patches in the series need to be updated because of that. Thanks! --- drivers/acpi/scan.c | 137 +++++++++++++++++++----------- drivers/pci/hotplug/acpiphp.h | 9 + drivers/pci/hotplug/acpiphp_glue.c | 168 ++++++++----------------------------- include/acpi/acpi_bus.h | 25 +++++ 4 files changed, 158 insertions(+), 181 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -450,43 +450,61 @@ static int acpi_scan_bus_check(struct ac return 0; } +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) +{ + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + return acpi_scan_bus_check(adev); + case ACPI_NOTIFY_DEVICE_CHECK: + return acpi_scan_device_check(adev); + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + return acpi_scan_hot_remove(adev); + } + return -EINVAL; +} + static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - int error; + int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before + * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) - goto out; + goto err_out; - switch (src) { - case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; + if (adev->flags.hotplug_notify) { + error = acpi_generic_hotplug_event(adev, src); + } else { + int (*event)(struct acpi_device *, u32); + + acpi_lock_hp_context(); + event = adev->hp ? adev->hp->event : NULL; + acpi_unlock_hp_context(); + /* + * There may be additional notify handlers for device objects + * without the .event() callback, so ignore them here. + */ + if (event) + error = event(adev, src); + else + goto out; } if (!error) ost_code = ACPI_OST_SC_SUCCESS; - out: + err_out: acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + + out: acpi_bus_put_acpi_device(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); @@ -494,8 +512,8 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -503,26 +521,49 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; + case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; + case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (handler && !handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; + goto out; } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; - default: - /* non-hotplug event; possibly handled by other handler */ + + case ACPI_NOTIFY_DEVICE_WAKE: return; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); + goto out; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + goto out; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + goto out; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto out; } + + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; adev = acpi_bus_get_acpi_device(handle); if (!adev) - goto err_out; + goto out; status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) @@ -530,10 +571,22 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_bus_put_acpi_device(adev); - err_out: + out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +{ + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb, data); +} + +void acpi_remove_hotplug_notify_handler(acpi_handle handle) +{ + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + acpi_hotplug_notify_cb); +} + static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1976,33 +2029,21 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) +static void acpi_scan_init_hotplug(struct acpi_device *adev) { - struct acpi_device_pnp pnp = {}; struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - if (!pnp.type.hardware_id) - goto out; + list_for_each_entry(hwid, &adev->pnp.ids, list) { + struct acpi_scan_handler *handler; - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); - break; - } - } + if (!handler) + continue; -out: - acpi_free_pnp_ids(&pnp); + acpi_install_hotplug_notify_handler(adev->handle, handler); + adev->flags.hotplug_notify = true; + break; + } } static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, @@ -2026,12 +2067,12 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; + acpi_scan_init_hotplug(device); + out: if (!*return_value) *return_value = device; Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -116,12 +116,17 @@ struct acpiphp_func { }; struct acpiphp_context { + struct acpi_hotplug_context hp; struct acpiphp_func func; - struct acpi_device *adev; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); @@ -129,7 +134,7 @@ static inline struct acpiphp_context *fu static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) { - return func_to_context(func)->adev; + return func_to_context(func)->hp.self; } static inline acpi_handle func_to_handle(struct acpiphp_func *func) Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -59,17 +59,12 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(u32 type, struct acpiphp_context *context); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. * @adev: ACPI device object to create the context for. @@ -79,39 +74,31 @@ static void acpiphp_context_handler(acpi static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->adev = adev; context->refcount = 1; - status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context; - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + if (!adev->hp) + return NULL; + + context = to_acpiphp_context(adev->hp); + context->refcount++; return context; } @@ -129,7 +116,7 @@ static void acpiphp_put_context(struct a return; WARN_ON(context->bridge); - acpi_detach_data(context->adev->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -211,22 +198,13 @@ static void post_dock_fixups(acpi_handle static void dock_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpi_device *adev; - acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->adev->handle != handle) - || context->func.parent->is_going_away) { - acpi_unlock_hp_context(); - return; + adev = acpi_bus_get_acpi_device(handle); + if (adev) { + acpiphp_hotplug_event(adev, type); + acpi_bus_put_acpi_device(adev); } - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_unlock_hp_context(); - - hotplug_event(type, context); - - put_bridge(context->func.parent); } static const struct acpi_dock_ops acpiphp_dock_ops = { @@ -397,25 +375,23 @@ static acpi_status register_slot(acpi_ha } /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } + if (!(newfunc->flags & FUNC_HAS_DCK)) + acpi_install_hotplug_notify_handler(handle, NULL); return AE_OK; } static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { + struct acpi_device *adev = acpi_bus_get_acpi_device(handle); struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; + if (!adev) + return NULL; + acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -424,6 +400,7 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } acpi_unlock_hp_context(); + acpi_bus_put_acpi_device(adev); return bridge; } @@ -431,7 +408,6 @@ static void cleanup_bridge(struct acpiph { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -440,13 +416,8 @@ static void cleanup_bridge(struct acpiph if (is_dock_device(handle)) unregister_hotplug_dock_device(handle); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + if (!(func->flags & FUNC_HAS_DCK)) + acpi_remove_hotplug_notify_handler(handle); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -814,7 +785,7 @@ static int acpiphp_disable_and_eject_slo static void hotplug_event(u32 type, struct acpiphp_context *context) { - acpi_handle handle = context->adev->handle; + acpi_handle handle = context->hp.self->handle; struct acpiphp_func *func = &context->func; struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; @@ -866,87 +837,24 @@ static void hotplug_event(u32 type, stru put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) -{ - struct acpiphp_context *context = data; - - acpi_scan_lock_acquire(); - - hotplug_event(type, context); - - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(context->adev->handle, type, - ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); -} - -/** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure - * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) +static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) { struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } acpi_lock_hp_context(); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->adev->handle != handle) - || context->func.parent->is_going_away) - goto err_out; - - get_bridge(context->func.parent); - acpiphp_put_context(context); - status = acpi_hotplug_execute(hotplug_event_work, context, type); - if (ACPI_SUCCESS(status)) { + context = acpiphp_get_context(adev); + if (!context || context->func.parent->is_going_away) { acpi_unlock_hp_context(); - return; + return -ENODATA; } - put_bridge(context->func.parent); - - err_out: + get_bridge(context->func.parent); + acpiphp_put_context(context); acpi_unlock_hp_context(); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + hotplug_event(type, context); + + put_bridge(context->func.parent); + return 0; } /** @@ -999,7 +907,7 @@ void acpiphp_enumerate_slots(struct pci_ * bridge is not interesting to us either. */ acpi_lock_hp_context(); - context = acpiphp_get_context(handle); + context = acpiphp_get_context(adev); if (!context) { acpi_unlock_hp_context(); put_device(&bus->dev); Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -137,6 +137,16 @@ struct acpi_scan_handler { }; /* + * ACPI Hotplug Context + * -------------------- + */ + +struct acpi_hotplug_context { + struct acpi_device *self; + int (*event)(struct acpi_device *, u32); +}; + +/* * ACPI Driver * ----------- */ @@ -190,7 +200,8 @@ struct acpi_device_flags { u32 initialized:1; u32 visited:1; u32 no_hotplug:1; - u32 reserved:24; + u32 hotplug_notify:1; + u32 reserved:23; }; /* File System */ @@ -329,6 +340,7 @@ struct acpi_device { struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; struct acpi_driver *driver; void *driver_data; struct device dev; @@ -351,6 +363,15 @@ static inline void acpi_set_device_statu *((u32 *)&adev->status) = sta; } +static inline void acpi_set_hp_context(struct acpi_device *adev, + struct acpi_hotplug_context *hp, + int (*event)(struct acpi_device *, u32)) +{ + hp->self = adev; + hp->event = event; + adev->hp = hp; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; @@ -425,6 +446,8 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); +void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 21/24][Resend] ACPI / hotplug / PCI: Rework the handling of eject requests 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (19 preceding siblings ...) 2014-02-03 23:37 ` [PATCH 20/24][Update] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki @ 2014-02-03 23:38 ` Rafael J. Wysocki 2014-02-03 23:39 ` [PATCH 22/24][Resend] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki ` (3 subsequent siblings) 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:38 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> To avoid the need to install a hotplug notify handler for each ACPI namespace node representing a device and having a matching scan handler, move the check whether or not the ejection of the given device is enabled through its scan handler from acpi_hotplug_notify_cb() to acpi_generic_hotplug_event(). Also, move the execution of ACPI_OST_SC_EJECT_IN_PROGRESS _OST to acpi_generic_hotplug_event(), because in acpi_hotplug_notify_cb() or in acpi_eject_store() we really don't know whether or not the eject is going to be in progress (for example, acpi_hotplug_execute() may still fail without queuing up the work item). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/acpi/scan.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -459,6 +459,12 @@ static int acpi_generic_hotplug_event(st return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: + if (adev->handler && !adev->handler->hotplug.enabled) { + dev_info(&adev->dev, "Eject disabled\n"); + return -EPERM; + } + acpi_evaluate_hotplug_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); return acpi_scan_hot_remove(adev); } return -EINVAL; @@ -483,6 +489,10 @@ static void acpi_device_hotplug(void *da if (adev->handler) { error = acpi_generic_hotplug_event(adev, src); + if (error == -EPERM) { + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + goto err_out; + } } else { int (*event)(struct acpi_device *, u32); @@ -512,7 +522,6 @@ static void acpi_device_hotplug(void *da static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - struct acpi_scan_handler *handler = data; u32 ost_code = ACPI_OST_SC_SUCCESS; struct acpi_device *adev; acpi_status status; @@ -528,13 +537,6 @@ static void acpi_hotplug_notify_cb(acpi_ case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (handler && !handler->hotplug.enabled) { - acpi_handle_err(handle, "Eject disabled\n"); - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto out; - } - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -632,8 +634,6 @@ acpi_eject_store(struct device *d, struc if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) return -ENODEV; - acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&acpi_device->dev); status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, ACPI_OST_EC_OSPM_EJECT); ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 22/24][Resend] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (20 preceding siblings ...) 2014-02-03 23:38 ` [PATCH 21/24][Resend] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki @ 2014-02-03 23:39 ` Rafael J. Wysocki 2014-02-06 13:09 ` [Update][PATCH 22/24] " Rafael J. Wysocki 2014-02-03 23:40 ` [PATCH 23/24][Update] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki ` (2 subsequent siblings) 24 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:39 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_hotplug_notify_cb() does not use its data argument any more, the second argument of acpi_install_hotplug_notify_handler() can be dropped, so do that and update its callers accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> --- drivers/acpi/scan.c | 6 +++--- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_bus.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -577,10 +577,10 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +void acpi_install_hotplug_notify_handler(acpi_handle handle) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, data); + acpi_hotplug_notify_cb, NULL); } void acpi_remove_hotplug_notify_handler(acpi_handle handle) @@ -2048,7 +2048,7 @@ static void acpi_scan_init_hotplug(acpi_ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_hotplug_notify_handler(handle, handler); + acpi_install_hotplug_notify_handler(handle); break; } } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -372,7 +372,7 @@ static acpi_status register_slot(acpi_ha /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle, NULL); + acpi_install_hotplug_notify_handler(handle); return AE_OK; } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -445,7 +445,7 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_install_hotplug_notify_handler(acpi_handle handle); void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update][PATCH 22/24] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() 2014-02-03 23:39 ` [PATCH 22/24][Resend] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-02-06 13:09 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-06 13:09 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Subject: ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Since acpi_hotplug_notify_cb() does not use its data argument any more, the second argument of acpi_install_hotplug_notify_handler() can be dropped, so do that and update its callers accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- This one had to be updated after patch [20/24] had been updated. Thanks, Rafael --- drivers/acpi/scan.c | 6 +++--- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_bus.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -577,10 +577,10 @@ static void acpi_hotplug_notify_cb(acpi_ acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data) +void acpi_install_hotplug_notify_handler(acpi_handle handle) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, data); + acpi_hotplug_notify_cb, NULL); } void acpi_remove_hotplug_notify_handler(acpi_handle handle) @@ -2040,7 +2040,7 @@ static void acpi_scan_init_hotplug(struc if (!handler) continue; - acpi_install_hotplug_notify_handler(adev->handle, handler); + acpi_install_hotplug_notify_handler(adev->handle); adev->flags.hotplug_notify = true; break; } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -372,7 +372,7 @@ static acpi_status register_slot(acpi_ha /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle, NULL); + acpi_install_hotplug_notify_handler(handle); return AE_OK; } Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -446,7 +446,7 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle, void *data); +void acpi_install_hotplug_notify_handler(acpi_handle handle); void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 23/24][Update] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (21 preceding siblings ...) 2014-02-03 23:39 ` [PATCH 22/24][Resend] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki @ 2014-02-03 23:40 ` Rafael J. Wysocki 2014-02-06 13:10 ` [Update][PATCH 23/24] " Rafael J. Wysocki 2014-02-03 23:41 ` [PATCH 24/24][New] ACPI / hotplug / PCI: Rework acpiphp_check_host_bridge() Rafael J. Wysocki 2014-02-05 10:14 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Mika Westerberg 24 siblings, 1 reply; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:40 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since acpi_bus_notify() is executed on all notifications for all devices anyway, make it execute acpi_device_hotplug() for all hotplug events instead of installing notify handlers pointing to the same function for all hotplug devices. This change reduces both the size and complexity of ACPI-based device hotplug code. Moreover, since acpi_device_hotplug() only does significant things for devices that have either an ACPI scan handler, or a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this modification shouldn't change functionality. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/bus.c | 61 +++++++++++++--------- drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 101 ------------------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 24 ++++---- include/acpi/acpi_bus.h | 2 6 files changed, 53 insertions(+), 137 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -340,62 +340,77 @@ static void acpi_bus_osc_support(void) */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - struct acpi_device *device; + struct acpi_device *adev; struct acpi_driver *driver; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", - type, handle)); + acpi_status status; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); break; case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); break; case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ + acpi_handle_err(handle, "Device has suffered a power fault\n"); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto err; } - device = acpi_bus_get_acpi_device(handle); - if (device) { - driver = device->driver; - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(device, type); + adev = acpi_bus_get_acpi_device(handle); + if (!adev) + goto err; + + driver = adev->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(adev, type); - acpi_bus_put_acpi_device(device); + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + case ACPI_NOTIFY_EJECT_REQUEST: + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); + if (ACPI_SUCCESS(status)) + return; + default: + break; } + acpi_bus_put_acpi_device(adev); + return; + + err: + acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } /* -------------------------------------------------------------------------- Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) #endif bool acpi_queue_hotplug_work(struct work_struct *work); +void acpi_device_hotplug(void *data, u32 src); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); /* -------------------------------------------------------------------------- Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -470,7 +470,7 @@ static int acpi_generic_hotplug_event(st return -EINVAL; } -static void acpi_device_hotplug(void *data, u32 src) +void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; @@ -520,75 +520,6 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) -{ - u32 ost_code = ACPI_OST_SC_SUCCESS; - struct acpi_device *adev; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - adev = acpi_bus_get_acpi_device(handle); - if (!adev) - goto out; - - status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); - if (ACPI_SUCCESS(status)) - return; - - acpi_bus_put_acpi_device(adev); - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); -} - -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} - -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); -} - static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2029,34 +1960,6 @@ void acpi_scan_hotplug_enabled(struct ac mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) -{ - struct acpi_device_pnp pnp = {}; - struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; - - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { - handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { - acpi_install_hotplug_notify_handler(handle); - break; - } - } - -out: - acpi_free_pnp_ids(&pnp); -} - static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2078,8 +1981,6 @@ static acpi_status acpi_bus_check_add(ac return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -293,7 +293,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -301,8 +300,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + acpi_unlock_hp_context(); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -370,10 +375,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -407,13 +408,14 @@ static void cleanup_bridge(struct acpiph list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { - acpi_handle handle = func_to_handle(func); + struct acpi_device *adev = func_to_acpi_device(func); - if (is_dock_device(handle)) - unregister_hotplug_dock_device(handle); + if (is_dock_device(adev->handle)) + unregister_hotplug_dock_device(adev->handle); - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); + acpi_lock_hp_context(); + adev->hp->event = NULL; + acpi_unlock_hp_context(); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -445,8 +445,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [Update][PATCH 23/24] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() 2014-02-03 23:40 ` [PATCH 23/24][Update] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-02-06 13:10 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-06 13:10 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Subject: ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Since acpi_bus_notify() is executed on all notifications for all devices anyway, make it execute acpi_device_hotplug() for all hotplug events instead of installing notify handlers pointing to the same function for all hotplug devices. This change reduces both the size and complexity of ACPI-based device hotplug code. Moreover, since acpi_device_hotplug() only does significant things for devices that have either an ACPI scan handler, or a hotplug context with .eject() defined, and those devices had notify handlers pointing to acpi_hotplug_notify_cb() installed before anyway, this modification shouldn't change functionality. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- This one had to be updated after patch [20/24] had been updated. Thanks, Rafael --- drivers/acpi/bus.c | 61 +++++++++++++++++---------- drivers/acpi/internal.h | 1 drivers/acpi/scan.c | 81 ++----------------------------------- drivers/pci/hotplug/acpiphp.h | 1 drivers/pci/hotplug/acpiphp_glue.c | 24 +++++----- include/acpi/acpi_bus.h | 2 6 files changed, 57 insertions(+), 113 deletions(-) Index: linux-pm/drivers/acpi/bus.c =================================================================== --- linux-pm.orig/drivers/acpi/bus.c +++ linux-pm/drivers/acpi/bus.c @@ -340,62 +340,77 @@ static void acpi_bus_osc_support(void) */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - struct acpi_device *device; + struct acpi_device *adev; struct acpi_driver *driver; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", - type, handle)); + acpi_status status; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); break; case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); break; case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ + acpi_handle_err(handle, "Device has suffered a power fault\n"); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto err; } - device = acpi_bus_get_acpi_device(handle); - if (device) { - driver = device->driver; - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(device, type); + adev = acpi_bus_get_acpi_device(handle); + if (!adev) + goto err; + + driver = adev->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(adev, type); - acpi_bus_put_acpi_device(device); + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + case ACPI_NOTIFY_EJECT_REQUEST: + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); + if (ACPI_SUCCESS(status)) + return; + default: + break; } + acpi_bus_put_acpi_device(adev); + return; + + err: + acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } /* -------------------------------------------------------------------------- Index: linux-pm/drivers/acpi/internal.h =================================================================== --- linux-pm.orig/drivers/acpi/internal.h +++ linux-pm/drivers/acpi/internal.h @@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) #endif bool acpi_queue_hotplug_work(struct work_struct *work); +void acpi_device_hotplug(void *data, u32 src); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); /* -------------------------------------------------------------------------- Index: linux-pm/drivers/acpi/scan.c =================================================================== --- linux-pm.orig/drivers/acpi/scan.c +++ linux-pm/drivers/acpi/scan.c @@ -470,7 +470,7 @@ static int acpi_generic_hotplug_event(st return -EINVAL; } -static void acpi_device_hotplug(void *data, u32 src) +void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; @@ -520,75 +520,6 @@ static void acpi_device_hotplug(void *da unlock_device_hotplug(); } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) -{ - u32 ost_code = ACPI_OST_SC_SUCCESS; - struct acpi_device *adev; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - adev = acpi_bus_get_acpi_device(handle); - if (!adev) - goto out; - - status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); - if (ACPI_SUCCESS(status)) - return; - - acpi_bus_put_acpi_device(adev); - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); -} - -void acpi_install_hotplug_notify_handler(acpi_handle handle) -{ - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, NULL); -} - -void acpi_remove_hotplug_notify_handler(acpi_handle handle) -{ - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb); -} - static ssize_t real_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2037,12 +1968,10 @@ static void acpi_scan_init_hotplug(struc struct acpi_scan_handler *handler; handler = acpi_scan_match_handler(hwid->id, NULL); - if (!handler) - continue; - - acpi_install_hotplug_notify_handler(adev->handle); - adev->flags.hotplug_notify = true; - break; + if (handler) { + adev->flags.hotplug_notify = true; + break; + } } } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -293,7 +293,6 @@ static acpi_status register_slot(acpi_ha newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - acpi_unlock_hp_context(); if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -301,8 +300,14 @@ static acpi_status register_slot(acpi_ha if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; + /* + * Dock stations' notify handler should be used for dock devices instead + * of the common one, so clear hp.event in their contexts. + */ if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; + context->hp.event = NULL; + + acpi_unlock_hp_context(); /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) @@ -370,10 +375,6 @@ static acpi_status register_slot(acpi_ha pr_debug("failed to register dock device\n"); } - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) - acpi_install_hotplug_notify_handler(handle); - return AE_OK; } @@ -407,13 +408,14 @@ static void cleanup_bridge(struct acpiph list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { - acpi_handle handle = func_to_handle(func); + struct acpi_device *adev = func_to_acpi_device(func); - if (is_dock_device(handle)) - unregister_hotplug_dock_device(handle); + if (is_dock_device(adev->handle)) + unregister_hotplug_dock_device(adev->handle); - if (!(func->flags & FUNC_HAS_DCK)) - acpi_remove_hotplug_notify_handler(handle); + acpi_lock_hp_context(); + adev->hp->event = NULL; + acpi_unlock_hp_context(); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -446,8 +446,6 @@ static inline bool acpi_device_enumerate typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -void acpi_install_hotplug_notify_handler(acpi_handle handle); -void acpi_remove_hotplug_notify_handler(acpi_handle handle); /** * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver Index: linux-pm/drivers/pci/hotplug/acpiphp.h =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h +++ linux-pm/drivers/pci/hotplug/acpiphp.h @@ -167,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ ^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH 24/24][New] ACPI / hotplug / PCI: Rework acpiphp_check_host_bridge() 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (22 preceding siblings ...) 2014-02-03 23:40 ` [PATCH 23/24][Update] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki @ 2014-02-03 23:41 ` Rafael J. Wysocki 2014-02-05 10:14 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Mika Westerberg 24 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-03 23:41 UTC (permalink / raw) To: ACPI Devel Maling List Cc: Mika Westerberg, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Since the only existing caller of acpiphp_check_host_bridge(), which is acpi_pci_root_scan_dependent(), already has a struct acpi_device pointer needed to obtain the ACPIPHP context, it doesn't make sense to execute acpi_bus_get_device() on its handle in acpiphp_handle_to_bridge() just in order to get that pointer back. For this reason, modify acpiphp_check_host_bridge() to take a struct acpi_device pointer as its argument and rearrange the code accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/pci_root.c | 2 +- drivers/pci/hotplug/acpiphp_glue.c | 11 +++-------- include/linux/pci-acpi.h | 4 ++-- 3 files changed, 6 insertions(+), 11 deletions(-) Index: linux-pm/include/linux/pci-acpi.h =================================================================== --- linux-pm.orig/include/linux/pci-acpi.h +++ linux-pm/include/linux/pci-acpi.h @@ -59,12 +59,12 @@ static inline void acpi_pci_slot_remove( void acpiphp_init(void); void acpiphp_enumerate_slots(struct pci_bus *bus); void acpiphp_remove_slots(struct pci_bus *bus); -void acpiphp_check_host_bridge(acpi_handle handle); +void acpiphp_check_host_bridge(struct acpi_device *adev); #else static inline void acpiphp_init(void) { } static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { } static inline void acpiphp_remove_slots(struct pci_bus *bus) { } -static inline void acpiphp_check_host_bridge(acpi_handle handle) { } +static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { } #endif #else /* CONFIG_ACPI */ Index: linux-pm/drivers/acpi/pci_root.c =================================================================== --- linux-pm.orig/drivers/acpi/pci_root.c +++ linux-pm/drivers/acpi/pci_root.c @@ -51,7 +51,7 @@ static void acpi_pci_root_remove(struct static int acpi_pci_root_scan_dependent(struct acpi_device *adev) { - acpiphp_check_host_bridge(adev->handle); + acpiphp_check_host_bridge(adev); return 0; } Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c =================================================================== --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c @@ -378,15 +378,11 @@ static acpi_status register_slot(acpi_ha return AE_OK; } -static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) +static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) { - struct acpi_device *adev = acpi_bus_get_acpi_device(handle); struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; - if (!adev) - return NULL; - acpi_lock_hp_context(); context = acpiphp_get_context(adev); if (context) { @@ -397,7 +393,6 @@ static struct acpiphp_bridge *acpiphp_ha acpiphp_put_context(context); } acpi_unlock_hp_context(); - acpi_bus_put_acpi_device(adev); return bridge; } @@ -764,11 +759,11 @@ static void acpiphp_sanitize_bus(struct * ACPI event handlers */ -void acpiphp_check_host_bridge(acpi_handle handle) +void acpiphp_check_host_bridge(struct acpi_device *adev) { struct acpiphp_bridge *bridge; - bridge = acpiphp_handle_to_bridge(handle); + bridge = acpiphp_dev_to_bridge(adev); if (bridge) { pci_lock_rescan_remove(); ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki ` (23 preceding siblings ...) 2014-02-03 23:41 ` [PATCH 24/24][New] ACPI / hotplug / PCI: Rework acpiphp_check_host_bridge() Rafael J. Wysocki @ 2014-02-05 10:14 ` Mika Westerberg 2014-02-05 10:59 ` Rafael J. Wysocki 24 siblings, 1 reply; 100+ messages in thread From: Mika Westerberg @ 2014-02-05 10:14 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Tue, Feb 04, 2014 at 12:12:26AM +0100, Rafael J. Wysocki wrote: > As I said previously, I have found two concurrency-related bugs more in ACPIPHP > and I needed to put fixes for those bugs at the top of the series (after previous > [1-2/13] and the patch at https://patchwork.kernel.org/patch/3567701/). For this > reason, I also had to rebase the ACPI/PCI hotplug consolidation patchset > (https://lkml.org/lkml/2014/2/2/87) which got a few additional cosmetic changes too. > > The following is a combination of the two series with one patch dropped (it would > conflict with [4-5/24]) and a few patches added. It is on top of 3.14-rc1. > > Patches [1-5/24], that are regarded as 3.14-rc2 material, are on the bleeding-edge > branch of linux-pm.git. The remaining patches will show up in bleeding-edge > shortly. > > [1/24] Remove entries from bus->devices in reverse order (in ACPIPHP). > [2/24] Move PCI rescan-remove locking to hotplug_event(). > [3/24] Scan root bus under the PCI rescan-remove lock > [4/24] Fix race in handle_hotplug_event() related to concurrent bridge removal. > [5/24] Fix race in hotplug_event() related to dock events and concurrent bridge removal. > [6/24] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > [7/24] Fix up two kerneldoc comments in acpiphp_glue.c. > [8/24] Get rid of an unnecessary label in register_slot(). > [9/24] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > [10/24] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > [11/24] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > [12/24] Drop acpiphp_bus_add() (which has only one user). > [13/24] Drop crit_sect mutexes (that are redundant). > [14/24] Clean up the usage of the slot variable in hotplug_event(). > [15/24] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > [16/24] Do not pass ACPI handle to hotplug_event(). > [17/24] Add a new function to ACPICA allowing a callback to be executed under the > namespace mutex after calling acpi_ns_get_attached_data(). > [18/24] Use the new ACPICA's function to fix a couple of potential races related > to ACPI notifies. > [19/24] Move the hotplug context lock definition to the ACPI core (from ACPIPHP). > [20/24] Consolidate ACPI hotplug signaling for PCI and ACPI core. > [21/24] Rework the handling of eject requests in the ACPI core. > [22/24] Simplify a routine for installing hotplug notify handlers. > [23/24] Dispatch ACPI hotplug notifications for "core" devices and PCI from > acpi_bus_notify(). > [24/24] Pass struct acpi_device pointer to acpiphp_check_host_bridge(). Tried your latest bleeding-edge branch (it seemed to have all the above patches) on my TBT test machines (Acer Aspire S5, Intel NUC and Intel DZ77RE-75K). TBT hotplug works nicely, no deadlocks or anything like that. Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core 2014-02-05 10:14 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Mika Westerberg @ 2014-02-05 10:59 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-05 10:59 UTC (permalink / raw) To: Mika Westerberg Cc: ACPI Devel Maling List, Bjorn Helgaas, Aaron Lu, Linux Kernel Mailing List, Linux PCI On Wednesday, February 05, 2014 12:14:05 PM Mika Westerberg wrote: > On Tue, Feb 04, 2014 at 12:12:26AM +0100, Rafael J. Wysocki wrote: > > As I said previously, I have found two concurrency-related bugs more in ACPIPHP > > and I needed to put fixes for those bugs at the top of the series (after previous > > [1-2/13] and the patch at https://patchwork.kernel.org/patch/3567701/). For this > > reason, I also had to rebase the ACPI/PCI hotplug consolidation patchset > > (https://lkml.org/lkml/2014/2/2/87) which got a few additional cosmetic changes too. > > > > The following is a combination of the two series with one patch dropped (it would > > conflict with [4-5/24]) and a few patches added. It is on top of 3.14-rc1. > > > > Patches [1-5/24], that are regarded as 3.14-rc2 material, are on the bleeding-edge > > branch of linux-pm.git. The remaining patches will show up in bleeding-edge > > shortly. > > > > [1/24] Remove entries from bus->devices in reverse order (in ACPIPHP). > > [2/24] Move PCI rescan-remove locking to hotplug_event(). > > [3/24] Scan root bus under the PCI rescan-remove lock > > [4/24] Fix race in handle_hotplug_event() related to concurrent bridge removal. > > [5/24] Fix race in hotplug_event() related to dock events and concurrent bridge removal. > > [6/24] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > > [7/24] Fix up two kerneldoc comments in acpiphp_glue.c. > > [8/24] Get rid of an unnecessary label in register_slot(). > > [9/24] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > > [10/24] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > > [11/24] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > > [12/24] Drop acpiphp_bus_add() (which has only one user). > > [13/24] Drop crit_sect mutexes (that are redundant). > > [14/24] Clean up the usage of the slot variable in hotplug_event(). > > [15/24] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > > [16/24] Do not pass ACPI handle to hotplug_event(). > > [17/24] Add a new function to ACPICA allowing a callback to be executed under the > > namespace mutex after calling acpi_ns_get_attached_data(). > > [18/24] Use the new ACPICA's function to fix a couple of potential races related > > to ACPI notifies. > > [19/24] Move the hotplug context lock definition to the ACPI core (from ACPIPHP). > > [20/24] Consolidate ACPI hotplug signaling for PCI and ACPI core. > > [21/24] Rework the handling of eject requests in the ACPI core. > > [22/24] Simplify a routine for installing hotplug notify handlers. > > [23/24] Dispatch ACPI hotplug notifications for "core" devices and PCI from > > acpi_bus_notify(). > > [24/24] Pass struct acpi_device pointer to acpiphp_check_host_bridge(). > > Tried your latest bleeding-edge branch (it seemed to have all the above > patches) on my TBT test machines (Acer Aspire S5, Intel NUC and Intel > DZ77RE-75K). Yes, bleeding-edge already has the patches (linux-next has them too now for that matter). > TBT hotplug works nicely, no deadlocks or anything like that. > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Thanks! -- I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki ` (12 preceding siblings ...) 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki @ 2014-02-11 0:19 ` Bjorn Helgaas 2014-02-11 12:53 ` Rafael J. Wysocki 13 siblings, 1 reply; 100+ messages in thread From: Bjorn Helgaas @ 2014-02-11 0:19 UTC (permalink / raw) To: Rafael J. Wysocki Cc: ACPI Devel Maling List, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg On Mon, Jan 27, 2014 at 01:37:17AM +0100, Rafael J. Wysocki wrote: > Hi All, > > ACPIPHP can be simplified a bit on top of some PCI and ACPI changes merged > recently and the following series of patches implements those simplifications: > > [1/11] Fix up two kerneldoc comments in acpiphp_glue.c. > [2/11] Get rid of an unnecessary label in register_slot(). > [3/11] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > [4/11] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > [5/11] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > [6/11] Drop acpiphp_bus_add() (which has only one user). > [7/11] Drop crit_sect mutexes (that are redundant). > [8/11] Clean up the usage of the slot variable in hotplug_event(). > [9/11] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > [10/11] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > [11/11] Drop handle argument from the member functions of struct acpi_dock_ops. I assume you'll handle all these through your tree, Rafael. Let me know if you need me to do anything. Bjorn > All of that is relateively straightforward, but I have some more intrusive changes > on top of it in the works. They will be posted separately later this week. > > Thanks! > > -- > I speak only for myself. > Rafael J. Wysocki, Intel Open Source Technology Center. ^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently 2014-02-11 0:19 ` [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Bjorn Helgaas @ 2014-02-11 12:53 ` Rafael J. Wysocki 0 siblings, 0 replies; 100+ messages in thread From: Rafael J. Wysocki @ 2014-02-11 12:53 UTC (permalink / raw) To: Bjorn Helgaas Cc: ACPI Devel Maling List, Aaron Lu, Linux Kernel Mailing List, Linux PCI, Mika Westerberg On Monday, February 10, 2014 05:19:58 PM Bjorn Helgaas wrote: > On Mon, Jan 27, 2014 at 01:37:17AM +0100, Rafael J. Wysocki wrote: > > Hi All, > > > > ACPIPHP can be simplified a bit on top of some PCI and ACPI changes merged > > recently and the following series of patches implements those simplifications: > > > > [1/11] Fix up two kerneldoc comments in acpiphp_glue.c. > > [2/11] Get rid of an unnecessary label in register_slot(). > > [3/11] Drop acpiphp_bus_trim() and use acpi_bus_trim() instead of it directly. > > [4/11] Move the acpi_bus_get_device() call out of acpiphp_no_hotplug(). > > [5/11] Store struct acpi_device pointers instead of ACPI handles in struct acpiphp_context. > > [6/11] Drop acpiphp_bus_add() (which has only one user). > > [7/11] Drop crit_sect mutexes (that are redundant). > > [8/11] Clean up the usage of the slot variable in hotplug_event(). > > [9/11] Drop dev_in_slot() and rework disable_slot() to walk bus->devices directly. > > [10/11] Use acpi_handle_debug() in hotplug_event() instead of open-coded stuff. > > [11/11] Drop handle argument from the member functions of struct acpi_dock_ops. > > I assume you'll handle all these through your tree, Rafael. Let me know if > you need me to do anything. Yes, I'll handle these, thanks! Rafael ^ permalink raw reply [flat|nested] 100+ messages in thread
end of thread, other threads:[~2014-02-11 12:39 UTC | newest] Thread overview: 100+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-01-27 0:37 [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 1/11] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki 2014-01-27 0:38 ` [PATCH 2/11] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki 2014-01-27 0:39 ` [PATCH 3/11] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki 2014-01-27 0:40 ` [PATCH 4/11] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki 2014-01-27 0:41 ` [PATCH 5/11] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki 2014-01-27 0:41 ` [PATCH 6/11] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki 2014-01-27 0:42 ` [PATCH 7/11] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki 2014-01-27 0:43 ` [PATCH 8/11] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki 2014-01-27 0:44 ` [PATCH 9/11] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki 2014-01-27 0:45 ` [PATCH 10/11] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki 2014-01-27 0:46 ` [PATCH 11/11] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations Rafael J. Wysocki 2014-01-28 22:10 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-01-28 22:12 ` [PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki 2014-01-28 22:13 ` [PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-01-28 22:14 ` [PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki 2014-01-28 22:14 ` [PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-01-28 22:16 ` [PATCH 5/5][RFT] ACPI / hotplug: Dispach hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-01-28 23:57 ` [PATCH 0/5][RFT] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-01-28 23:58 ` [Resend][PATCH 1/5][RFT] ACPI / hotplug / PCI: Attach hotplug contexts to struct acpi_device Rafael J. Wysocki 2014-01-28 23:59 ` [Resend][PATCH 2/5][RFT] ACPI / hotplug: Introduce acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-01-28 23:59 ` [Update][PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki 2014-01-29 0:00 ` [Update][PATCH 4/5][RFT] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-01-31 15:28 ` Mika Westerberg 2014-01-31 15:42 ` Rafael J. Wysocki 2014-01-31 15:40 ` Mika Westerberg 2014-01-31 16:01 ` Mika Westerberg 2014-01-31 16:16 ` Rafael J. Wysocki 2014-01-31 17:09 ` Mika Westerberg 2014-01-31 17:34 ` Rafael J. Wysocki 2014-02-02 0:12 ` Rafael J. Wysocki 2014-01-29 0:02 ` [Update][PATCH 5/5][RFT] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-01-30 15:28 ` [Update 2x][PATCH " Rafael J. Wysocki 2014-02-02 0:52 ` [PATCH v2 0/6] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-02-02 0:54 ` [PATCH v2 1/6] ACPI / hotplug: Fix theoretical race in acpi_hotplug_notify_cb() Rafael J. Wysocki 2014-02-02 17:01 ` Rafael J. Wysocki 2014-02-02 0:55 ` [PATCH v2 2/6] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki 2014-02-02 0:56 ` [PATCH v2 3/6] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki 2014-02-02 0:57 ` [PATCH v2 4/6] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki 2014-02-02 0:58 ` [PATCH v2 5/6] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-02-02 0:58 ` [PATCH v2 6/6] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-02-02 17:11 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Rafael J. Wysocki 2014-02-02 17:12 ` [PATCH v3 1/7] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki 2014-02-02 17:15 ` [PATCH v3 2/7] ACPI / hotplug: Fix potential races in notify handlers Rafael J. Wysocki 2014-02-02 17:16 ` [PATCH v3 3/7] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki 2014-02-02 17:17 ` [PATCH v3 4/7] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki 2014-02-02 17:18 ` [PATCH v3 5/7] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki 2014-02-02 17:19 ` [PATCH v3 6/7] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-02-02 17:20 ` [PATCH v3 7/7] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-02-03 10:45 ` [PATCH v3 0/7] ACPI / hotplug / PCI: Consolidation of ACPIPHP with ACPI core device hotplug Mika Westerberg 2014-02-03 21:51 ` Rafael J. Wysocki 2014-02-02 0:19 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Rafael J. Wysocki 2014-02-02 0:21 ` [PATCH v2 1/13] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki 2014-02-02 0:22 ` [PATCH v2 2/13] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() Rafael J. Wysocki 2014-02-02 0:23 ` [PATCH v2 3/13] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki 2014-02-02 0:24 ` [PATCH v2 4/13] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki 2014-02-02 0:25 ` [PATCH v2 5/13] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki 2014-02-02 0:26 ` [PATCH v2 6/13] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki 2014-02-02 0:27 ` [PATCH v2 7/13] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki 2014-02-02 0:27 ` [PATCH v2 8/13] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki 2014-02-02 0:28 ` [PATCH v2 9/13] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki 2014-02-02 0:29 ` [PATCH v2 10/13] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki 2014-02-02 0:30 ` [PATCH v2 11/13] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki 2014-02-02 0:31 ` [PATCH v2 12/13] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki 2014-02-02 0:31 ` [PATCH v2 13/13] ACPI / hotplug: Do not pass ACPI handles to ACPI dock operations Rafael J. Wysocki 2014-02-03 1:47 ` [PATCH] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock Rafael J. Wysocki 2014-02-03 10:44 ` [PATCH v2 0/13] ACPI / hotplug / PCI: Updates on top of changes merged recently Mika Westerberg 2014-02-03 23:12 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Rafael J. Wysocki 2014-02-03 23:14 ` [PATCH 1/24][Resend] ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order Rafael J. Wysocki 2014-02-03 23:15 ` [PATCH 2/24][Resend] ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() Rafael J. Wysocki 2014-02-03 23:16 ` [PATCH 3/24][Resend] ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock Rafael J. Wysocki 2014-02-03 23:18 ` [PATCH 4/24][New] ACPI / hotplug / PCI: Fix bridge removal race in handle_hotplug_event() Rafael J. Wysocki 2014-02-03 23:18 ` [PATCH 5/24][New] ACPI / hotplug / PCI: Fix bridge removal race vs dock events Rafael J. Wysocki 2014-02-03 23:20 ` [PATCH 6/24][Resend] ACPI / hotplug / PCI: Simplify disable_slot() Rafael J. Wysocki 2014-02-03 23:21 ` [PATCH 7/24][Resend] ACPI / hotplug / PCI: Proper kerneldoc comments for enumeration/removal Rafael J. Wysocki 2014-02-03 23:22 ` [PATCH 8/24][Resend] ACPI / hotplug / PCI: Simplify register_slot() Rafael J. Wysocki 2014-02-03 23:23 ` [PATCH 9/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_trim() Rafael J. Wysocki 2014-02-03 23:24 ` [PATCH 10/24][Resend] ACPI / hotplug / PCI: Rework acpiphp_no_hotplug() Rafael J. Wysocki 2014-02-03 23:25 ` [PATCH 11/24][Update] ACPI / hotplug / PCI: Store acpi_device pointer in acpiphp_context Rafael J. Wysocki 2014-02-03 23:26 ` [PATCH 12/24][Resend] ACPI / hotplug / PCI: Drop acpiphp_bus_add() Rafael J. Wysocki 2014-02-03 23:27 ` [PATCH 13/24][Resend] ACPI / hotplug / PCI: Drop crit_sect locking Rafael J. Wysocki 2014-02-03 23:33 ` [PATCH 14/24][Update] ACPI / hotplug / PCI: Simplify hotplug_event() Rafael J. Wysocki 2014-02-03 23:33 ` [PATCH 15/24][Resend] ACPI / hotplug / PCI: Use acpi_handle_debug() in hotplug_event() Rafael J. Wysocki 2014-02-03 23:34 ` [PATCH 16/24][New] ACPI / hotplug / PCI: Do not pass ACPI handle to hotplug_event() Rafael J. Wysocki 2014-02-03 23:34 ` [PATCH 17/24][Resend] ACPICA: Introduce acpi_get_data_full() and rework acpi_get_data() Rafael J. Wysocki 2014-02-03 23:36 ` [PATCH 18/24][Update] ACPI / hotplug: Fix potential race in acpi_bus_notify() Rafael J. Wysocki 2014-02-03 23:36 ` [PATCH 19/24][Update] ACPI / hotplug / PCI: Define hotplug context lock in the core Rafael J. Wysocki 2014-02-03 23:37 ` [PATCH 20/24][Update] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug Rafael J. Wysocki 2014-02-06 13:07 ` [Update][PATCH 20/24] " Rafael J. Wysocki 2014-02-06 23:35 ` [Update 2x][PATCH " Rafael J. Wysocki 2014-02-03 23:38 ` [PATCH 21/24][Resend] ACPI / hotplug / PCI: Rework the handling of eject requests Rafael J. Wysocki 2014-02-03 23:39 ` [PATCH 22/24][Resend] ACPI / hotplug / PCI: Simplify acpi_install_hotplug_notify_handler() Rafael J. Wysocki 2014-02-06 13:09 ` [Update][PATCH 22/24] " Rafael J. Wysocki 2014-02-03 23:40 ` [PATCH 23/24][Update] ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify() Rafael J. Wysocki 2014-02-06 13:10 ` [Update][PATCH 23/24] " Rafael J. Wysocki 2014-02-03 23:41 ` [PATCH 24/24][New] ACPI / hotplug / PCI: Rework acpiphp_check_host_bridge() Rafael J. Wysocki 2014-02-05 10:14 ` [PATCH v2 0/24] ACPI / hotplug / PCI: ACPIPHP updates and consolidation with ACPI core Mika Westerberg 2014-02-05 10:59 ` Rafael J. Wysocki 2014-02-11 0:19 ` [PATCH 0/11] ACPI / hotplug / PCI: Updates on top of changes merged recently Bjorn Helgaas 2014-02-11 12:53 ` Rafael J. Wysocki
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).