From ecd046da57d3327367b930478234e58f01bc9f0f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:43 +0800 Subject: ACPI: simplify acpiphp driver with new helper functions Use the new helper functions introduced previously to simplify the ACPI-based PCI hotplug (acpiphp) driver. [rjw: Changelog] Signed-off-by: Jiang Liu Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 59df8575a48..a0a7133a1d1 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -201,7 +201,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; - acpi_handle tmp; acpi_status status = AE_OK; unsigned long long adr, sun; int device, function, retval, found = 0; @@ -232,19 +231,19 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) newfunc->handle = handle; newfunc->function = function; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) + if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) + if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) + if (acpi_has_method(handle, "_PS0")) newfunc->flags |= FUNC_HAS_PS0; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) + if (acpi_has_method(handle, "_PS3")) newfunc->flags |= FUNC_HAS_PS3; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) + if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); @@ -843,25 +842,14 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) */ int acpiphp_eject_slot(struct acpiphp_slot *slot) { - acpi_status status; struct acpiphp_func *func; - struct acpi_object_list arg_list; - union acpi_object arg; list_for_each_entry(func, &slot->funcs, sibling) { /* We don't want to call _EJ0 on non-existing functions. */ if ((func->flags & FUNC_HAS_EJ0)) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __func__); + if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle))) return -1; - } else + else break; } } @@ -1171,7 +1159,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) { - acpi_handle dummy_handle; struct acpiphp_bridge *bridge; if (acpiphp_disabled) @@ -1200,8 +1187,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) get_device(&bus->dev); if (!pci_is_root_bus(bridge->pci_bus) && - ACPI_SUCCESS(acpi_get_handle(bridge->handle, - "_EJ0", &dummy_handle))) { + acpi_has_method(bridge->handle, "_EJ0")) { dbg("found ejectable p2p bridge\n"); bridge->flags |= BRIDGE_HAS_EJ0; bridge->func = acpiphp_bridge_handle_to_function(handle); -- cgit v1.2.3-70-g09d2 From f09ce741a03ad7de591aa47e760fbeee28567b63 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:03:25 +0200 Subject: ACPI / dock / PCI: Drop ACPI dock notifier chain The only user of the ACPI dock notifier chain is the ACPI-based PCI hotplug (acpiphp) driver that uses it to carry out post-dock fixups needed by some systems with broken _DCK. However, it is not necessary to use a separate notifier chain for that, as it can be simply replaced with a new callback in struct acpi_dock_ops. For this reason, add a new .fixup() callback to struct acpi_dock_ops and make hotplug_dock_devices() execute it for all dock devices with hotplug operations registered. Accordingly, make acpiphp point that callback to the function carrying out the post-dock fixups and do not register a separate dock notifier for each device registering dock operations. Finally, drop the ACPI dock notifier chain that has no more users. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 66 +++++++++++++++----------------------- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 18 +++-------- include/acpi/acpi_drivers.h | 10 +----- 4 files changed, 30 insertions(+), 65 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 3e20b13fa27..c89a9c3b48b 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -51,8 +51,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " " the driver to wait for userspace to write the undock sysfs file " " before undocking"); -static struct atomic_notifier_head dock_notifier_list; - static const struct acpi_device_id dock_device_ids[] = { {"LNXDOCK", 0}, {"", 0}, @@ -89,6 +87,12 @@ struct dock_dependent_device { #define DOCK_EVENT 3 #define UNDOCK_EVENT 2 +enum dock_callback_type { + DOCK_CALL_HANDLER, + DOCK_CALL_FIXUP, + DOCK_CALL_UEVENT, +}; + /***************************************************************************** * Dock Dependent device functions * *****************************************************************************/ @@ -179,7 +183,7 @@ static void dock_release_hotplug(struct dock_dependent_device *dd) } static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, - bool uevent) + enum dock_callback_type cb_type) { acpi_notify_handler cb = NULL; bool run = false; @@ -189,8 +193,18 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, if (dd->hp_context) { run = true; dd->hp_refcount++; - if (dd->hp_ops) - cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler; + if (dd->hp_ops) { + switch (cb_type) { + case DOCK_CALL_FIXUP: + cb = dd->hp_ops->fixup; + break; + case DOCK_CALL_UEVENT: + cb = dd->hp_ops->uevent; + break; + default: + cb = dd->hp_ops->handler; + } + } } mutex_unlock(&hotplug_lock); @@ -372,9 +386,13 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; + /* Call driver specific post-dock fixups. */ + list_for_each_entry(dd, &ds->dependent_devices, list) + dock_hotplug_event(dd, event, DOCK_CALL_FIXUP); + /* Call driver specific hotplug functions. */ list_for_each_entry(dd, &ds->dependent_devices, list) - dock_hotplug_event(dd, event, false); + dock_hotplug_event(dd, event, DOCK_CALL_HANDLER); /* * Now make sure that an acpi_device is created for each dependent @@ -405,7 +423,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); list_for_each_entry(dd, &ds->dependent_devices, list) - dock_hotplug_event(dd, event, true); + dock_hotplug_event(dd, event, DOCK_CALL_UEVENT); if (num != DOCK_EVENT) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); @@ -487,37 +505,6 @@ static int dock_in_progress(struct dock_station *ds) return 0; } -/** - * register_dock_notifier - add yourself to the dock notifier list - * @nb: the callers notifier block - * - * If a driver wishes to be notified about dock events, they can - * use this function to put a notifier block on the dock notifier list. - * this notifier call chain will be called after a dock event, but - * before hotplugging any new devices. - */ -int register_dock_notifier(struct notifier_block *nb) -{ - if (!dock_station_count) - return -ENODEV; - - return atomic_notifier_chain_register(&dock_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(register_dock_notifier); - -/** - * unregister_dock_notifier - remove yourself from the dock notifier list - * @nb: the callers notifier block - */ -void unregister_dock_notifier(struct notifier_block *nb) -{ - if (!dock_station_count) - return; - - atomic_notifier_chain_unregister(&dock_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_dock_notifier); - /** * register_hotplug_dock_device - register a hotplug function * @handle: the handle of the device @@ -658,8 +645,6 @@ static void dock_notify(struct dock_station *ds, u32 event) complete_dock(ds); break; } - atomic_notifier_call_chain(&dock_notifier_list, - event, NULL); hotplug_dock_devices(ds, event); complete_dock(ds); dock_event(ds, event, DOCK_EVENT); @@ -945,7 +930,6 @@ void __init acpi_dock_init(void) return; } - ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 6fdd49c6f0b..6c781edabcc 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -122,7 +122,6 @@ struct acpiphp_func { struct acpiphp_slot *slot; /* parent */ struct list_head sibling; - struct notifier_block nb; acpi_handle handle; u8 function; /* pci function# */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a0a7133a1d1..8bfad0dc29a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -119,15 +119,14 @@ static void free_bridge(struct kref *kref) * TBD - figure out a way to only call fixups for * systems that require them. */ -static int post_dock_fixups(struct notifier_block *nb, unsigned long val, - void *v) +static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { - struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); + struct acpiphp_func *func = data; struct pci_bus *bus = func->slot->bridge->pci_bus; u32 buses; if (!bus->self) - return NOTIFY_OK; + return; /* fixup bad _DCK function that rewrites * secondary bridge on slot @@ -143,11 +142,11 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, | ((unsigned int)(bus->busn_res.end) << 16); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } - return NOTIFY_OK; } static const struct acpi_dock_ops acpiphp_dock_ops = { + .fixup = post_dock_fixups, .handler = hotplug_event_func, }; @@ -315,14 +314,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) &acpiphp_dock_ops, newfunc, acpiphp_dock_init, acpiphp_dock_release)) dbg("failed to register dock device\n"); - - /* we need to be notified when dock events happen - * outside of the hotplug operation, since we may - * need to do fixups before we can hotplug. - */ - newfunc->nb.notifier_call = post_dock_fixups; - if (register_dock_notifier(&newfunc->nb)) - dbg("failed to register a dock notifier"); } /* install notify handler */ @@ -472,7 +463,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_for_each_entry(func, &slot->funcs, sibling) { if (is_dock_device(func->handle)) { unregister_hotplug_dock_device(func->handle); - unregister_dock_notifier(&func->nb); } if (!(func->flags & FUNC_HAS_DCK)) { status = acpi_remove_notify_handler(func->handle, diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 0cf85786ed2..1cedfcb1bd8 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -113,14 +113,13 @@ void pci_acpi_crs_quirks(void); Dock Station -------------------------------------------------------------------------- */ struct acpi_dock_ops { + acpi_notify_handler fixup; acpi_notify_handler handler; acpi_notify_handler uevent; }; #ifdef CONFIG_ACPI_DOCK extern int is_dock_device(acpi_handle handle); -extern int register_dock_notifier(struct notifier_block *nb); -extern void unregister_dock_notifier(struct notifier_block *nb); extern int register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context, @@ -132,13 +131,6 @@ static inline int is_dock_device(acpi_handle handle) { return 0; } -static inline int register_dock_notifier(struct notifier_block *nb) -{ - return -ENODEV; -} -static inline void unregister_dock_notifier(struct notifier_block *nb) -{ -} static inline int register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context, -- cgit v1.2.3-70-g09d2 From 1696d9dc57e062ce5200f6a42a6aaada15b434bb Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 15 Jul 2013 10:15:09 +0200 Subject: ACPI: Remove the old /proc/acpi/event interface It is quite some time that this one has been deprecated. Get rid of it. Should some really important user be overseen, it may be reverted and the userspace program worked on first, but it is time to do something to get rid of this old stuff... Signed-off-by: Thomas Renninger Acked-by: Matthew Garrett Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki --- Documentation/laptops/asus-laptop.txt | 8 +-- Documentation/laptops/sony-laptop.txt | 8 +-- drivers/acpi/Kconfig | 18 ------ drivers/acpi/ac.c | 1 - drivers/acpi/acpi_pad.c | 1 - drivers/acpi/battery.c | 2 - drivers/acpi/bus.c | 98 ----------------------------- drivers/acpi/button.c | 2 - drivers/acpi/event.c | 106 -------------------------------- drivers/acpi/processor_driver.c | 4 -- drivers/acpi/sbs.c | 15 +---- drivers/acpi/thermal.c | 3 - drivers/acpi/video.c | 10 --- drivers/char/sonypi.c | 5 -- drivers/pci/hotplug/acpiphp_ibm.c | 1 - drivers/platform/x86/asus-laptop.c | 1 - drivers/platform/x86/eeepc-laptop.c | 1 - drivers/platform/x86/fujitsu-laptop.c | 4 -- drivers/platform/x86/panasonic-laptop.c | 3 - drivers/platform/x86/sony-laptop.c | 4 -- drivers/platform/x86/thinkpad_acpi.c | 11 ---- include/acpi/acpi_bus.h | 9 --- 22 files changed, 10 insertions(+), 305 deletions(-) (limited to 'drivers/pci') diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt index 69f9fb3701e..79a1bc675a8 100644 --- a/Documentation/laptops/asus-laptop.txt +++ b/Documentation/laptops/asus-laptop.txt @@ -8,8 +8,8 @@ http://acpi4asus.sf.net/ This driver provides support for extra features of ACPI-compatible ASUS laptops. It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or - VICTOR XP7210 for example). It makes all the extra buttons generate standard - ACPI events that go through /proc/acpi/events and input events (like keyboards). + VICTOR XP7210 for example). It makes all the extra buttons generate input + events (like keyboards). On some models adds support for changing the display brightness and output, switching the LCD backlight on and off, and most importantly, allows you to blink those fancy LEDs intended for reporting mail and wireless status. @@ -55,8 +55,8 @@ Usage DSDT) to me. That's all, now, all the events generated by the hotkeys of your laptop - should be reported in your /proc/acpi/event entry. You can check with - "acpi_listen". + should be reported via netlink events. You can check with + "acpi_genl monitor" (part of the acpica project). Hotkeys are also reported as input keys (like keyboards) you can check which key are supported using "xev" under X11. diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt index 0d5ac7f5287..978b1e61515 100644 --- a/Documentation/laptops/sony-laptop.txt +++ b/Documentation/laptops/sony-laptop.txt @@ -12,10 +12,10 @@ Fn keys (hotkeys): ------------------ Some models report hotkeys through the SNC or SPIC devices, such events are reported both through the ACPI subsystem as acpi events and through the INPUT -subsystem. See the logs of acpid or /proc/acpi/event and -/proc/bus/input/devices to find out what those events are and which input -devices are created by the driver. Additionally, loading the driver with the -debug option will report all events in the kernel log. +subsystem. See the logs of /proc/bus/input/devices to find out what those +events are and which input devices are created by the driver. +Additionally, loading the driver with the debug option will report all events +in the kernel log. The "scancodes" passed to the input system (that can be remapped with udev) are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 100bd724f64..3278a210c43 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -91,24 +91,6 @@ config ACPI_EC_DEBUGFS Thus this option is a debug option that helps to write ACPI drivers and can be used to identify ACPI code or EC firmware bugs. -config ACPI_PROC_EVENT - bool "Deprecated /proc/acpi/event support" - depends on PROC_FS - default y - help - A user-space daemon, acpid, typically reads /proc/acpi/event - and handles all ACPI-generated events. - - These events are now delivered to user-space either - via the input layer or as netlink events. - - This build option enables the old code for legacy - user-space implementation. After some time, this will - be moved under CONFIG_ACPI_PROCFS, and then deleted. - - Say Y here to retain the old behaviour. Say N if your - user-space is newer than kernel 2.6.23 (September 2007). - config ACPI_AC tristate "AC Adapter" depends on X86 diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 4f4e741d34b..f37beaa3275 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -267,7 +267,6 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event) msleep(ac_sleep_before_get_state_ms); acpi_ac_get_state(ac); - acpi_bus_generate_proc_event(device, event, (u32) ac->state); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, (u32) ac->state); diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 27bb6a91de5..6230637054c 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -452,7 +452,6 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, switch (event) { case ACPI_PROCESSOR_AGGREGATOR_NOTIFY: acpi_pad_handle_notify(handle); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd252a..33dfa851899 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1034,8 +1034,6 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) if (event == ACPI_BATTERY_NOTIFY_INFO) acpi_battery_refresh(battery); acpi_battery_update(battery); - acpi_bus_generate_proc_event(device, event, - acpi_battery_present(battery)); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, acpi_battery_present(battery)); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5bb33bab44..b6e9a3786e2 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -345,104 +345,6 @@ static void acpi_bus_osc_support(void) /* do we need to check other returned cap? Sounds no */ } -/* -------------------------------------------------------------------------- - Event Management - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_PROC_EVENT -static DEFINE_SPINLOCK(acpi_bus_event_lock); - -LIST_HEAD(acpi_bus_event_list); -DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); - -extern int event_is_open; - -int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data) -{ - struct acpi_bus_event *event; - unsigned long flags; - - /* drop event on the floor if no one's listening */ - if (!event_is_open) - return 0; - - event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC); - if (!event) - return -ENOMEM; - - strcpy(event->device_class, device_class); - strcpy(event->bus_id, bus_id); - event->type = type; - event->data = data; - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - list_add_tail(&event->node, &acpi_bus_event_list); - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - wake_up_interruptible(&acpi_bus_event_queue); - - return 0; - -} - -EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4); - -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) -{ - if (!device) - return -EINVAL; - return acpi_bus_generate_proc_event4(device->pnp.device_class, - device->pnp.bus_id, type, data); -} - -EXPORT_SYMBOL(acpi_bus_generate_proc_event); - -int acpi_bus_receive_event(struct acpi_bus_event *event) -{ - unsigned long flags; - struct acpi_bus_event *entry = NULL; - - DECLARE_WAITQUEUE(wait, current); - - - if (!event) - return -EINVAL; - - if (list_empty(&acpi_bus_event_list)) { - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&acpi_bus_event_queue, &wait); - - if (list_empty(&acpi_bus_event_list)) - schedule(); - - remove_wait_queue(&acpi_bus_event_queue, &wait); - set_current_state(TASK_RUNNING); - - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - if (!list_empty(&acpi_bus_event_list)) { - entry = list_entry(acpi_bus_event_list.next, - struct acpi_bus_event, node); - list_del(&entry->node); - } - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - if (!entry) - return -ENODEV; - - memcpy(event, entry, sizeof(struct acpi_bus_event)); - - kfree(entry); - - return 0; -} - -#endif /* CONFIG_ACPI_PROC_EVENT */ - /* -------------------------------------------------------------------------- Notification Handling -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index d2e617b5b3f..a55773801c5 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -303,8 +303,6 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) pm_wakeup_event(&device->dev, 0); } - - acpi_bus_generate_proc_event(device, event, ++button->pushed); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 1442737cede..8247fcdde07 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -21,100 +21,6 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event"); -#ifdef CONFIG_ACPI_PROC_EVENT -/* Global vars for handling event proc entry */ -static DEFINE_SPINLOCK(acpi_system_event_lock); -int event_is_open = 0; -extern struct list_head acpi_bus_event_list; -extern wait_queue_head_t acpi_bus_event_queue; - -static int acpi_system_open_event(struct inode *inode, struct file *file) -{ - spin_lock_irq(&acpi_system_event_lock); - - if (event_is_open) - goto out_busy; - - event_is_open = 1; - - spin_unlock_irq(&acpi_system_event_lock); - return 0; - - out_busy: - spin_unlock_irq(&acpi_system_event_lock); - return -EBUSY; -} - -static ssize_t -acpi_system_read_event(struct file *file, char __user * buffer, size_t count, - loff_t * ppos) -{ - int result = 0; - struct acpi_bus_event event; - static char str[ACPI_MAX_STRING]; - static int chars_remaining = 0; - static char *ptr; - - if (!chars_remaining) { - memset(&event, 0, sizeof(struct acpi_bus_event)); - - if ((file->f_flags & O_NONBLOCK) - && (list_empty(&acpi_bus_event_list))) - return -EAGAIN; - - result = acpi_bus_receive_event(&event); - if (result) - return result; - - chars_remaining = sprintf(str, "%s %s %08x %08x\n", - event.device_class ? event. - device_class : "", - event.bus_id ? event. - bus_id : "", event.type, - event.data); - ptr = str; - } - - if (chars_remaining < count) { - count = chars_remaining; - } - - if (copy_to_user(buffer, ptr, count)) - return -EFAULT; - - *ppos += count; - chars_remaining -= count; - ptr += count; - - return count; -} - -static int acpi_system_close_event(struct inode *inode, struct file *file) -{ - spin_lock_irq(&acpi_system_event_lock); - event_is_open = 0; - spin_unlock_irq(&acpi_system_event_lock); - return 0; -} - -static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) -{ - poll_wait(file, &acpi_bus_event_queue, wait); - if (!list_empty(&acpi_bus_event_list)) - return POLLIN | POLLRDNORM; - return 0; -} - -static const struct file_operations acpi_system_event_ops = { - .owner = THIS_MODULE, - .open = acpi_system_open_event, - .read = acpi_system_read_event, - .release = acpi_system_close_event, - .poll = acpi_system_poll_event, - .llseek = default_llseek, -}; -#endif /* CONFIG_ACPI_PROC_EVENT */ - /* ACPI notifier chain */ static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); @@ -280,9 +186,6 @@ static int acpi_event_genetlink_init(void) static int __init acpi_event_init(void) { -#ifdef CONFIG_ACPI_PROC_EVENT - struct proc_dir_entry *entry; -#endif int error = 0; if (acpi_disabled) @@ -293,15 +196,6 @@ static int __init acpi_event_init(void) if (error) printk(KERN_WARNING PREFIX "Failed to create genetlink family for ACPI event\n"); - -#ifdef CONFIG_ACPI_PROC_EVENT - /* 'event' [R] */ - entry = proc_create("event", S_IRUSR, acpi_root_dir, - &acpi_system_event_ops); - if (!entry) - return -ENODEV; -#endif - return 0; } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 823be116619..94b7b3b5559 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -91,21 +91,17 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) acpi_processor_ppc_has_changed(pr, 1); if (saved == pr->performance_platform_limit) break; - acpi_bus_generate_proc_event(device, event, - pr->performance_platform_limit); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, pr->performance_platform_limit); break; case ACPI_PROCESSOR_NOTIFY_POWER: acpi_processor_cst_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_PROCESSOR_NOTIFY_THROTTLING: acpi_processor_tstate_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index b6241eeb113..aef7e1cd1e5 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -873,14 +873,9 @@ static void acpi_sbs_callback(void *context) u8 saved_charger_state = sbs->charger_present; u8 saved_battery_state; acpi_ac_get_present(sbs); - if (sbs->charger_present != saved_charger_state) { -#ifdef CONFIG_ACPI_PROC_EVENT - acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, - ACPI_SBS_NOTIFY_STATUS, - sbs->charger_present); -#endif + if (sbs->charger_present != saved_charger_state) kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE); - } + if (sbs->manager_present) { for (id = 0; id < MAX_SBS_BAT; ++id) { if (!(sbs->batteries_supported & (1 << id))) @@ -890,12 +885,6 @@ static void acpi_sbs_callback(void *context) acpi_battery_read(bat); if (saved_battery_state == bat->present) continue; -#ifdef CONFIG_ACPI_PROC_EVENT - acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, - bat->name, - ACPI_SBS_NOTIFY_STATUS, - bat->present); -#endif kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE); } } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a33821ca389..547a906a766 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -769,7 +769,6 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip, else return 0; - acpi_bus_generate_proc_event(tz->device, type, 1); acpi_bus_generate_netlink_event(tz->device->pnp.device_class, dev_name(&tz->device->dev), type, 1); @@ -980,14 +979,12 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) case ACPI_THERMAL_NOTIFY_THRESHOLDS: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_THERMAL_NOTIFY_DEVICES: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5d7075d2570..8f91a378319 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1556,7 +1556,6 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, * most likely via hotkey. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; @@ -1564,20 +1563,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) * connector. */ acpi_video_device_enumerate(video); acpi_video_device_rebind(video); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_VIDEO_NEXT; break; case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_VIDEO_PREV; break; @@ -1620,31 +1615,26 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_CYCLE; break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSUP; break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSDOWN; break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_ZERO; break; case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_DISPLAY_OFF; break; default: diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index bf2349dbbf7..7cc1fe2241f 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -876,11 +876,6 @@ found: if (useinput) sonypi_report_input_event(event); -#ifdef CONFIG_ACPI - if (sonypi_acpi_device) - acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); -#endif - kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event, sizeof(event), &sonypi_device.fifo_lock); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index c35e8ad6db0..5394fffdf16 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -270,7 +270,6 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context) if (subevent == 0x80) { dbg("%s: generationg bus event\n", __func__); - acpi_bus_generate_proc_event(note->device, note->event, detail); acpi_bus_generate_netlink_event(note->device->pnp.device_class, dev_name(¬e->device->dev), note->event, detail); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8e268da6fdb..0e9c169b42f 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1543,7 +1543,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) /* TODO Find a better way to handle events count. */ count = asus->event_count[event % 128]++; - acpi_bus_generate_proc_event(asus->device, event, count); acpi_bus_generate_netlink_event(asus->device->pnp.device_class, dev_name(&asus->device->dev), event, count); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5d26e70bed6..a6afd4108be 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1269,7 +1269,6 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event) if (event > ACPI_MAX_SYS_NOTIFY) return; count = eeepc->event_count[event % 128]++; - acpi_bus_generate_proc_event(device, event, count); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, count); diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1c9386e7c58..52b8a97efde 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -773,8 +773,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) else set_lcd_level(newb); } - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); keycode = KEY_BRIGHTNESSUP; } else if (oldb > newb) { if (disable_brightness_adjust != 1) { @@ -783,8 +781,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) else set_lcd_level(newb); } - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); keycode = KEY_BRIGHTNESSDOWN; } break; diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 4add9a31bf6..984253da365 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -464,9 +464,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) "error getting hotkey status\n")); return; } - - acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); - if (!sparse_keymap_report_event(hotk_input_dev, result & 0xf, result & 0x80, false)) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 2ac045f27f1..069821b1fc2 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1275,9 +1275,6 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) ev_type = HOTKEY; sony_laptop_report_input_event(real_ev); } - - acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev); - acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); } @@ -4243,7 +4240,6 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) found: sony_laptop_report_input_event(device_event); - acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); sonypi_compat_report_event(device_event); return IRQ_HANDLED; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 54d31c0a984..e946c0d58a9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2282,10 +2282,6 @@ static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; static void tpacpi_hotkey_send_key(unsigned int scancode) { tpacpi_input_send_key_masked(scancode); - if (hotkey_report_mode < 2) { - acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, - 0x80, TP_HKEY_EV_HOTKEY_BASE + scancode); - } } static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) @@ -3737,13 +3733,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) "event happened to %s\n", TPACPI_MAIL); } - /* Legacy events */ - if (!ignore_acpi_ev && - (send_acpi_ev || hotkey_report_mode < 2)) { - acpi_bus_generate_proc_event(ibm->acpi->device, - event, hkey); - } - /* netlink events */ if (!ignore_acpi_ev && send_acpi_ev) { acpi_bus_generate_netlink_event( diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68c8d2..2650d1f19e4 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -383,15 +383,6 @@ bool acpi_bus_can_wakeup(acpi_handle handle); static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; } #endif -#ifdef CONFIG_ACPI_PROC_EVENT -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); -int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data); -int acpi_bus_receive_event(struct acpi_bus_event *event); -#else -static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) - { return 0; } -#endif - void acpi_scan_lock_acquire(void); void acpi_scan_lock_release(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); -- cgit v1.2.3-70-g09d2 From be1c9de98d8904c75a5ab8b2a0d97bea0f7c07cc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:23 +0200 Subject: ACPI / PCI: Make bus registration and unregistration symmetric Since acpi_pci_slot_enumerate() and acpiphp_enumerate_slots() can get the ACPI device handle they need from bus->bridge, it is not necessary to pass that handle to them as an argument. Drop the second argument of acpi_pci_slot_enumerate() and acpiphp_enumerate_slots(), rework them to obtain the ACPI handle from bus->bridge and make acpi_pci_add_bus() and acpi_pci_remove_bus() entirely symmetrical. Tested-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/pci_slot.c | 14 +++++++++----- drivers/pci/hotplug/acpiphp_glue.c | 6 ++++-- drivers/pci/pci-acpi.c | 16 ++++------------ include/linux/pci-acpi.h | 10 ++++------ 4 files changed, 21 insertions(+), 25 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 033d1179bdb..d678a180ca2 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -159,12 +159,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle) +void acpi_pci_slot_enumerate(struct pci_bus *bus) { - mutex_lock(&slot_list_lock); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - register_slot, NULL, bus, NULL); - mutex_unlock(&slot_list_lock); + acpi_handle handle = ACPI_HANDLE(bus->bridge); + + if (handle) { + mutex_lock(&slot_list_lock); + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + register_slot, NULL, bus, NULL); + mutex_unlock(&slot_list_lock); + } } void acpi_pci_slot_remove(struct pci_bus *bus) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8bfad0dc29a..a203ba529fe 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1147,14 +1147,16 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, * Create hotplug slots for the PCI bus. * It should always return 0 to avoid skipping following notifiers. */ -void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) +void acpiphp_enumerate_slots(struct pci_bus *bus) { + acpi_handle handle; struct acpiphp_bridge *bridge; if (acpiphp_disabled) return; - if (detect_ejectable_slots(handle) <= 0) + handle = ACPI_HANDLE(bus->bridge); + if (!handle || detect_ejectable_slots(handle) <= 0) return; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index dbdc5f7e2b2..c78cc432eda 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -290,24 +290,16 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = { void acpi_pci_add_bus(struct pci_bus *bus) { - acpi_handle handle = NULL; - - if (bus->bridge) - handle = ACPI_HANDLE(bus->bridge); - if (acpi_pci_disabled || handle == NULL) + if (acpi_pci_disabled || !bus->bridge) return; - acpi_pci_slot_enumerate(bus, handle); - acpiphp_enumerate_slots(bus, handle); + acpi_pci_slot_enumerate(bus); + acpiphp_enumerate_slots(bus); } void acpi_pci_remove_bus(struct pci_bus *bus) { - /* - * bus->bridge->acpi_node.handle has already been reset to NULL - * when acpi_pci_remove_bus() is called, so don't check ACPI handle. - */ - if (acpi_pci_disabled) + if (acpi_pci_disabled || !bus->bridge) return; acpiphp_remove_slots(bus); diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 17044797727..d006f0ca60f 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -47,24 +47,22 @@ void acpi_pci_remove_bus(struct pci_bus *bus); #ifdef CONFIG_ACPI_PCI_SLOT void acpi_pci_slot_init(void); -void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle); +void acpi_pci_slot_enumerate(struct pci_bus *bus); void acpi_pci_slot_remove(struct pci_bus *bus); #else static inline void acpi_pci_slot_init(void) { } -static inline void acpi_pci_slot_enumerate(struct pci_bus *bus, - acpi_handle handle) { } +static inline void acpi_pci_slot_enumerate(struct pci_bus *bus) { } static inline void acpi_pci_slot_remove(struct pci_bus *bus) { } #endif #ifdef CONFIG_HOTPLUG_PCI_ACPI void acpiphp_init(void); -void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle); +void acpiphp_enumerate_slots(struct pci_bus *bus); void acpiphp_remove_slots(struct pci_bus *bus); void acpiphp_check_host_bridge(acpi_handle handle); #else static inline void acpiphp_init(void) { } -static inline void acpiphp_enumerate_slots(struct pci_bus *bus, - acpi_handle handle) { } +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) { } #endif -- cgit v1.2.3-70-g09d2 From 2552002a46cd6a7a262ea1718db33d1a1517008e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:23 +0200 Subject: ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() The acpiphp_enumerate_slots() function is now split into two parts, acpiphp_enumerate_slots() proper and init_bridge_misc() which is only called by the former. If these functions are combined, it is possible to make the code easier to follow and to clean up the error handling (to prevent memory leaks on error from happening in particular), so do that. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 92 +++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 47 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a203ba529fe..68c3809ed7c 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -353,46 +353,6 @@ static int detect_ejectable_slots(acpi_handle handle) return found; } -/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ -static void init_bridge_misc(struct acpiphp_bridge *bridge) -{ - acpi_status status; - - /* must be added to the list prior to calling register_slot */ - mutex_lock(&bridge_mutex); - list_add(&bridge->list, &bridge_list); - mutex_unlock(&bridge_mutex); - - /* register all slot objects under this bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, - register_slot, NULL, bridge, NULL); - if (ACPI_FAILURE(status)) { - mutex_lock(&bridge_mutex); - list_del(&bridge->list); - mutex_unlock(&bridge_mutex); - return; - } - - /* install notify handler for P2P bridges */ - if (!pci_is_root_bus(bridge->pci_bus)) { - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { - status = acpi_remove_notify_handler(bridge->func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - } - status = acpi_install_notify_handler(bridge->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - } - } -} - /* find acpiphp_func from acpiphp_bridge */ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) @@ -1149,8 +1109,9 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus) { - acpi_handle handle; struct acpiphp_bridge *bridge; + acpi_handle handle; + acpi_status status; if (acpiphp_disabled) return; @@ -1178,14 +1139,51 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ get_device(&bus->dev); - if (!pci_is_root_bus(bridge->pci_bus) && - acpi_has_method(bridge->handle, "_EJ0")) { - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - bridge->func = acpiphp_bridge_handle_to_function(handle); + /* must be added to the list prior to calling register_slot */ + mutex_lock(&bridge_mutex); + list_add(&bridge->list, &bridge_list); + mutex_unlock(&bridge_mutex); + + /* register all slot objects under this bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1, + register_slot, NULL, bridge, NULL); + if (ACPI_FAILURE(status)) { + acpi_handle_err(bridge->handle, "failed to register slots\n"); + goto err; + } + + if (pci_is_root_bus(bridge->pci_bus)) + return; + + /* install notify handler for P2P bridges */ + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, + bridge); + if (ACPI_FAILURE(status)) { + acpi_handle_err(bridge->handle, + "failed to register notify handler\n"); + goto err; + } + + if (!acpi_has_method(bridge->handle, "_EJ0")) + return; + + dbg("found ejectable p2p bridge\n"); + bridge->flags |= BRIDGE_HAS_EJ0; + bridge->func = acpiphp_bridge_handle_to_function(bridge->handle); + if (bridge->func) { + status = acpi_remove_notify_handler(bridge->func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + acpi_handle_err(bridge->func->handle, + "failed to remove notify handler\n"); } + return; - init_bridge_misc(bridge); + err: + cleanup_bridge(bridge); + put_bridge(bridge); } /* Destroy hotplug slots associated with the PCI bus */ -- cgit v1.2.3-70-g09d2 From 2e862c51904ddd12be2d256513160e1f87beafee Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:23 +0200 Subject: ACPI / hotplug / PCI: Always return success after adding a function When a new ACPIPHP function is added by register_slot() and the notify handler cannot be installed for it, register_slot() returns an error status without cleaning up, which causes the entire namespace walk in acpiphp_enumerate_slots() to be aborted, although it still may be possible to successfully install the function notify handler for other device objects under the given brigde. To address this issue make register_slot() return success after a new function has been added, even if the addition of the notify handler for it has failed. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 68c3809ed7c..d75ba7e0ca8 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -325,10 +325,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (ACPI_FAILURE(status)) err("failed to register interrupt notify handler\n"); - } else - status = AE_OK; + } - return status; + return AE_OK; err_exit: bridge->nr_slots--; -- cgit v1.2.3-70-g09d2 From cb7b8cedf6c88b9d1d08e0565e8da52180921071 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Hotplug context objects for bridges and functions When either a new hotplug bridge or a new hotplug function is added by the ACPI-based PCI hotplug (ACPIPHP) code, attach a context object to its ACPI handle to store hotplug-related information in it. To start with, put the handle's bridge and function pointers into that object. Count references to the context objects and drop them when they are not needed any more. First of all, this makes it possible to find out if the given bridge has been registered as a function already in a much more straightforward way and acpiphp_bridge_handle_to_function() can be dropped (Yay!). This also will allow some more simplifications to be made going forward. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 10 +++ drivers/pci/hotplug/acpiphp_glue.c | 179 ++++++++++++++++++++++++++++--------- 2 files changed, 146 insertions(+), 43 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 6c781edabcc..f946e47eca7 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -49,6 +49,7 @@ #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) +struct acpiphp_context; struct acpiphp_bridge; struct acpiphp_slot; @@ -77,6 +78,7 @@ struct acpiphp_bridge { struct kref ref; acpi_handle handle; + struct acpiphp_context *context; /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ struct acpiphp_func *func; @@ -119,6 +121,7 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { + struct acpiphp_context *context; struct acpiphp_slot *slot; /* parent */ struct list_head sibling; @@ -128,6 +131,13 @@ struct acpiphp_func { u32 flags; /* see below */ }; +struct acpiphp_context { + acpi_handle handle; + struct acpiphp_func *func; + struct acpiphp_bridge *bridge; + unsigned int refcount; +}; + /* * struct acpiphp_attention_info - device specific attention registration * diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d75ba7e0ca8..a0c518c2185 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -55,6 +55,7 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); +static DEFINE_MUTEX(acpiphp_context_lock); #define MY_NAME "acpiphp_glue" @@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) } } +static void acpiphp_context_handler(acpi_handle handle, void *context) +{ + /* Intentionally empty. */ +} + +/** + * acpiphp_init_context - Create hotplug context and grab a reference to it. + * @handle: ACPI object handle to create the context for. + * + * Call under acpiphp_context_lock. + */ +static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +{ + struct acpiphp_context *context; + acpi_status status; + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return NULL; + + context->handle = handle; + context->refcount = 1; + status = acpi_attach_data(handle, acpiphp_context_handler, context); + if (ACPI_FAILURE(status)) { + kfree(context); + return NULL; + } + return context; +} + +/** + * 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. + */ +static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +{ + struct acpiphp_context *context = NULL; + acpi_status status; + void *data; + + status = acpi_get_data(handle, acpiphp_context_handler, &data); + if (ACPI_SUCCESS(status)) { + context = data; + context->refcount++; + } + return context; +} + +/** + * acpiphp_put_context - Drop a reference to ACPI hotplug context. + * @handle: ACPI object handle to put the context for. + * + * The context object is removed if there are no more references to it. + * + * Call under acpiphp_context_lock. + */ +static void acpiphp_put_context(struct acpiphp_context *context) +{ + if (--context->refcount) + return; + + WARN_ON(context->func || context->bridge); + acpi_detach_data(context->handle, acpiphp_context_handler); + kfree(context); +} + static inline void get_bridge(struct acpiphp_bridge *bridge) { kref_get(&bridge->ref); @@ -91,25 +160,37 @@ static inline void put_bridge(struct acpiphp_bridge *bridge) static void free_bridge(struct kref *kref) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; + mutex_lock(&acpiphp_context_lock); + bridge = container_of(kref, struct acpiphp_bridge, ref); list_for_each_entry_safe(slot, next, &bridge->slots, node) { list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { + context = func->context; + context->func = NULL; + acpiphp_put_context(context); kfree(func); } kfree(slot); } - /* Release reference acquired by acpiphp_bridge_handle_to_function() */ + /* Release the reference acquired by acpiphp_enumerate_slots(). */ if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) put_bridge(bridge->func->slot->bridge); + put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); + context = bridge->context; + context->bridge = NULL; + acpiphp_put_context(context); kfree(bridge); + + mutex_unlock(&acpiphp_context_lock); } /* @@ -194,10 +275,11 @@ static void acpiphp_dock_release(void *data) } /* callback routine to register each ACPI PCI slot object */ -static acpi_status -register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) +static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, + void **rv) { - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; + struct acpiphp_bridge *bridge = data; + struct acpiphp_context *context; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -230,6 +312,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) newfunc->handle = handle; newfunc->function = function; + mutex_lock(&acpiphp_context_lock); + context = acpiphp_init_context(handle); + if (!context) { + mutex_unlock(&acpiphp_context_lock); + acpi_handle_err(handle, "No hotplug context\n"); + kfree(newfunc); + return AE_NOT_EXIST; + } + newfunc->context = context; + context->func = newfunc; + mutex_unlock(&acpiphp_context_lock); + if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -266,8 +360,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (!found) { slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - kfree(newfunc); - return AE_NO_MEMORY; + status = AE_NO_MEMORY; + goto err_out; } slot->bridge = bridge; @@ -291,7 +385,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) else warn("acpiphp_register_hotplug_slot failed " "(err code = 0x%x)\n", retval); - goto err_exit; + + status = AE_OK; + goto err; } } @@ -329,15 +425,20 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; - err_exit: + err: bridge->nr_slots--; mutex_lock(&bridge_mutex); list_del(&slot->node); mutex_unlock(&bridge_mutex); kfree(slot); - kfree(newfunc); - return AE_OK; + err_out: + mutex_lock(&acpiphp_context_lock); + context->func = NULL; + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + kfree(newfunc); + return status; } @@ -352,32 +453,6 @@ static int detect_ejectable_slots(acpi_handle handle) return found; } - -/* find acpiphp_func from acpiphp_bridge */ -static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) -{ - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - struct acpiphp_func *func = NULL; - - mutex_lock(&bridge_mutex); - list_for_each_entry(bridge, &bridge_list, list) { - list_for_each_entry(slot, &bridge->slots, node) { - list_for_each_entry(func, &slot->funcs, sibling) { - if (func->handle == handle) { - get_bridge(func->slot->bridge); - mutex_unlock(&bridge_mutex); - return func; - } - } - } - } - mutex_unlock(&bridge_mutex); - - return NULL; -} - - static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { struct acpiphp_bridge *bridge; @@ -1108,6 +1183,7 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; acpi_handle handle; acpi_status status; @@ -1120,8 +1196,8 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) return; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) { - err("out of memory\n"); + if (!bridge) { + acpi_handle_err(handle, "No memory for bridge object\n"); return; } @@ -1131,6 +1207,21 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->pci_dev = pci_dev_get(bus->self); bridge->pci_bus = bus; + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (!context) { + context = acpiphp_init_context(handle); + if (!context) { + mutex_unlock(&acpiphp_context_lock); + acpi_handle_err(handle, "No hotplug context\n"); + kfree(bridge); + return; + } + } + bridge->context = context; + context->bridge = bridge; + mutex_unlock(&acpiphp_context_lock); + /* * Grab a ref to the subordinate PCI bus in case the bus is * removed via PCI core logical hotplug. The ref pins the bus @@ -1169,13 +1260,15 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) dbg("found ejectable p2p bridge\n"); bridge->flags |= BRIDGE_HAS_EJ0; - bridge->func = acpiphp_bridge_handle_to_function(bridge->handle); - if (bridge->func) { - status = acpi_remove_notify_handler(bridge->func->handle, - ACPI_SYSTEM_NOTIFY, + if (context->func) { + get_bridge(context->func->slot->bridge); + bridge->func = context->func; + handle = context->handle; + WARN_ON(bridge->handle != handle); + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_func); if (ACPI_FAILURE(status)) - acpi_handle_err(bridge->func->handle, + acpi_handle_err(handle, "failed to remove notify handler\n"); } return; -- cgit v1.2.3-70-g09d2 From 87831273438d66167dddc6d73e42d49671cb56bb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Unified notify handler for hotplug events Using the hotplug context objects introduced previously rework the ACPI-based PCI hotplug (ACPIPHP) core code so that all notifications for ACPI device objects corresponding to the hotplug PCI devices are handled by one function, handle_hotplug_event(), which recognizes whether it has to handle a bridge or a function. In addition to code size reduction it allows some ugly pieces of code where notify handlers have to be uninstalled and installed again to go away. Moreover, it fixes a theoretically possible race between handle_hotplug_event() and free_bridge() tearing down data structures for the same handle. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 1 + drivers/pci/hotplug/acpiphp_glue.c | 132 +++++++++++++++---------------------- 2 files changed, 53 insertions(+), 80 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index f946e47eca7..b96a8a9c39c 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -136,6 +136,7 @@ struct acpiphp_context { struct acpiphp_func *func; struct acpiphp_bridge *bridge; unsigned int refcount; + bool handler_for_func; }; /* diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a0c518c2185..ef7b25c1db5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -59,11 +59,10 @@ static DEFINE_MUTEX(acpiphp_context_lock); #define MY_NAME "acpiphp_glue" -static void handle_hotplug_event_bridge (acpi_handle, u32, void *); +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_func(acpi_handle handle, u32 type, void *context); -static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); static void free_bridge(struct kref *kref); /* callback routine to check for the existence of a pci dock device */ @@ -179,13 +178,13 @@ static void free_bridge(struct kref *kref) kfree(slot); } + context = bridge->context; /* Release the reference acquired by acpiphp_enumerate_slots(). */ - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) + if (context->handler_for_func) put_bridge(bridge->func->slot->bridge); put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); - context = bridge->context; context->bridge = NULL; acpiphp_put_context(context); kfree(bridge); @@ -414,12 +413,12 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - newfunc); - - if (ACPI_FAILURE(status)) + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event, + context); + if (ACPI_SUCCESS(status)) + context->handler_for_func = true; + else err("failed to register interrupt notify handler\n"); } @@ -476,32 +475,23 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) acpi_status status; acpi_handle handle = bridge->handle; - if (!pci_is_root_bus(bridge->pci_bus)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); + if (!bridge->context->handler_for_func) { + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { - status = acpi_install_notify_handler(bridge->func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - bridge->func); - if (ACPI_FAILURE(status)) - err("failed to install interrupt notify handler\n"); - } - list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { if (is_dock_device(func->handle)) { unregister_hotplug_dock_device(func->handle); } if (!(func->flags & FUNC_HAS_DCK)) { + func->context->handler_for_func = false; status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } @@ -1071,31 +1061,6 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) put_bridge(bridge); } -/** - * handle_hotplug_event_bridge - handle ACPI event on bridges - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_bridge structure - * - * Handles ACPI event notification on {host,p2p} bridges. - */ -static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, - void *context) -{ - struct acpiphp_bridge *bridge = context; - - /* - * Currently the code adds all hotplug events to the kacpid_wq - * queue when it should add hotplug events to the kacpi_hotplug_wq. - * The proper way to fix this is to reorganize the code so that - * drivers (dock, etc.) do not call acpi_os_execute(), etc. - * For now just re-add this work to the kacpi_hotplug_wq so we - * don't deadlock on hotplug actions. - */ - get_bridge(bridge); - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge); -} - static void hotplug_event_func(acpi_handle handle, u32 type, void *context) { struct acpiphp_func *func = context; @@ -1153,17 +1118,33 @@ static void _handle_hotplug_event_func(struct work_struct *work) } /** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * handle_hotplug_event - handle ACPI hotplug event * @handle: Notify()'ed acpi_handle * @type: Notify code - * @context: pointer to acpiphp_func structure + * @data: pointer to acpiphp_context structure * * Handles ACPI event notification on slots. */ -static void handle_hotplug_event_func(acpi_handle handle, u32 type, - void *context) +static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_func *func = context; + struct acpiphp_context *context; + void (*work_func)(struct work_struct *work) = NULL; + + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (context) { + if (context->bridge) { + get_bridge(context->bridge); + data = context->bridge; + work_func = _handle_hotplug_event_bridge; + } else if (context->func) { + get_bridge(context->func->slot->bridge); + data = context->func; + work_func = _handle_hotplug_event_func; + } + acpiphp_put_context(context); + } + mutex_unlock(&acpiphp_context_lock); /* * Currently the code adds all hotplug events to the kacpid_wq @@ -1173,8 +1154,8 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, * For now just re-add this work to the kacpi_hotplug_wq so we * don't deadlock on hotplug actions. */ - get_bridge(func->slot->bridge); - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); + if (work_func) + alloc_acpi_hp_work(handle, type, data, work_func); } /* @@ -1245,33 +1226,24 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) if (pci_is_root_bus(bridge->pci_bus)) return; - /* install notify handler for P2P bridges */ - status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - if (ACPI_FAILURE(status)) { - acpi_handle_err(bridge->handle, - "failed to register notify handler\n"); - goto err; + if (acpi_has_method(bridge->handle, "_EJ0")) { + dbg("found ejectable p2p bridge\n"); + bridge->flags |= BRIDGE_HAS_EJ0; + } + if (context->handler_for_func) { + /* Notify handler already installed. */ + bridge->func = context->func; + get_bridge(context->func->slot->bridge); + return; } - if (!acpi_has_method(bridge->handle, "_EJ0")) + /* install notify handler for P2P bridges */ + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event, NULL); + if (ACPI_SUCCESS(status)) return; - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - if (context->func) { - get_bridge(context->func->slot->bridge); - bridge->func = context->func; - handle = context->handle; - WARN_ON(bridge->handle != handle); - status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to remove notify handler\n"); - } - return; + acpi_handle_err(bridge->handle, "failed to register notify handler\n"); err: cleanup_bridge(bridge); -- cgit v1.2.3-70-g09d2 From ed13febf8fac1a08f939f97378574937a7d2f121 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Using the hotplug context objects introduced previously rework the ACPI-based PCI hotplug (ACPIPHP) core code to get to acpiphp_bridge objects associated with hotplug bridges from those context objects rather than from the global list of hotplug bridges. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ef7b25c1db5..6cfd8a68476 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -454,18 +454,20 @@ static int detect_ejectable_slots(acpi_handle handle) static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { - struct acpiphp_bridge *bridge; + struct acpiphp_context *context; + struct acpiphp_bridge *bridge = NULL; - mutex_lock(&bridge_mutex); - list_for_each_entry(bridge, &bridge_list, list) - if (bridge->handle == handle) { + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (context) { + bridge = context->bridge; + if (bridge) get_bridge(bridge); - mutex_unlock(&bridge_mutex); - return bridge; - } - mutex_unlock(&bridge_mutex); - return NULL; + acpiphp_put_context(context); + } + mutex_unlock(&acpiphp_context_lock); + return bridge; } static void cleanup_bridge(struct acpiphp_bridge *bridge) -- cgit v1.2.3-70-g09d2 From c8ebcf1ff91a8f64b09c4df0ee21ae80a953c39c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Modify handle_hotplug_event() to pass the entire context object (instead of its fields individually) to work functions started by it. This change makes the subsequent consolidation of the event handling work functions a bit more straightforward. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 6cfd8a68476..b5a98f4baa3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -989,6 +989,7 @@ void acpiphp_check_host_bridge(acpi_handle handle) static void _handle_hotplug_event_bridge(struct work_struct *work) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -1000,7 +1001,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) hp_work = container_of(work, struct acpi_hp_work, work); handle = hp_work->handle; type = hp_work->type; - bridge = (struct acpiphp_bridge *)hp_work->context; + context = hp_work->context; + bridge = context->bridge; acpi_scan_lock_acquire(); @@ -1105,18 +1107,18 @@ static void hotplug_event_func(acpi_handle handle, u32 type, void *context) static void _handle_hotplug_event_func(struct work_struct *work) { + struct acpiphp_context *context; struct acpi_hp_work *hp_work; - struct acpiphp_func *func; hp_work = container_of(work, struct acpi_hp_work, work); - func = hp_work->context; + context = hp_work->context; acpi_scan_lock_acquire(); - hotplug_event_func(hp_work->handle, hp_work->type, func); + hotplug_event_func(hp_work->handle, hp_work->type, context->func); acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_func */ - put_bridge(func->slot->bridge); + put_bridge(context->func->slot->bridge); } /** @@ -1137,11 +1139,9 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) if (context) { if (context->bridge) { get_bridge(context->bridge); - data = context->bridge; work_func = _handle_hotplug_event_bridge; } else if (context->func) { get_bridge(context->func->slot->bridge); - data = context->func; work_func = _handle_hotplug_event_func; } acpiphp_put_context(context); @@ -1157,7 +1157,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) * don't deadlock on hotplug actions. */ if (work_func) - alloc_acpi_hp_work(handle, type, data, work_func); + alloc_acpi_hp_work(handle, type, context, work_func); } /* -- cgit v1.2.3-70-g09d2 From 43e5c091c797616170b11f4a1b32ea8c81ad0100 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Merge hotplug event handling functions There are separate handling event functions for hotplug bridges and for hotplug functions, but they may be combined into one common hotplug event handling function which simplifies the code slightly. That also allows a theoretical bug to be dealt with which in principle may occur if a hotplug bridge is on a dock station, because in that case the bridge-specific notification should be used instead of the function-specific one, but the dock station always uses the latter. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 152 ++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 87 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b5a98f4baa3..e2f9ea03aec 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -62,7 +62,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_func(acpi_handle handle, u32 type, void *context); +static void hotplug_event(acpi_handle handle, u32 type, void *data); static void free_bridge(struct kref *kref); /* callback routine to check for the existence of a pci dock device */ @@ -201,8 +201,8 @@ static void free_bridge(struct kref *kref) */ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { - struct acpiphp_func *func = data; - struct pci_bus *bus = func->slot->bridge->pci_bus; + struct acpiphp_context *context = data; + struct pci_bus *bus = context->func->slot->bridge->pci_bus; u32 buses; if (!bus->self) @@ -227,7 +227,7 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) static const struct acpi_dock_ops acpiphp_dock_ops = { .fixup = post_dock_fixups, - .handler = hotplug_event_func, + .handler = hotplug_event, }; /* Check whether the PCI device is managed by native PCIe hotplug driver */ @@ -261,16 +261,16 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) static void acpiphp_dock_init(void *data) { - struct acpiphp_func *func = data; + struct acpiphp_context *context = data; - get_bridge(func->slot->bridge); + get_bridge(context->func->slot->bridge); } static void acpiphp_dock_release(void *data) { - struct acpiphp_func *func = data; + struct acpiphp_context *context = data; - put_bridge(func->slot->bridge); + put_bridge(context->func->slot->bridge); } /* callback routine to register each ACPI PCI slot object */ @@ -406,7 +406,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, */ newfunc->flags &= ~FUNC_HAS_EJ0; if (register_hotplug_dock_device(handle, - &acpiphp_dock_ops, newfunc, + &acpiphp_dock_ops, context, acpiphp_dock_init, acpiphp_dock_release)) dbg("failed to register dock device\n"); } @@ -987,24 +987,26 @@ void acpiphp_check_host_bridge(acpi_handle handle) ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); } -static void _handle_hotplug_event_bridge(struct work_struct *work) +static void hotplug_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpiphp_context *context = data; struct acpiphp_bridge *bridge; + struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; - struct acpi_hp_work *hp_work; - acpi_handle handle; - u32 type; - hp_work = container_of(work, struct acpi_hp_work, work); - handle = hp_work->handle; - type = hp_work->type; - context = hp_work->context; + mutex_lock(&acpiphp_context_lock); bridge = context->bridge; + if (bridge) + get_bridge(bridge); - acpi_scan_lock_acquire(); + /* + * If context->func is not NULL, we are holding a reference to its + * parent bridge, so it won't go away until we drop that reference. + */ + func = context->func; + mutex_unlock(&acpiphp_context_lock); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1013,15 +1015,24 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __func__, objname); dbg("%s: re-enumerating slots under %s\n", __func__, objname); - acpiphp_check_bridge(bridge); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); + if (bridge) { + acpiphp_check_bridge(bridge); + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, check_sub_bridges, + NULL, NULL, NULL); + } else { + acpiphp_enable_slot(func->slot); + } break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ dbg("%s: Device check notify on %s\n", __func__, objname); - acpiphp_check_bridge(bridge); + if (bridge) + acpiphp_check_bridge(bridge); + else + acpiphp_check_bridge(func->slot->bridge); + break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -1032,12 +1043,15 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { - struct acpiphp_slot *slot; - slot = bridge->func->slot; - if (!acpiphp_disable_slot(slot)) - acpiphp_eject_slot(slot); - } + if (!func) + break; + + if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0)) + break; + + if (!(acpiphp_disable_slot(func->slot))) + acpiphp_eject_slot(func->slot); + break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: @@ -1056,56 +1070,16 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) break; default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); + warn("notify_handler: unknown event type 0x%x for %s\n", type, + objname); break; } - acpi_scan_lock_release(); - kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ - put_bridge(bridge); -} - -static void hotplug_event_func(acpi_handle handle, u32 type, void *context) -{ - struct acpiphp_func *func = context; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __func__, objname); - acpiphp_enable_slot(func->slot); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check : re-enumerate from parent bus */ - dbg("%s: Device check notify on %s\n", __func__, objname); - acpiphp_check_bridge(func->slot->bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __func__, objname); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __func__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } + if (bridge) + put_bridge(bridge); } -static void _handle_hotplug_event_func(struct work_struct *work) +static void hotplug_event_work(struct work_struct *work) { struct acpiphp_context *context; struct acpi_hp_work *hp_work; @@ -1114,11 +1088,18 @@ static void _handle_hotplug_event_func(struct work_struct *work) context = hp_work->context; acpi_scan_lock_acquire(); - hotplug_event_func(hp_work->handle, hp_work->type, context->func); + hotplug_event(hp_work->handle, hp_work->type, context); acpi_scan_lock_release(); - kfree(hp_work); /* allocated in handle_hotplug_event_func */ - put_bridge(context->func->slot->bridge); + kfree(hp_work); /* allocated in handle_hotplug_event() */ + + mutex_lock(&acpiphp_context_lock); + if (context->func) + put_bridge(context->func->slot->bridge); + else + acpiphp_put_context(context); + + mutex_unlock(&acpiphp_context_lock); } /** @@ -1132,22 +1113,19 @@ static void _handle_hotplug_event_func(struct work_struct *work) static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context; - void (*work_func)(struct work_struct *work) = NULL; mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - if (context->bridge) { - get_bridge(context->bridge); - work_func = _handle_hotplug_event_bridge; - } else if (context->func) { + if (context->func) { get_bridge(context->func->slot->bridge); - work_func = _handle_hotplug_event_func; + acpiphp_put_context(context); + } else if (!context->bridge) { + acpiphp_put_context(context); + context = NULL; } - acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); - /* * Currently the code adds all hotplug events to the kacpid_wq * queue when it should add hotplug events to the kacpi_hotplug_wq. @@ -1156,8 +1134,8 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) * For now just re-add this work to the kacpi_hotplug_wq so we * don't deadlock on hotplug actions. */ - if (work_func) - alloc_acpi_hp_work(handle, type, context, work_func); + if (context) + alloc_acpi_hp_work(handle, type, context, hotplug_event_work); } /* -- cgit v1.2.3-70-g09d2 From f28181109e85b49b5b4b1c381d889b4ea7315988 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Since the func pointer in struct acpiphp_context can always be used instead of the func pointer in struct acpiphp_bridge, drop the latter. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 2 -- drivers/pci/hotplug/acpiphp_glue.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b96a8a9c39c..4980ff4919a 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -79,8 +79,6 @@ struct acpiphp_bridge { acpi_handle handle; struct acpiphp_context *context; - /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ - struct acpiphp_func *func; int nr_slots; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e2f9ea03aec..a83ce9db16b 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -181,7 +181,7 @@ static void free_bridge(struct kref *kref) context = bridge->context; /* Release the reference acquired by acpiphp_enumerate_slots(). */ if (context->handler_for_func) - put_bridge(bridge->func->slot->bridge); + put_bridge(context->func->slot->bridge); put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); @@ -1212,7 +1212,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) } if (context->handler_for_func) { /* Notify handler already installed. */ - bridge->func = context->func; get_bridge(context->func->slot->bridge); return; } -- cgit v1.2.3-70-g09d2 From ac372338b750648355bcc64bb0bca13fc6f0a3d5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() To make the code in register_slot() a bit easier to follow, change the way the slot allocation part is organized. Drop one local variable that's not used any more after that modification. This code change should not lead to any changes in behavior. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 74 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 38 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a83ce9db16b..95af39c9a39 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -283,7 +283,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, struct acpiphp_func *newfunc; acpi_status status = AE_OK; unsigned long long adr, sun; - int device, function, retval, found = 0; + int device, function, retval; struct pci_bus *pbus = bridge->pci_bus; struct pci_dev *pdev; u32 val; @@ -352,44 +352,49 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (slot->device == device) { if (slot->sun != sun) warn("sibling found, but _SUN doesn't match!\n"); - found = 1; - break; - } - if (!found) { - slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); - if (!slot) { - status = AE_NO_MEMORY; - goto err_out; + goto slot_found; } - slot->bridge = bridge; - slot->device = device; - slot->sun = sun; - INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); + slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); + if (!slot) { + status = AE_NO_MEMORY; + goto err; + } + + slot->bridge = bridge; + slot->device = device; + slot->sun = sun; + INIT_LIST_HEAD(&slot->funcs); + mutex_init(&slot->crit_sect); + mutex_lock(&bridge_mutex); + list_add_tail(&slot->node, &bridge->slots); + mutex_unlock(&bridge_mutex); + bridge->nr_slots++; + + dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", + slot->sun, pci_domain_nr(pbus), pbus->number, device); + + retval = acpiphp_register_hotplug_slot(slot); + if (retval) { + if (retval == -EBUSY) + warn("Slot %llu already registered by another " + "hotplug driver\n", slot->sun); + else + warn("acpiphp_register_hotplug_slot failed " + "(err code = 0x%x)\n", retval); + + bridge->nr_slots--; mutex_lock(&bridge_mutex); - list_add_tail(&slot->node, &bridge->slots); + list_del(&slot->node); mutex_unlock(&bridge_mutex); - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(pbus), pbus->number, device); - retval = acpiphp_register_hotplug_slot(slot); - if (retval) { - if (retval == -EBUSY) - warn("Slot %llu already registered by another " - "hotplug driver\n", slot->sun); - else - warn("acpiphp_register_hotplug_slot failed " - "(err code = 0x%x)\n", retval); - - status = AE_OK; - goto err; - } + kfree(slot); + status = AE_OK; + goto err; } + slot_found: newfunc->slot = slot; mutex_lock(&bridge_mutex); list_add_tail(&newfunc->sibling, &slot->funcs); @@ -425,13 +430,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, return AE_OK; err: - bridge->nr_slots--; - mutex_lock(&bridge_mutex); - list_del(&slot->node); - mutex_unlock(&bridge_mutex); - kfree(slot); - - err_out: mutex_lock(&acpiphp_context_lock); context->func = NULL; acpiphp_put_context(context); -- cgit v1.2.3-70-g09d2 From bbd34fcdd1b201e996235731a7c98fd5197d9e51 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Register all devices under the given bridge Rework register_slot() to create a struct acpiphp_func object for every function it is called for and to create acpiphp slots for all of them. Although acpiphp_register_hotplug_slot() is only called for the slots whose functions are identified as "ejectable", so that user space can manipulate them, the ACPIPHP notify handler, handle_hotplug_event(), is now installed for all of the registered functions (that aren't dock stations) and hotplug events may be handled for all of them. As a result, essentially, all PCI bridges represented by objects in the ACPI namespace are now going to be "hotplug" bridges and that may affect resources allocation in general, although it shouldn't lead to problems. This allows the code to be simplified substantially and addresses the problem where bus check or device check notifications for some PCI bridges or devices are not handled, because those devices are not recognized as "ejectable" or there appear to be no "ejectable" devices under those bridges. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 232 ++++++++++++------------------------- 2 files changed, 76 insertions(+), 157 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 4980ff4919a..76a1c979a25 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -134,7 +134,6 @@ struct acpiphp_context { struct acpiphp_func *func; struct acpiphp_bridge *bridge; unsigned int refcount; - bool handler_for_func; }; /* diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 95af39c9a39..b306e993ad0 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -65,20 +65,6 @@ static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(acpi_handle handle, u32 type, void *data); static void free_bridge(struct kref *kref); -/* callback routine to check for the existence of a pci dock device */ -static acpi_status -is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - if (is_dock_device(handle)) { - (*count)++; - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - static void acpiphp_context_handler(acpi_handle handle, void *context) { /* Intentionally empty. */ @@ -179,14 +165,16 @@ static void free_bridge(struct kref *kref) } context = bridge->context; - /* Release the reference acquired by acpiphp_enumerate_slots(). */ - if (context->handler_for_func) + /* Root bridges will not have hotplug context. */ + if (context) { + /* Release the reference taken by acpiphp_enumerate_slots(). */ put_bridge(context->func->slot->bridge); + context->bridge = NULL; + acpiphp_put_context(context); + } put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); - context->bridge = NULL; - acpiphp_put_context(context); kfree(bridge); mutex_unlock(&acpiphp_context_lock); @@ -282,28 +270,24 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; - unsigned long long adr, sun; - int device, function, retval; + unsigned long long adr; + int device, function; struct pci_bus *pbus = bridge->pci_bus; - struct pci_dev *pdev; + struct pci_dev *pdev = bridge->pci_dev; u32 val; - if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) + if (pdev && device_is_managed_by_native_pciehp(pdev)) return AE_OK; status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (ACPI_FAILURE(status)) { - warn("can't evaluate _ADR (%#x)\n", status); + acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status); return AE_OK; } device = (adr >> 16) & 0xffff; function = adr & 0xffff; - pdev = bridge->pci_dev; - if (pdev && device_is_managed_by_native_pciehp(pdev)) - return AE_OK; - newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); if (!newfunc) return AE_NO_MEMORY; @@ -338,23 +322,10 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; - status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) { - /* - * use the count of the number of slots we've found - * for the number of the slot - */ - sun = bridge->nr_slots+1; - } - /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) - if (slot->device == device) { - if (slot->sun != sun) - warn("sibling found, but _SUN doesn't match!\n"); - + if (slot->device == device) goto slot_found; - } slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { @@ -364,34 +335,38 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot->bridge = bridge; slot->device = device; - slot->sun = sun; INIT_LIST_HEAD(&slot->funcs); mutex_init(&slot->crit_sect); mutex_lock(&bridge_mutex); list_add_tail(&slot->node, &bridge->slots); mutex_unlock(&bridge_mutex); - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(pbus), pbus->number, device); - retval = acpiphp_register_hotplug_slot(slot); - if (retval) { - if (retval == -EBUSY) - warn("Slot %llu already registered by another " - "hotplug driver\n", slot->sun); - else - warn("acpiphp_register_hotplug_slot failed " - "(err code = 0x%x)\n", retval); + /* Register slots for ejectable funtions only. */ + if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { + unsigned long long sun; + int retval; - bridge->nr_slots--; - mutex_lock(&bridge_mutex); - list_del(&slot->node); - mutex_unlock(&bridge_mutex); - kfree(slot); - status = AE_OK; - goto err; + bridge->nr_slots++; + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + sun = bridge->nr_slots; + + slot->sun = sun; + dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", + slot->sun, pci_domain_nr(pbus), pbus->number, device); + + retval = acpiphp_register_hotplug_slot(slot); + if (retval) { + bridge->nr_slots--; + if (retval == -EBUSY) + warn("Slot %llu already registered by another " + "hotplug driver\n", slot->sun); + else + warn("acpiphp_register_hotplug_slot failed " + "(err code = 0x%x)\n", retval); + } + /* Even if the slot registration fails, we can still use it. */ } slot_found: @@ -421,10 +396,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event, context); - if (ACPI_SUCCESS(status)) - context->handler_for_func = true; - else - err("failed to register interrupt notify handler\n"); + if (ACPI_FAILURE(status)) + acpi_handle_err(handle, + "failed to install notify handler\n"); } return AE_OK; @@ -438,18 +412,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, return status; } - -/* see if it's worth looking at this bridge */ -static int detect_ejectable_slots(acpi_handle handle) -{ - int found = acpi_pci_detect_ejectable(handle); - if (!found) { - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - is_pci_dock_device, NULL, (void *)&found, NULL); - } - return found; -} - static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { struct acpiphp_context *context; @@ -473,14 +435,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) struct acpiphp_slot *slot; struct acpiphp_func *func; acpi_status status; - acpi_handle handle = bridge->handle; - - if (!bridge->context->handler_for_func) { - status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - } list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -488,7 +442,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) unregister_hotplug_dock_device(func->handle); } if (!(func->flags & FUNC_HAS_DCK)) { - func->context->handler_for_func = false; status = acpi_remove_notify_handler(func->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event); @@ -678,9 +631,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) list_for_each_entry(func, &slot->funcs, sibling) { if (PCI_FUNC(dev->devfn) == func->function) { - /* check if this bridge has ejectable slots */ - if ((detect_ejectable_slots(func->handle) > 0)) - dev->is_hotplug_bridge = 1; + dev->is_hotplug_bridge = 1; break; } } @@ -988,8 +939,8 @@ void acpiphp_check_host_bridge(acpi_handle handle) static void hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context = data; + struct acpiphp_func *func = context->func; struct acpiphp_bridge *bridge; - struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; @@ -999,11 +950,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) if (bridge) get_bridge(bridge); - /* - * If context->func is not NULL, we are holding a reference to its - * parent bridge, so it won't go away until we drop that reference. - */ - func = context->func; mutex_unlock(&acpiphp_context_lock); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1041,9 +987,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if (!func) - break; - if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0)) break; @@ -1090,14 +1033,7 @@ static void hotplug_event_work(struct work_struct *work) acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event() */ - - mutex_lock(&acpiphp_context_lock); - if (context->func) - put_bridge(context->func->slot->bridge); - else - acpiphp_put_context(context); - - mutex_unlock(&acpiphp_context_lock); + put_bridge(context->func->slot->bridge); } /** @@ -1115,13 +1051,8 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - if (context->func) { - get_bridge(context->func->slot->bridge); - acpiphp_put_context(context); - } else if (!context->bridge) { - acpiphp_put_context(context); - context = NULL; - } + get_bridge(context->func->slot->bridge); + acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); /* @@ -1142,7 +1073,6 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) */ void acpiphp_enumerate_slots(struct pci_bus *bus) { - struct acpiphp_context *context; struct acpiphp_bridge *bridge; acpi_handle handle; acpi_status status; @@ -1151,7 +1081,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) return; handle = ACPI_HANDLE(bus->bridge); - if (!handle || detect_ejectable_slots(handle) <= 0) + if (!handle) return; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); @@ -1166,21 +1096,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->pci_dev = pci_dev_get(bus->self); bridge->pci_bus = bus; - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (!context) { - context = acpiphp_init_context(handle); - if (!context) { - mutex_unlock(&acpiphp_context_lock); - acpi_handle_err(handle, "No hotplug context\n"); - kfree(bridge); - return; - } - } - bridge->context = context; - context->bridge = bridge; - mutex_unlock(&acpiphp_context_lock); - /* * Grab a ref to the subordinate PCI bus in case the bus is * removed via PCI core logical hotplug. The ref pins the bus @@ -1188,6 +1103,35 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ get_device(&bus->dev); + if (!pci_is_root_bus(bridge->pci_bus)) { + struct acpiphp_context *context; + + /* + * This bridge should have been registered as a hotplug function + * under its parent, so the context has to be there. If not, we + * are in deep goo. + */ + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (WARN_ON(!context || !context->func)) { + mutex_unlock(&acpiphp_context_lock); + put_device(&bus->dev); + kfree(bridge); + return; + } + bridge->context = context; + context->bridge = bridge; + /* Get a reference to the parent bridge. */ + get_bridge(context->func->slot->bridge); + mutex_unlock(&acpiphp_context_lock); + } + + status = acpi_get_handle(bridge->handle, "_EJ0", &handle); + if (ACPI_SUCCESS(status)) { + dbg("found ejectable p2p bridge\n"); + bridge->flags |= BRIDGE_HAS_EJ0; + } + /* must be added to the list prior to calling register_slot */ mutex_lock(&bridge_mutex); list_add(&bridge->list, &bridge_list); @@ -1198,33 +1142,9 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) register_slot, NULL, bridge, NULL); if (ACPI_FAILURE(status)) { acpi_handle_err(bridge->handle, "failed to register slots\n"); - goto err; - } - - if (pci_is_root_bus(bridge->pci_bus)) - return; - - if (acpi_has_method(bridge->handle, "_EJ0")) { - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - } - if (context->handler_for_func) { - /* Notify handler already installed. */ - get_bridge(context->func->slot->bridge); - return; + cleanup_bridge(bridge); + put_bridge(bridge); } - - /* install notify handler for P2P bridges */ - status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, NULL); - if (ACPI_SUCCESS(status)) - return; - - acpi_handle_err(bridge->handle, "failed to register notify handler\n"); - - err: - cleanup_bridge(bridge); - put_bridge(bridge); } /* Destroy hotplug slots associated with the PCI bus */ -- cgit v1.2.3-70-g09d2 From 7342798d0ab850a630877a362bc5a4f033100f37 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot If the slot unique number is passed as an additional argument to acpiphp_register_hotplug_slot(), the 'sun' field in struct acpiphp_slot is only used by ibm_[s|g]et_attention_status(), but then it's more efficient to store it in struct slot. Thus move the 'sun' field from struct acpiphp_slot to struct slot changing its data type to unsigned int in the process, and redefine acpiphp_register_hotplug_slot() to take the slot number as separate argument. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 5 ++--- drivers/pci/hotplug/acpiphp_core.c | 6 ++++-- drivers/pci/hotplug/acpiphp_glue.c | 7 +++---- drivers/pci/hotplug/acpiphp_ibm.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 76a1c979a25..4f10aec81b8 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -60,6 +60,7 @@ struct slot { struct hotplug_slot *hotplug_slot; struct acpiphp_slot *acpi_slot; struct hotplug_slot_info info; + unsigned int sun; /* ACPI _SUN (Slot User Number) value */ }; static inline const char *slot_name(struct slot *slot) @@ -106,8 +107,6 @@ struct acpiphp_slot { struct mutex crit_sect; u8 device; /* pci device# */ - - unsigned long long sun; /* ACPI _SUN (slot unique number) */ u32 flags; /* see below */ }; @@ -179,7 +178,7 @@ struct acpiphp_attention_info /* acpiphp_core.c */ int acpiphp_register_attention(struct acpiphp_attention_info*info); int acpiphp_unregister_attention(struct acpiphp_attention_info *info); -int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot); +int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun); void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); /* acpiphp_glue.c */ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index ca8127950fc..1798740f7e1 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -290,7 +290,8 @@ static void release_slot(struct hotplug_slot *hotplug_slot) } /* callback routine to initialize 'struct slot' for each slot */ -int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) +int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, + unsigned int sun) { struct slot *slot; int retval = -ENOMEM; @@ -317,7 +318,8 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); acpiphp_slot->slot = slot; - snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun); + slot->sun = sun; + snprintf(name, SLOT_NAME_SIZE, "%u", sun); retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bridge->pci_bus, diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b306e993ad0..a251071b7d7 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -352,16 +352,15 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (ACPI_FAILURE(status)) sun = bridge->nr_slots; - slot->sun = sun; dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(pbus), pbus->number, device); + sun, pci_domain_nr(pbus), pbus->number, device); - retval = acpiphp_register_hotplug_slot(slot); + retval = acpiphp_register_hotplug_slot(slot, sun); if (retval) { bridge->nr_slots--; if (retval == -EBUSY) warn("Slot %llu already registered by another " - "hotplug driver\n", slot->sun); + "hotplug driver\n", sun); else warn("acpiphp_register_hotplug_slot failed " "(err code = 0x%x)\n", retval); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index c35e8ad6db0..8d45f6d6954 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -66,7 +66,7 @@ do { \ #define IBM_HARDWARE_ID1 "IBM37D0" #define IBM_HARDWARE_ID2 "IBM37D4" -#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun) +#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun) /* union apci_descriptor - allows access to the * various device descriptors that are embedded in the -- cgit v1.2.3-70-g09d2 From 75a33ed1b58005e455cb6533a7689ac0eb6bedd6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge The only bridge flag used by the ACPI-based PCI hotplug (ACPIPHP) code is BRIDGE_HAS_EJ0, but it is only used by the event handling function hotplug_event() and if that flag is set, the corresponding function flag FUNC_HAS_EJ0 is set as well, so that bridge flag is redundant. For this reason, drop BRIDGE_HAS_EJ0 and all code referring to it and since it is the only bridge flag defined, drop the flags field from struct acpiphp_bridge entirely. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 5 ----- drivers/pci/hotplug/acpiphp_glue.c | 9 --------- 2 files changed, 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 4f10aec81b8..990fbfd110f 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -83,8 +83,6 @@ struct acpiphp_bridge { int nr_slots; - u32 flags; - /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ struct pci_bus *pci_bus; @@ -154,9 +152,6 @@ struct acpiphp_attention_info /* ACPI _STA method value (ignore bit 4; battery present) */ #define ACPI_STA_ALL (0x0000000f) -/* bridge flags */ -#define BRIDGE_HAS_EJ0 (0x00000001) - /* slot flags */ #define SLOT_POWEREDON (0x00000001) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a251071b7d7..5d79175b9a0 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -986,9 +986,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0)) - break; - if (!(acpiphp_disable_slot(func->slot))) acpiphp_eject_slot(func->slot); @@ -1125,12 +1122,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) mutex_unlock(&acpiphp_context_lock); } - status = acpi_get_handle(bridge->handle, "_EJ0", &handle); - if (ACPI_SUCCESS(status)) { - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - } - /* must be added to the list prior to calling register_slot */ mutex_lock(&bridge_mutex); list_add(&bridge->list, &bridge_list); -- cgit v1.2.3-70-g09d2 From bd4674dfc5fc704837148f36af41e1e0a640dfec Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Since there has to be a struct acpiphp_func object for every struct acpiphp_context created by register_slot(), the struct acpiphp_func one can be embedded into the struct acpiphp_context one, which allows some code simplifications to be made. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 8 +++++-- drivers/pci/hotplug/acpiphp_glue.c | 44 ++++++++++++++------------------------ 2 files changed, 22 insertions(+), 30 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 990fbfd110f..31c84bdd2be 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -116,7 +116,6 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { - struct acpiphp_context *context; struct acpiphp_slot *slot; /* parent */ struct list_head sibling; @@ -128,11 +127,16 @@ struct acpiphp_func { struct acpiphp_context { acpi_handle handle; - struct acpiphp_func *func; + struct acpiphp_func func; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) +{ + return container_of(func, struct acpiphp_context, func); +} + /* * struct acpiphp_attention_info - device specific attention registration * diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 5d79175b9a0..cc7453e0722 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -128,7 +128,7 @@ static void acpiphp_put_context(struct acpiphp_context *context) if (--context->refcount) return; - WARN_ON(context->func || context->bridge); + WARN_ON(context->bridge); acpi_detach_data(context->handle, acpiphp_context_handler); kfree(context); } @@ -155,12 +155,9 @@ static void free_bridge(struct kref *kref) bridge = container_of(kref, struct acpiphp_bridge, ref); list_for_each_entry_safe(slot, next, &bridge->slots, node) { - list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { - context = func->context; - context->func = NULL; - acpiphp_put_context(context); - kfree(func); - } + list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) + acpiphp_put_context(func_to_context(func)); + kfree(slot); } @@ -168,7 +165,7 @@ static void free_bridge(struct kref *kref) /* Root bridges will not have hotplug context. */ if (context) { /* Release the reference taken by acpiphp_enumerate_slots(). */ - put_bridge(context->func->slot->bridge); + put_bridge(context->func.slot->bridge); context->bridge = NULL; acpiphp_put_context(context); } @@ -190,7 +187,7 @@ static void free_bridge(struct kref *kref) static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { struct acpiphp_context *context = data; - struct pci_bus *bus = context->func->slot->bridge->pci_bus; + struct pci_bus *bus = context->func.slot->bridge->pci_bus; u32 buses; if (!bus->self) @@ -251,14 +248,14 @@ static void acpiphp_dock_init(void *data) { struct acpiphp_context *context = data; - get_bridge(context->func->slot->bridge); + get_bridge(context->func.slot->bridge); } static void acpiphp_dock_release(void *data) { struct acpiphp_context *context = data; - put_bridge(context->func->slot->bridge); + put_bridge(context->func.slot->bridge); } /* callback routine to register each ACPI PCI slot object */ @@ -288,23 +285,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, device = (adr >> 16) & 0xffff; function = adr & 0xffff; - newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); - if (!newfunc) - return AE_NO_MEMORY; - - newfunc->handle = handle; - newfunc->function = function; - mutex_lock(&acpiphp_context_lock); context = acpiphp_init_context(handle); if (!context) { mutex_unlock(&acpiphp_context_lock); acpi_handle_err(handle, "No hotplug context\n"); - kfree(newfunc); return AE_NOT_EXIST; } - newfunc->context = context; - context->func = newfunc; + newfunc = &context->func; + newfunc->handle = handle; + newfunc->function = function; mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) @@ -404,10 +394,8 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, err: mutex_lock(&acpiphp_context_lock); - context->func = NULL; acpiphp_put_context(context); mutex_unlock(&acpiphp_context_lock); - kfree(newfunc); return status; } @@ -938,7 +926,7 @@ void acpiphp_check_host_bridge(acpi_handle handle) static void hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context = data; - struct acpiphp_func *func = context->func; + struct acpiphp_func *func = &context->func; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -1029,7 +1017,7 @@ static void hotplug_event_work(struct work_struct *work) acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event() */ - put_bridge(context->func->slot->bridge); + put_bridge(context->func.slot->bridge); } /** @@ -1047,7 +1035,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - get_bridge(context->func->slot->bridge); + get_bridge(context->func.slot->bridge); acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); @@ -1109,7 +1097,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (WARN_ON(!context || !context->func)) { + if (WARN_ON(!context)) { mutex_unlock(&acpiphp_context_lock); put_device(&bus->dev); kfree(bridge); @@ -1118,7 +1106,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->context = context; context->bridge = bridge; /* Get a reference to the parent bridge. */ - get_bridge(context->func->slot->bridge); + get_bridge(context->func.slot->bridge); mutex_unlock(&acpiphp_context_lock); } -- cgit v1.2.3-70-g09d2 From 5a3bc573ae32a71bb9e307812d4de1bdcab6b9fb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func The ACPI handle stored in struct acpiphp_func is also stored in the struct acpiphp_context object containing it and it is trivial to get from a struct acpiphp_func pointer to the handle field of the outer struct acpiphp_context. Hence, the handle field of struct acpiphp_func is redundant, so drop it and provide a helper function, func_to_handle(), allowing it users to get the ACPI handle for the given struct acpiphp_func pointer. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 6 ++++- drivers/pci/hotplug/acpiphp_glue.c | 54 ++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 24 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 31c84bdd2be..dbb94258da5 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -119,7 +119,6 @@ struct acpiphp_func { struct acpiphp_slot *slot; /* parent */ struct list_head sibling; - acpi_handle handle; u8 function; /* pci function# */ u32 flags; /* see below */ @@ -137,6 +136,11 @@ static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) return container_of(func, struct acpiphp_context, func); } +static inline acpi_handle func_to_handle(struct acpiphp_func *func) +{ + return func_to_context(func)->handle; +} + /* * struct acpiphp_attention_info - device specific attention registration * diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cc7453e0722..9e4ad6f3764 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -293,7 +293,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, return AE_NOT_EXIST; } newfunc = &context->func; - newfunc->handle = handle; newfunc->function = function; mutex_unlock(&acpiphp_context_lock); @@ -425,11 +424,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { - if (is_dock_device(func->handle)) { - unregister_hotplug_dock_device(func->handle); - } + acpi_handle handle = func_to_handle(func); + + if (is_dock_device(handle)) + unregister_hotplug_dock_device(handle); + if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(func->handle, + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event); if (ACPI_FAILURE(status)) @@ -457,7 +458,8 @@ static int power_on_slot(struct acpiphp_slot *slot) list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_PS0) { dbg("%s: executing _PS0\n", __func__); - status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); + status = acpi_evaluate_object(func_to_handle(func), + "_PS0", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS0 failed\n", __func__); retval = -1; @@ -489,7 +491,8 @@ static int power_off_slot(struct acpiphp_slot *slot) list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_PS3) { - status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); + status = acpi_evaluate_object(func_to_handle(func), + "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __func__); retval = -1; @@ -543,10 +546,11 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) */ static int acpiphp_bus_add(struct acpiphp_func *func) { + acpi_handle handle = func_to_handle(func); struct acpi_device *device; int ret_val; - if (!acpi_bus_get_device(func->handle, &device)) { + if (!acpi_bus_get_device(handle, &device)) { dbg("bus exists... trim\n"); /* this shouldn't be in here, so remove * the bus then re-add it... @@ -554,9 +558,9 @@ static int acpiphp_bus_add(struct acpiphp_func *func) acpi_bus_trim(device); } - ret_val = acpi_bus_scan(func->handle); + ret_val = acpi_bus_scan(handle); if (!ret_val) - ret_val = acpi_bus_get_device(func->handle, &device); + ret_val = acpi_bus_get_device(handle, &device); if (ret_val) dbg("error adding bus, %x\n", -ret_val); @@ -598,7 +602,8 @@ static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) params[1].type = ACPI_TYPE_INTEGER; params[1].integer.value = 1; /* _REG is optional, we don't care about if there is failure */ - acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL); + acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list, + NULL); } } @@ -739,9 +744,8 @@ static int disable_device(struct acpiphp_slot *slot) pci_dev_put(pdev); } - list_for_each_entry(func, &slot->funcs, sibling) { - acpiphp_bus_trim(func->handle); - } + list_for_each_entry(func, &slot->funcs, sibling) + acpiphp_bus_trim(func_to_handle(func)); slot->flags &= (~SLOT_ENABLED); @@ -763,17 +767,20 @@ static int disable_device(struct acpiphp_slot *slot) */ static unsigned int get_slot_status(struct acpiphp_slot *slot) { - acpi_status status; unsigned long long sta = 0; - u32 dvid; struct acpiphp_func *func; list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { - status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); + acpi_status status; + + status = acpi_evaluate_integer(func_to_handle(func), + "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && sta) break; } else { + u32 dvid; + pci_bus_read_config_dword(slot->bridge->pci_bus, PCI_DEVFN(slot->device, func->function), @@ -798,12 +805,13 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot) list_for_each_entry(func, &slot->funcs, sibling) { /* We don't want to call _EJ0 on non-existing functions. */ - if ((func->flags & FUNC_HAS_EJ0)) { - if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle))) - return -1; - else - break; - } + if (!(func->flags & FUNC_HAS_EJ0)) + continue; + + if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func)))) + return -1; + else + break; } return 0; } -- cgit v1.2.3-70-g09d2 From 89373a55d294b53e85792dbc636015b83d492f67 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge The handle field in struct acpiphp_bridge is only used by acpiphp_enumerate_slots(), but in that function the local handle variable can be used instead, so make that happen and drop handle from struct acpiphp_bridge. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index dbb94258da5..afd7110a1ca 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -77,7 +77,6 @@ struct acpiphp_bridge { struct list_head list; struct list_head slots; struct kref ref; - acpi_handle handle; struct acpiphp_context *context; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 9e4ad6f3764..bbbf8f4e848 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1084,7 +1084,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) INIT_LIST_HEAD(&bridge->slots); kref_init(&bridge->ref); - bridge->handle = handle; bridge->pci_dev = pci_dev_get(bus->self); bridge->pci_bus = bus; @@ -1124,10 +1123,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) mutex_unlock(&bridge_mutex); /* register all slot objects under this bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, register_slot, NULL, bridge, NULL); if (ACPI_FAILURE(status)) { - acpi_handle_err(bridge->handle, "failed to register slots\n"); + acpi_handle_err(handle, "failed to register slots\n"); cleanup_bridge(bridge); put_bridge(bridge); } -- cgit v1.2.3-70-g09d2 From bda46dbb6626c923a800b4033c86fefa613cd64c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Store parent in functions and bus in slots To avoid chasing more pointers than necessary in some situations, move the bridge pointer from struct acpiphp_slot to struct acpiphp_func (and call it 'parent') and add a bus pointer to struct acpiphp_slot. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 5 +++-- drivers/pci/hotplug/acpiphp_core.c | 6 ++---- drivers/pci/hotplug/acpiphp_glue.c | 25 +++++++++++++------------ 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index afd7110a1ca..7d3251d2f4a 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -97,7 +97,7 @@ struct acpiphp_bridge { */ struct acpiphp_slot { struct list_head node; - struct acpiphp_bridge *bridge; /* parent */ + struct pci_bus *bus; struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; @@ -115,7 +115,8 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { - struct acpiphp_slot *slot; /* parent */ + struct acpiphp_bridge *parent; + struct acpiphp_slot *slot; struct list_head sibling; diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 1798740f7e1..8f20e602161 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -321,10 +321,8 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, slot->sun = sun; snprintf(name, SLOT_NAME_SIZE, "%u", sun); - retval = pci_hp_register(slot->hotplug_slot, - acpiphp_slot->bridge->pci_bus, - acpiphp_slot->device, - name); + retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus, + acpiphp_slot->device, name); if (retval == -EBUSY) goto error_hpslot; if (retval) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bbbf8f4e848..7ac315afa43 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -165,7 +165,7 @@ static void free_bridge(struct kref *kref) /* Root bridges will not have hotplug context. */ if (context) { /* Release the reference taken by acpiphp_enumerate_slots(). */ - put_bridge(context->func.slot->bridge); + put_bridge(context->func.parent); context->bridge = NULL; acpiphp_put_context(context); } @@ -187,7 +187,7 @@ static void free_bridge(struct kref *kref) static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { struct acpiphp_context *context = data; - struct pci_bus *bus = context->func.slot->bridge->pci_bus; + struct pci_bus *bus = context->func.slot->bus; u32 buses; if (!bus->self) @@ -248,14 +248,14 @@ static void acpiphp_dock_init(void *data) { struct acpiphp_context *context = data; - get_bridge(context->func.slot->bridge); + get_bridge(context->func.parent); } static void acpiphp_dock_release(void *data) { struct acpiphp_context *context = data; - put_bridge(context->func.slot->bridge); + put_bridge(context->func.parent); } /* callback routine to register each ACPI PCI slot object */ @@ -294,6 +294,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, } newfunc = &context->func; newfunc->function = function; + newfunc->parent = bridge; mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) @@ -322,7 +323,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, goto err; } - slot->bridge = bridge; + slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); mutex_init(&slot->crit_sect); @@ -639,7 +640,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) static int __ref enable_device(struct acpiphp_slot *slot) { struct pci_dev *dev; - struct pci_bus *bus = slot->bridge->pci_bus; + struct pci_bus *bus = slot->bus; struct acpiphp_func *func; int num, max, pass; LIST_HEAD(add_list); @@ -709,7 +710,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) /* 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->bridge->pci_bus; + struct pci_bus *bus = slot->bus; struct pci_dev *dev; struct pci_dev *ret = NULL; @@ -781,7 +782,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) } else { u32 dvid; - pci_bus_read_config_dword(slot->bridge->pci_bus, + pci_bus_read_config_dword(slot->bus, PCI_DEVFN(slot->device, func->function), PCI_VENDOR_ID, &dvid); @@ -970,7 +971,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) if (bridge) acpiphp_check_bridge(bridge); else - acpiphp_check_bridge(func->slot->bridge); + acpiphp_check_bridge(func->parent); break; @@ -1025,7 +1026,7 @@ static void hotplug_event_work(struct work_struct *work) acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event() */ - put_bridge(context->func.slot->bridge); + put_bridge(context->func.parent); } /** @@ -1043,7 +1044,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - get_bridge(context->func.slot->bridge); + get_bridge(context->func.parent); acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); @@ -1113,7 +1114,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->context = context; context->bridge = bridge; /* Get a reference to the parent bridge. */ - get_bridge(context->func.slot->bridge); + get_bridge(context->func.parent); mutex_unlock(&acpiphp_context_lock); } -- cgit v1.2.3-70-g09d2 From 236e26245a6a437c4afbf33a5ad94cf61d1a7a7c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Rework namespace scanning and trimming routines The acpiphp_bus_trim() and acpiphp_bus_add() functions need not return error codes that are never checked, so redefine them and simplify them a bit. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 52 ++++++++++---------------------------- 1 file changed, 13 insertions(+), 39 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7ac315afa43..b136eee7a93 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -540,53 +540,27 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) return max; } - /** - * acpiphp_bus_add - add a new bus to acpi subsystem - * @func: acpiphp_func of the bridge + * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. + * @handle: ACPI device object handle to start from. */ -static int acpiphp_bus_add(struct acpiphp_func *func) +static void acpiphp_bus_trim(acpi_handle handle) { - acpi_handle handle = func_to_handle(func); - struct acpi_device *device; - int ret_val; - - if (!acpi_bus_get_device(handle, &device)) { - dbg("bus exists... trim\n"); - /* this shouldn't be in here, so remove - * the bus then re-add it... - */ - acpi_bus_trim(device); - } + struct acpi_device *adev = NULL; - ret_val = acpi_bus_scan(handle); - if (!ret_val) - ret_val = acpi_bus_get_device(handle, &device); - - if (ret_val) - dbg("error adding bus, %x\n", -ret_val); - - return ret_val; + acpi_bus_get_device(handle, &adev); + if (adev) + acpi_bus_trim(adev); } - /** - * acpiphp_bus_trim - trim a bus from acpi subsystem - * @handle: handle to acpi namespace + * acpiphp_bus_add - Scan ACPI namespace subtree. + * @handle: ACPI object handle to start the scan from. */ -static int acpiphp_bus_trim(acpi_handle handle) +static void acpiphp_bus_add(acpi_handle handle) { - struct acpi_device *device; - int retval; - - retval = acpi_bus_get_device(handle, &device); - if (retval) { - dbg("acpi_device not found\n"); - return retval; - } - - acpi_bus_trim(device); - return 0; + acpiphp_bus_trim(handle); + acpi_bus_scan(handle); } static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) @@ -649,7 +623,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) goto err_exit; list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func); + acpiphp_bus_add(func_to_handle(func)); num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); if (num == 0) { -- cgit v1.2.3-70-g09d2 From 07bb735378919e4b5863077f5c1b4037b6ca1a99 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Two checks in check_hotplug_bridge() are redundant (they have been done by the caller already), so drop them. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b136eee7a93..f131512b7bb 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -586,16 +586,10 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) { struct acpiphp_func *func; - if (!dev->subordinate) - return; - /* quirk, or pcie could set it already */ if (dev->is_hotplug_bridge) return; - if (PCI_SLOT(dev->devfn) != slot->device) - return; - list_for_each_entry(func, &slot->funcs, sibling) { if (PCI_FUNC(dev->devfn) == func->function) { dev->is_hotplug_bridge = 1; -- cgit v1.2.3-70-g09d2 From ad21d2d046a8a6bbf1b10c04770ec835a4e379e6 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Both acpiphp_disable_slot() and acpiphp_eject_slot() are always called together so instead of calling each separately we can consolidate them into one function acpiphp_disable_and_eject_slot() that does both (but it will return success on _EJ0 failures that were ignored in the majority of call sites anyway). [rjw: Rebased plus minor tweaks] Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp.h | 3 +-- drivers/pci/hotplug/acpiphp_core.c | 6 +---- drivers/pci/hotplug/acpiphp_glue.c | 50 ++++++++++++++------------------------ 3 files changed, 20 insertions(+), 39 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7d3251d2f4a..fe6c79bb8ee 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -188,8 +188,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); int acpiphp_enable_slot(struct acpiphp_slot *slot); -int acpiphp_disable_slot(struct acpiphp_slot *slot); -int acpiphp_eject_slot(struct acpiphp_slot *slot); +int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); u8 acpiphp_get_power_status(struct acpiphp_slot *slot); u8 acpiphp_get_attention_status(struct acpiphp_slot *slot); u8 acpiphp_get_latch_status(struct acpiphp_slot *slot); diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 8f20e602161..bf2203ef130 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) static int disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - int retval; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* disable the specified slot */ - retval = acpiphp_disable_slot(slot->acpi_slot); - if (!retval) - retval = acpiphp_eject_slot(slot->acpi_slot); - return retval; + return acpiphp_disable_and_eject_slot(slot->acpi_slot); } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index f131512b7bb..6db790ebd1e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -764,27 +764,6 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } -/** - * acpiphp_eject_slot - physically eject the slot - * @slot: ACPI PHP slot - */ -int acpiphp_eject_slot(struct acpiphp_slot *slot) -{ - struct acpiphp_func *func; - - list_for_each_entry(func, &slot->funcs, sibling) { - /* We don't want to call _EJ0 on non-existing functions. */ - if (!(func->flags & FUNC_HAS_EJ0)) - continue; - - if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func)))) - return -1; - else - break; - } - return 0; -} - /** * acpiphp_check_bridge - re-enumerate devices * @bridge: where to begin re-enumeration @@ -805,13 +784,11 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) if (slot->flags & SLOT_ENABLED) { if (status == ACPI_STA_ALL) continue; - retval = acpiphp_disable_slot(slot); - if (retval) { - err("Error occurred in disabling\n"); + + retval = acpiphp_disable_and_eject_slot(slot); + if (retval) goto err_exit; - } else { - acpiphp_eject_slot(slot); - } + disabled++; } else { if (status != ACPI_STA_ALL) @@ -951,9 +928,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); - + acpiphp_disable_and_eject_slot(func->slot); break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: @@ -1148,11 +1123,12 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) } /** - * acpiphp_disable_slot - power off slot + * acpiphp_disable_and_eject_slot - power off and eject slot * @slot: ACPI PHP slot */ -int acpiphp_disable_slot(struct acpiphp_slot *slot) +int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) { + struct acpiphp_func *func; int retval = 0; mutex_lock(&slot->crit_sect); @@ -1167,6 +1143,16 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; + list_for_each_entry(func, &slot->funcs, sibling) + if (func->flags & FUNC_HAS_EJ0) { + acpi_handle handle = func_to_handle(func); + + if (ACPI_FAILURE(acpi_evaluate_ej0(handle))) + acpi_handle_err(handle, "_EJ0 failed\n"); + + break; + } + err_exit: mutex_unlock(&slot->crit_sect); return retval; -- cgit v1.2.3-70-g09d2 From 5c8d0e1dc475f0f35b5a774c92c68c3f7dbd3f5f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Do not queue up event handling work items in vain Modify handle_hotplug_event() to avoid queing up the execution of handle_hotplug_event_work_fn() as a work item on kacpi_hotplug_wq for non-hotplug events, such as ACPI_NOTIFY_DEVICE_WAKE. Move the code printing diagnostic messages for those events into handle_hotplug_event(). In addition to that, remove the bogus comment about how the core should distinguish between hotplug and non-hotplug events and queue them up on different workqueues. The core clearly cannot know in advance what events will be interesting to the given caller of acpi_install_notify_handler(). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 64 +++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 35 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 6db790ebd1e..44191db1f05 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -920,36 +920,11 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) break; - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __func__, objname); - break; - case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); acpiphp_disable_and_eject_slot(func->slot); break; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - printk(KERN_ERR "Device %s cannot be configured due" - " to a frequency mismatch\n", objname); - break; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - printk(KERN_ERR "Device %s cannot be configured due" - " to a bus mode mismatch\n", objname); - break; - - case ACPI_NOTIFY_POWER_FAULT: - printk(KERN_ERR "Device %s has suffered a power fault\n", - objname); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, - objname); - break; } if (bridge) @@ -984,23 +959,42 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context; + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + case ACPI_NOTIFY_EJECT_REQUEST: + 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"); + return; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + return; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + return; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + return; + } + mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { get_bridge(context->func.parent); acpiphp_put_context(context); + alloc_acpi_hp_work(handle, type, context, hotplug_event_work); } mutex_unlock(&acpiphp_context_lock); - /* - * Currently the code adds all hotplug events to the kacpid_wq - * queue when it should add hotplug events to the kacpi_hotplug_wq. - * The proper way to fix this is to reorganize the code so that - * drivers (dock, etc.) do not call acpi_os_execute(), etc. - * For now just re-add this work to the kacpi_hotplug_wq so we - * don't deadlock on hotplug actions. - */ - if (context) - alloc_acpi_hp_work(handle, type, context, hotplug_event_work); } /* -- cgit v1.2.3-70-g09d2 From bc805a55392a7cb3e9b1251d00449c70e3967fc5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly The ACPI-based PCI hotplug (acpiphp) core code need not and really should not execute _PS0 and _PS3 directly for devices it handles. First of all, it is not necessary to put devices into D3 after acpi_bus_trim() has walked through them, because acpi_device_unregister() invoked by it puts each device into D3cold before returning. Thus after disable_device() the slot should be powered down already. Second, calling _PS0 directly on ACPI device objects may not be appropriate, because it may require power resources to be set up in a specific way in advance and that must be taken care of by the ACPI core. Thus modify acpiphp_bus_add() to power up the device using the appropriate interface after it has run acpi_bus_scan() on its handle. After that, the functions executing _PS0 and _PS3, power_on_slot() and power_off_slot(), are not necessary any more, so drop them and update the code calling them accordingly. Also drop the function flags related to device power states, since they aren't useful any more too. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp.h | 7 +-- drivers/pci/hotplug/acpiphp_glue.c | 106 ++++--------------------------------- 2 files changed, 10 insertions(+), 103 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index fe6c79bb8ee..ca2c91df3d1 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -162,7 +162,6 @@ struct acpiphp_attention_info /* slot flags */ -#define SLOT_POWEREDON (0x00000001) #define SLOT_ENABLED (0x00000002) #define SLOT_MULTIFUNCTION (0x00000004) @@ -170,11 +169,7 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_PS0 (0x00000010) -#define FUNC_HAS_PS1 (0x00000020) -#define FUNC_HAS_PS2 (0x00000040) -#define FUNC_HAS_PS3 (0x00000080) -#define FUNC_HAS_DCK (0x00000100) +#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 44191db1f05..b6691cc8230 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -303,12 +303,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (acpi_has_method(handle, "_PS0")) - newfunc->flags |= FUNC_HAS_PS0; - - if (acpi_has_method(handle, "_PS3")) - newfunc->flags |= FUNC_HAS_PS3; - if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; @@ -366,7 +360,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), &val, 60*1000)) - slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); + slot->flags |= SLOT_ENABLED; if (is_dock_device(handle)) { /* we don't want to call this device's _EJ0 @@ -446,73 +440,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) mutex_unlock(&bridge_mutex); } -static int power_on_slot(struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - int retval = 0; - - /* if already enabled, just skip */ - if (slot->flags & SLOT_POWEREDON) - goto err_exit; - - list_for_each_entry(func, &slot->funcs, sibling) { - if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0\n", __func__); - status = acpi_evaluate_object(func_to_handle(func), - "_PS0", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS0 failed\n", __func__); - retval = -1; - goto err_exit; - } else - break; - } - } - - /* TBD: evaluate _STA to check if the slot is enabled */ - - slot->flags |= SLOT_POWEREDON; - - err_exit: - return retval; -} - - -static int power_off_slot(struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - - int retval = 0; - - /* if already disabled, just skip */ - if ((slot->flags & SLOT_POWEREDON) == 0) - goto err_exit; - - list_for_each_entry(func, &slot->funcs, sibling) { - if (func->flags & FUNC_HAS_PS3) { - status = acpi_evaluate_object(func_to_handle(func), - "_PS3", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS3 failed\n", __func__); - retval = -1; - goto err_exit; - } else - break; - } - } - - /* TBD: evaluate _STA to check if the slot is disabled */ - - slot->flags &= (~SLOT_POWEREDON); - - err_exit: - return retval; -} - - - /** * acpiphp_max_busnr - return the highest reserved bus number under the given bus. * @bus: bus to start search with @@ -559,8 +486,13 @@ static void acpiphp_bus_trim(acpi_handle handle) */ static void acpiphp_bus_add(acpi_handle handle) { + struct acpi_device *adev = NULL; + acpiphp_bus_trim(handle); acpi_bus_scan(handle); + acpi_bus_get_device(handle, &adev); + if (adev) + acpi_device_set_power(adev, ACPI_STATE_D0); } static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) @@ -1095,23 +1027,8 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) int retval; mutex_lock(&slot->crit_sect); - - /* wake up all functions */ - retval = power_on_slot(slot); - if (retval) - goto err_exit; - - if (get_slot_status(slot) == ACPI_STA_ALL) { - /* configure all functions */ - retval = enable_device(slot); - if (retval) - power_off_slot(slot); - } else { - dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__); - power_off_slot(slot); - } - - err_exit: + /* configure all functions */ + retval = enable_device(slot); mutex_unlock(&slot->crit_sect); return retval; } @@ -1132,11 +1049,6 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; - /* power off all functions */ - retval = power_off_slot(slot); - if (retval) - goto err_exit; - list_for_each_entry(func, &slot->funcs, sibling) if (func->flags & FUNC_HAS_EJ0) { acpi_handle handle = func_to_handle(func); @@ -1159,7 +1071,7 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) */ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) { - return (slot->flags & SLOT_POWEREDON); + return (slot->flags & SLOT_ENABLED); } -- cgit v1.2.3-70-g09d2 From 55502ddb2d83ada0661733361ec14b9cbef157a5 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() With Thunderbolt you can daisy chain devices: connect new devices to an already plugged one. In that case the "hotplug slot" is already enabled, but we still want to look for new PCI devices behind it. Reuse enable_device() to scan for new PCI devices on enabled slots and push the SLOT_ENABLED check up into acpiphp_enable_slot(). [rjw: Rebased, modified the changelog] Signed-off-by: Kirill A. Shutemov Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b6691cc8230..c7a668e1fc1 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -545,9 +545,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) int num, max, pass; LIST_HEAD(add_list); - if (slot->flags & SLOT_ENABLED) - goto err_exit; - list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_add(func_to_handle(func)); @@ -1024,11 +1021,14 @@ void acpiphp_remove_slots(struct pci_bus *bus) */ int acpiphp_enable_slot(struct acpiphp_slot *slot) { - int retval; + int retval = 0; mutex_lock(&slot->crit_sect); + /* configure all functions */ - retval = enable_device(slot); + if (!(slot->flags & SLOT_ENABLED)) + retval = enable_device(slot); + mutex_unlock(&slot->crit_sect); return retval; } -- cgit v1.2.3-70-g09d2 From b91182a67c53db227e34921838dd683090ecfabc Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Currently, enable_device() checks the return value of pci_scan_slot() and returns immediately if that's 0 (meaning that no new functions have been found in the slot). However, if one of the functions in the slot is a bridge, some new devices may appear below it even if the bridge itself is present continuously, so it generally is necessary to do the rescan anyway just in case. [In particular, that's necessary with the Thunderbolt daisy chaining in which case new devices may be connected to the existing ones down the chain.] The correctness of this change relies on the ability of pcibios_resource_survey_bus() to detect if it has already been called for the given bus and to skip it if so. Failure to do that will lead to resource allocation conflicts. [rjw: Changelog] Signed-off-by: Kirill A. Shutemov Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index c7a668e1fc1..21a6269501e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -542,18 +542,13 @@ static int __ref enable_device(struct acpiphp_slot *slot) struct pci_dev *dev; struct pci_bus *bus = slot->bus; struct acpiphp_func *func; - int num, max, pass; + int max, pass; LIST_HEAD(add_list); list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_add(func_to_handle(func)); - num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); - if (num == 0) { - /* Maybe only part of funcs are added. */ - dbg("No new device found\n"); - goto err_exit; - } + pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); max = acpiphp_max_busnr(bus); for (pass = 0; pass < 2; pass++) { @@ -599,8 +594,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) } } - - err_exit: return 0; } -- cgit v1.2.3-70-g09d2 From 4ebe34503baa0644c9352bcd76d4cf573bffe206 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 16 Jul 2013 22:10:35 +0200 Subject: ACPI / hotplug / PCI: Check for new devices on enabled slots The current implementation of acpiphp_check_bridge() is pretty dumb: - It enables a slot if it's not enabled and the slot status is ACPI_STA_ALL. - It disables a slot if it's enabled and the slot status is not ACPI_STA_ALL. This behavior is not sufficient to handle the Thunderbolt daisy chaining case properly, however, because in that case the bus behind the already enabled slot needs to be rescanned for new devices. For this reason, modify acpiphp_check_bridge() so that slots are disabled and stopped if they are not in the ACPI_STA_ALL state. For slots in the ACPI_STA_ALL state, devices behind them that don't respond are trimmed using a new function, trim_stale_devices(), introduced specifically for this purpose. That function walks the given bus and checks each device on it. If the device doesn't respond, it is assumed to be gone and is removed. Once all of the stale devices directy behind the slot have been removed, acpiphp_check_bridge() will start looking for new devices that might have appeared on the given bus. It will do that even if the slot is already enabled (SLOT_ENABLED is set for it). In addition to that, make the bus check notification ignore SLOT_ENABLED and go for enable_device() directly if bridge is NULL, so that devices behind the slot are re-enumerated in that case too. This change is based on earlier patches from Kirill A Shutemov and Mika Westerberg. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 91 ++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 29 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 21a6269501e..e2e5e308881 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -686,6 +687,45 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } +/** + * trim_stale_devices - remove PCI devices that are not responding. + * @dev: PCI device to start walking the hierarchy from. + */ +static void trim_stale_devices(struct pci_dev *dev) +{ + acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct pci_bus *bus = dev->subordinate; + bool alive = false; + + if (handle) { + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL; + } + if (!alive) { + u32 v; + + /* Check if the device responds. */ + alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0); + } + if (!alive) { + pci_stop_and_remove_bus_device(dev); + if (handle) + acpiphp_bus_trim(handle); + } else if (bus) { + struct pci_dev *child, *tmp; + + /* 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) + trim_stale_devices(child); + + pm_runtime_put(&dev->dev); + } +} + /** * acpiphp_check_bridge - re-enumerate devices * @bridge: where to begin re-enumeration @@ -693,41 +733,30 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) * Iterate over all slots under this bridge and make sure that if a * card is present they are enabled, and if not they are disabled. */ -static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) +static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) { struct acpiphp_slot *slot; - int retval = 0; - int enabled, disabled; - - enabled = disabled = 0; list_for_each_entry(slot, &bridge->slots, node) { - unsigned int status = get_slot_status(slot); - if (slot->flags & SLOT_ENABLED) { - if (status == ACPI_STA_ALL) - continue; - - retval = acpiphp_disable_and_eject_slot(slot); - if (retval) - goto err_exit; - - disabled++; + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *tmp; + + mutex_lock(&slot->crit_sect); + /* wake up all functions */ + if (get_slot_status(slot) == ACPI_STA_ALL) { + /* remove stale devices if any */ + list_for_each_entry_safe(dev, tmp, &bus->devices, + bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + trim_stale_devices(dev); + + /* configure all functions */ + enable_device(slot); } else { - if (status != ACPI_STA_ALL) - continue; - retval = acpiphp_enable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - goto err_exit; - } - enabled++; + disable_device(slot); } + mutex_unlock(&slot->crit_sect); } - - dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled); - - err_exit: - return retval; } static void acpiphp_set_hpp_values(struct pci_bus *bus) @@ -828,7 +857,11 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); } else { - acpiphp_enable_slot(func->slot); + struct acpiphp_slot *slot = func->slot; + + mutex_lock(&slot->crit_sect); + enable_device(slot); + mutex_unlock(&slot->crit_sect); } break; -- cgit v1.2.3-70-g09d2 From c38f82cf1b7dc8aad2bce8e30113fd6aa3159dab Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Drop some unused symbols from acpiphp.h and redefine SLOT_ENABLED (which is the only slot flag now) as 1. [rjw: Redefinition of SLOT_ENABLED, changelog] Signed-off-by: Mika Westerberg Signed-off-by: Kirill A. Shutemov Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index ca2c91df3d1..f4e02892466 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -154,16 +154,12 @@ struct acpiphp_attention_info struct module *owner; }; -/* PCI bus bridge HID */ -#define ACPI_PCI_HOST_HID "PNP0A03" - /* ACPI _STA method value (ignore bit 4; battery present) */ #define ACPI_STA_ALL (0x0000000f) /* slot flags */ -#define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (0x00000004) +#define SLOT_ENABLED (0x00000001) /* function flags */ -- cgit v1.2.3-70-g09d2 From 1ad3790ac7cfac699993a3f2e189a69a82f8fe4d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() There is no need for a temporary variable and all the tricks with ternary operators in acpiphp_get_(latch)|(adapter)_status(). Change those functions to be a bit more straightforward. [rjw: Changelog] Signed-off-by: Kirill A. Shutemov Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e2e5e308881..d8748a4a18a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1107,11 +1107,7 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) */ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1; + return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); } @@ -1121,9 +1117,5 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) */ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta == 0) ? 0 : 1; + return !!get_slot_status(slot); } -- cgit v1.2.3-70-g09d2 From a1d0abcea845730c4ff2f47897e28c2f11c79d4f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Notice that functions enable_device() and disable_device() cannot fail and their return values are ignored in the majority of places, so redefine them as void and use the opportunity to change their names to enable_slot() and disable_slot(), respectively, which much better reflects what they do. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d8748a4a18a..18c9e54990e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -532,13 +532,13 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) } /** - * enable_device - enable, configure a slot + * enable_slot - enable, configure a slot * @slot: slot to be enabled * * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. */ -static int __ref enable_device(struct acpiphp_slot *slot) +static void __ref enable_slot(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bus; @@ -556,6 +556,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) list_for_each_entry(dev, &bus->devices, bus_list) { if (PCI_SLOT(dev->devfn) != slot->device) continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { max = pci_scan_bridge(bus, dev, max, pass); @@ -594,8 +595,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) continue; } } - - return 0; } /* return first device in slot, acquiring a reference on it */ @@ -617,16 +616,16 @@ static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) } /** - * disable_device - disable a slot + * disable_slot - disable a slot * @slot: ACPI PHP slot */ -static int disable_device(struct acpiphp_slot *slot) +static void disable_slot(struct acpiphp_slot *slot) { struct acpiphp_func *func; struct pci_dev *pdev; /* - * enable_device() enumerates all functions in this device via + * enable_slot() enumerates all functions in this device via * pci_scan_slot(), whether they have associated ACPI hotplug * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. @@ -640,8 +639,6 @@ static int disable_device(struct acpiphp_slot *slot) acpiphp_bus_trim(func_to_handle(func)); slot->flags &= (~SLOT_ENABLED); - - return 0; } @@ -751,9 +748,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) trim_stale_devices(dev); /* configure all functions */ - enable_device(slot); + enable_slot(slot); } else { - disable_device(slot); + disable_slot(slot); } mutex_unlock(&slot->crit_sect); } @@ -860,7 +857,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) struct acpiphp_slot *slot = func->slot; mutex_lock(&slot->crit_sect); - enable_device(slot); + enable_slot(slot); mutex_unlock(&slot->crit_sect); } break; @@ -1047,16 +1044,13 @@ void acpiphp_remove_slots(struct pci_bus *bus) */ int acpiphp_enable_slot(struct acpiphp_slot *slot) { - int retval = 0; - mutex_lock(&slot->crit_sect); - /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) - retval = enable_device(slot); + enable_slot(slot); mutex_unlock(&slot->crit_sect); - return retval; + return 0; } /** @@ -1071,9 +1065,7 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) mutex_lock(&slot->crit_sect); /* unconfigure all functions */ - retval = disable_device(slot); - if (retval) - goto err_exit; + disable_slot(slot); list_for_each_entry(func, &slot->funcs, sibling) if (func->flags & FUNC_HAS_EJ0) { @@ -1085,7 +1077,6 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) break; } - err_exit: mutex_unlock(&slot->crit_sect); return retval; } -- cgit v1.2.3-70-g09d2 From ff181e5a4f6b536e5f3f1601cd5c54e792cd9abc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Clean up bridge_mutex usage Do not acquire bridge_mutex around the addition of a slot to its bridge's list of slots and arount the addition of a function to its slot's list of functions, because that doesn't help anything right now (those lists are walked without any locking anyway). However, acquire bridge_mutex around the list walk in acpiphp_remove_slots() and use list_for_each_entry() there, because we terminate the walk as soon as we find the first matching entry. This prevents that list walk from colliding with bridge addition and removal. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/pci/hotplug/acpiphp_glue.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 18c9e54990e..e4b7f2bc94d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -323,9 +323,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, INIT_LIST_HEAD(&slot->funcs); mutex_init(&slot->crit_sect); - mutex_lock(&bridge_mutex); list_add_tail(&slot->node, &bridge->slots); - mutex_unlock(&bridge_mutex); /* Register slots for ejectable funtions only. */ if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { @@ -355,9 +353,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot_found: newfunc->slot = slot; - mutex_lock(&bridge_mutex); list_add_tail(&newfunc->sibling, &slot->funcs); - mutex_unlock(&bridge_mutex); if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), &val, 60*1000)) @@ -1025,17 +1021,21 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) /* Destroy hotplug slots associated with the PCI bus */ void acpiphp_remove_slots(struct pci_bus *bus) { - struct acpiphp_bridge *bridge, *tmp; + struct acpiphp_bridge *bridge; if (acpiphp_disabled) return; - list_for_each_entry_safe(bridge, tmp, &bridge_list, list) + mutex_lock(&bridge_mutex); + list_for_each_entry(bridge, &bridge_list, list) if (bridge->pci_bus == bus) { + mutex_unlock(&bridge_mutex); cleanup_bridge(bridge); put_bridge(bridge); - break; + return; } + + mutex_unlock(&bridge_mutex); } /** -- cgit v1.2.3-70-g09d2 From 2d8b1d566a5f4874f4d92361f5cdbb50baa396f8 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 20:09:59 +0300 Subject: ACPI / hotplug / PCI: Get rid of check_sub_bridges() Now that acpiphp_check_bridge() always enumerates devices behind the bridge, there is no need to do that for each sub-bridge anymore like it is done in the current ACPI-based PCI hotplug (ACPIPHP) code. Given this we don't need check_sub_bridges() anymore, so drop that function completely. This also simplifies the ACPIPHP code a bit. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e4b7f2bc94d..05e463db11d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -788,25 +788,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) * ACPI event handlers */ -static acpi_status -check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - bridge = acpiphp_handle_to_bridge(handle); - if (bridge) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - dbg("%s: re-enumerating slots under %s\n", - __func__, objname); - acpiphp_check_bridge(bridge); - put_bridge(bridge); - } - return AE_OK ; -} - void acpiphp_check_host_bridge(acpi_handle handle) { struct acpiphp_bridge *bridge; @@ -816,9 +797,6 @@ void acpiphp_check_host_bridge(acpi_handle handle) acpiphp_check_bridge(bridge); put_bridge(bridge); } - - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); } static void hotplug_event(acpi_handle handle, u32 type, void *data) @@ -846,9 +824,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) dbg("%s: re-enumerating slots under %s\n", __func__, objname); if (bridge) { acpiphp_check_bridge(bridge); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, - NULL, NULL, NULL); } else { struct acpiphp_slot *slot = func->slot; -- cgit v1.2.3-70-g09d2 From d010e5769a5ab2ae8d2bcb36e77b98172c24d80c Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 30 Jul 2013 10:32:30 +0800 Subject: PCI / ACPI: Use dev_dbg() instead of dev_info() in acpi_pci_set_power_state() acpi_pci_set_power_state() uses dev_info() to print diagnostic messages regarding ACPI power state changes of devices, but that results in too much not really interesting output into the kernel log in some cases. For this reason, change it to use dev_dbg() instead and prevent kernel log from being spammed. [rjw: Changelog] References: https://bugzilla.kernel.org/show_bug.cgi?id=60636 Suggested-by: Alan Stern Signed-off-by: Lan Tianyu Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c78cc432eda..fb3522957f0 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -210,7 +210,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) } if (!error) - dev_info(&dev->dev, "power state changed by ACPI to %s\n", + dev_dbg(&dev->dev, "power state changed by ACPI to %s\n", acpi_power_state_string(state_conv[state])); return error; -- cgit v1.2.3-70-g09d2 From 1aaac07112f04068d7e2fc47bb435cfd4f9d5468 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 17 Aug 2013 22:16:33 +0200 Subject: ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge() After commit bbd34fc (ACPI / hotplug / PCI: Register all devices under the given bridge) register_slot() is called for all PCI devices under a given bridge that have corresponding objects in the ACPI namespace, but it calls acpiphp_register_hotplug_slot() only for devices satisfying specific criteria. Still, cleanup_bridge() calls acpiphp_unregister_hotplug_slot() for all objects created by register_slot(), although it should only call it for the ones that acpiphp_register_hotplug_slot() has been called for (successfully). This causes a NULL pointer to be dereferenced by the acpiphp_unregister_hotplug_slot() executed by cleanup_bridge() if the object it is called for has not been passed to acpiphp_register_hotplug_slot(). To fix this problem, check if the 'slot' field of the object passed to acpiphp_unregister_hotplug_slot() in cleanup_bridge() is not NULL, which only is the case if acpiphp_register_hotplug_slot() has been executed for that object. In addition to that, make register_slot() reset the 'slot' field to NULL if acpiphp_register_hotplug_slot() has failed for the given object to prevent stale pointers from being used by acpiphp_unregister_hotplug_slot(). Reported-and-tested-by: Yinghai Lu Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 05e463db11d..8054ddcdaed 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, retval = acpiphp_register_hotplug_slot(slot, sun); if (retval) { + slot->slot = NULL; bridge->nr_slots--; if (retval == -EBUSY) warn("Slot %llu already registered by another " @@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) err("failed to remove notify handler\n"); } } - acpiphp_unregister_hotplug_slot(slot); + if (slot->slot) + acpiphp_unregister_hotplug_slot(slot); } mutex_lock(&bridge_mutex); -- cgit v1.2.3-70-g09d2