diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-20 19:10:18 -0500 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-20 19:10:18 -0500 |
| commit | edf5bf34d40804fbef32f240a79b74ffc69a658b (patch) | |
| tree | cc254893c5eb42fd4bc35b2098be614006f68d1a | |
| parent | 3b52b21fa1f44c8956e21dfba645eda959111b5e (diff) | |
ACPI / dock: Use callback pointers from devices' ACPI hotplug contexts
Instead of requiring a set of special dock operations to be registered
via register_hotplug_dock_device() for each ACPI dock device, it is
much more straightforward to use callback pointers from the devices'
hotplug contexts if available.
For this reason, modify dock_hotplug_event() to use callback pointers
from the hotplug contexts of ACPI devices and fall back to using the
special dock operarions only if those callbacks are missing. Also
make the ACPI-based PCI hotplug (ACPIPHP) subsystem set the .fixup
callback pointer in the hotplug contexts of devices handled by it to
a new function, acpiphp_post_dock_fixup(), so that the dock station
driver can use the callbacks from those contexts instead of special
dock operations registered via register_hotplug_dock_device().
Along with the above changes drop the ACPIPHP's dock operations that
are not necessary any more.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
| -rw-r--r-- | drivers/acpi/dock.c | 29 | ||||
| -rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 119 |
2 files changed, 78 insertions, 70 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 8c3967cb4830..78c4ee7a422e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
| @@ -185,9 +185,38 @@ static void dock_release_hotplug(struct dock_dependent_device *dd) | |||
| 185 | static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, | 185 | static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, |
| 186 | enum dock_callback_type cb_type) | 186 | enum dock_callback_type cb_type) |
| 187 | { | 187 | { |
| 188 | struct acpi_device *adev = dd->adev; | ||
| 188 | acpi_notify_handler cb = NULL; | 189 | acpi_notify_handler cb = NULL; |
| 189 | bool run = false; | 190 | bool run = false; |
| 190 | 191 | ||
| 192 | acpi_lock_hp_context(); | ||
| 193 | |||
| 194 | if (!adev->hp) | ||
| 195 | goto no_context; | ||
| 196 | |||
| 197 | if (cb_type == DOCK_CALL_FIXUP) { | ||
| 198 | void (*fixup)(struct acpi_device *); | ||
| 199 | |||
| 200 | fixup = adev->hp->fixup; | ||
| 201 | if (fixup) { | ||
| 202 | acpi_unlock_hp_context(); | ||
| 203 | fixup(adev); | ||
| 204 | return; | ||
| 205 | } | ||
| 206 | } else { | ||
| 207 | int (*notify)(struct acpi_device *, u32); | ||
| 208 | |||
| 209 | notify = adev->hp->event; | ||
| 210 | if (notify) { | ||
| 211 | acpi_unlock_hp_context(); | ||
| 212 | notify(adev, event); | ||
| 213 | return; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | no_context: | ||
| 218 | acpi_unlock_hp_context(); | ||
| 219 | |||
| 191 | mutex_lock(&hotplug_lock); | 220 | mutex_lock(&hotplug_lock); |
| 192 | 221 | ||
| 193 | if (dd->hp_context) { | 222 | if (dd->hp_context) { |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cd886725c42e..15865aeebbb5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
| @@ -60,6 +60,7 @@ static LIST_HEAD(bridge_list); | |||
| 60 | static DEFINE_MUTEX(bridge_mutex); | 60 | static DEFINE_MUTEX(bridge_mutex); |
| 61 | 61 | ||
| 62 | static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); | 62 | static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); |
| 63 | static void acpiphp_post_dock_fixup(struct acpi_device *adev); | ||
| 63 | static void acpiphp_sanitize_bus(struct pci_bus *bus); | 64 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
| 64 | static void acpiphp_set_hpp_values(struct pci_bus *bus); | 65 | static void acpiphp_set_hpp_values(struct pci_bus *bus); |
| 65 | static void hotplug_event(u32 type, struct acpiphp_context *context); | 66 | static void hotplug_event(u32 type, struct acpiphp_context *context); |
| @@ -80,7 +81,8 @@ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) | |||
| 80 | return NULL; | 81 | return NULL; |
| 81 | 82 | ||
| 82 | context->refcount = 1; | 83 | context->refcount = 1; |
| 83 | acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event, NULL); | 84 | acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event, |
| 85 | acpiphp_post_dock_fixup); | ||
| 84 | return context; | 86 | return context; |
| 85 | } | 87 | } |
| 86 | 88 | ||
| @@ -130,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge) | |||
| 130 | kref_put(&bridge->ref, free_bridge); | 132 | kref_put(&bridge->ref, free_bridge); |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 135 | static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev) | ||
| 136 | { | ||
| 137 | struct acpiphp_context *context; | ||
| 138 | |||
| 139 | acpi_lock_hp_context(); | ||
| 140 | context = acpiphp_get_context(adev); | ||
| 141 | if (!context || context->func.parent->is_going_away) { | ||
| 142 | acpi_unlock_hp_context(); | ||
| 143 | return NULL; | ||
| 144 | } | ||
| 145 | get_bridge(context->func.parent); | ||
| 146 | acpiphp_put_context(context); | ||
| 147 | acpi_unlock_hp_context(); | ||
| 148 | return context; | ||
| 149 | } | ||
| 150 | |||
| 151 | static void acpiphp_let_context_go(struct acpiphp_context *context) | ||
| 152 | { | ||
| 153 | put_bridge(context->func.parent); | ||
| 154 | } | ||
| 155 | |||
| 133 | static void free_bridge(struct kref *kref) | 156 | static void free_bridge(struct kref *kref) |
| 134 | { | 157 | { |
| 135 | struct acpiphp_context *context; | 158 | struct acpiphp_context *context; |
| @@ -164,28 +187,29 @@ static void free_bridge(struct kref *kref) | |||
| 164 | acpi_unlock_hp_context(); | 187 | acpi_unlock_hp_context(); |
| 165 | } | 188 | } |
| 166 | 189 | ||
| 167 | /* | 190 | /** |
| 168 | * the _DCK method can do funny things... and sometimes not | 191 | * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices. |
| 169 | * hah-hah funny. | 192 | * @adev: ACPI device object corresponding to a PCI device. |
| 170 | * | 193 | * |
| 171 | * TBD - figure out a way to only call fixups for | 194 | * TBD - figure out a way to only call fixups for systems that require them. |
| 172 | * systems that require them. | ||
| 173 | */ | 195 | */ |
| 174 | static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | 196 | static void acpiphp_post_dock_fixup(struct acpi_device *adev) |
| 175 | { | 197 | { |
| 176 | struct acpiphp_context *context = data; | 198 | struct acpiphp_context *context = acpiphp_grab_context(adev); |
| 177 | struct pci_bus *bus = context->func.slot->bus; | 199 | struct pci_bus *bus; |
| 178 | u32 buses; | 200 | u32 buses; |
| 179 | 201 | ||
| 180 | if (!bus->self) | 202 | if (!context) |
| 181 | return; | 203 | return; |
| 182 | 204 | ||
| 205 | bus = context->func.slot->bus; | ||
| 206 | if (!bus->self) | ||
| 207 | goto out; | ||
| 208 | |||
| 183 | /* fixup bad _DCK function that rewrites | 209 | /* fixup bad _DCK function that rewrites |
| 184 | * secondary bridge on slot | 210 | * secondary bridge on slot |
| 185 | */ | 211 | */ |
| 186 | pci_read_config_dword(bus->self, | 212 | pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses); |
| 187 | PCI_PRIMARY_BUS, | ||
| 188 | &buses); | ||
| 189 | 213 | ||
| 190 | if (((buses >> 8) & 0xff) != bus->busn_res.start) { | 214 | if (((buses >> 8) & 0xff) != bus->busn_res.start) { |
| 191 | buses = (buses & 0xff000000) | 215 | buses = (buses & 0xff000000) |
| @@ -194,24 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | |||
| 194 | | ((unsigned int)(bus->busn_res.end) << 16); | 218 | | ((unsigned int)(bus->busn_res.end) << 16); |
| 195 | pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); | 219 | pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); |
| 196 | } | 220 | } |
| 197 | } | ||
| 198 | 221 | ||
| 199 | static void dock_event(acpi_handle handle, u32 type, void *data) | 222 | out: |
| 200 | { | 223 | acpiphp_let_context_go(context); |
| 201 | struct acpi_device *adev; | ||
| 202 | |||
| 203 | adev = acpi_bus_get_acpi_device(handle); | ||
| 204 | if (adev) { | ||
| 205 | acpiphp_hotplug_event(adev, type); | ||
| 206 | acpi_bus_put_acpi_device(adev); | ||
| 207 | } | ||
| 208 | } | 224 | } |
| 209 | 225 | ||
| 210 | static const struct acpi_dock_ops acpiphp_dock_ops = { | ||
| 211 | .fixup = post_dock_fixups, | ||
| 212 | .handler = dock_event, | ||
| 213 | }; | ||
| 214 | |||
| 215 | /* Check whether the PCI device is managed by native PCIe hotplug driver */ | 226 | /* Check whether the PCI device is managed by native PCIe hotplug driver */ |
| 216 | static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) | 227 | static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) |
| 217 | { | 228 | { |
| @@ -241,20 +252,6 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) | |||
| 241 | return true; | 252 | return true; |
| 242 | } | 253 | } |
| 243 | 254 | ||
| 244 | static void acpiphp_dock_init(void *data) | ||
| 245 | { | ||
| 246 | struct acpiphp_context *context = data; | ||
| 247 | |||
| 248 | get_bridge(context->func.parent); | ||
| 249 | } | ||
| 250 | |||
| 251 | static void acpiphp_dock_release(void *data) | ||
| 252 | { | ||
| 253 | struct acpiphp_context *context = data; | ||
| 254 | |||
| 255 | put_bridge(context->func.parent); | ||
| 256 | } | ||
| 257 | |||
| 258 | /** | 255 | /** |
| 259 | * acpiphp_add_context - Add ACPIPHP context to an ACPI device object. | 256 | * acpiphp_add_context - Add ACPIPHP context to an ACPI device object. |
| 260 | * @handle: ACPI handle of the object to add a context to. | 257 | * @handle: ACPI handle of the object to add a context to. |
| @@ -300,15 +297,18 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, | |||
| 300 | newfunc = &context->func; | 297 | newfunc = &context->func; |
| 301 | newfunc->function = function; | 298 | newfunc->function = function; |
| 302 | newfunc->parent = bridge; | 299 | newfunc->parent = bridge; |
| 300 | acpi_unlock_hp_context(); | ||
| 303 | 301 | ||
| 304 | if (acpi_has_method(handle, "_EJ0")) | 302 | /* |
| 303 | * If this is a dock device, its _EJ0 should be executed by the dock | ||
| 304 | * notify handler after calling _DCK. | ||
| 305 | */ | ||
| 306 | if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0")) | ||
| 305 | newfunc->flags = FUNC_HAS_EJ0; | 307 | newfunc->flags = FUNC_HAS_EJ0; |
| 306 | 308 | ||
| 307 | if (acpi_has_method(handle, "_STA")) | 309 | if (acpi_has_method(handle, "_STA")) |
| 308 | newfunc->flags |= FUNC_HAS_STA; | 310 | newfunc->flags |= FUNC_HAS_STA; |
| 309 | 311 | ||
| 310 | acpi_unlock_hp_context(); | ||
| 311 | |||
| 312 | /* search for objects that share the same slot */ | 312 | /* search for objects that share the same slot */ |
| 313 | list_for_each_entry(slot, &bridge->slots, node) | 313 | list_for_each_entry(slot, &bridge->slots, node) |
| 314 | if (slot->device == device) | 314 | if (slot->device == device) |
| @@ -369,18 +369,6 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, | |||
| 369 | &val, 60*1000)) | 369 | &val, 60*1000)) |
| 370 | slot->flags |= SLOT_ENABLED; | 370 | slot->flags |= SLOT_ENABLED; |
| 371 | 371 | ||
| 372 | if (is_dock_device(adev)) { | ||
| 373 | /* we don't want to call this device's _EJ0 | ||
| 374 | * because we want the dock notify handler | ||
| 375 | * to call it after it calls _DCK | ||
| 376 | */ | ||
| 377 | newfunc->flags &= ~FUNC_HAS_EJ0; | ||
| 378 | if (register_hotplug_dock_device(handle, | ||
| 379 | &acpiphp_dock_ops, context, | ||
| 380 | acpiphp_dock_init, acpiphp_dock_release)) | ||
| 381 | pr_debug("failed to register dock device\n"); | ||
| 382 | } | ||
| 383 | |||
| 384 | return AE_OK; | 372 | return AE_OK; |
| 385 | } | 373 | } |
| 386 | 374 | ||
| @@ -411,11 +399,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
| 411 | list_for_each_entry(func, &slot->funcs, sibling) { | 399 | list_for_each_entry(func, &slot->funcs, sibling) { |
| 412 | struct acpi_device *adev = func_to_acpi_device(func); | 400 | struct acpi_device *adev = func_to_acpi_device(func); |
| 413 | 401 | ||
| 414 | if (is_dock_device(adev)) | ||
| 415 | unregister_hotplug_dock_device(adev->handle); | ||
| 416 | |||
| 417 | acpi_lock_hp_context(); | 402 | acpi_lock_hp_context(); |
| 418 | adev->hp->event = NULL; | 403 | adev->hp->event = NULL; |
| 404 | adev->hp->fixup = NULL; | ||
| 419 | acpi_unlock_hp_context(); | 405 | acpi_unlock_hp_context(); |
| 420 | } | 406 | } |
| 421 | slot->flags |= SLOT_IS_GOING_AWAY; | 407 | slot->flags |= SLOT_IS_GOING_AWAY; |
| @@ -851,19 +837,12 @@ static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) | |||
| 851 | { | 837 | { |
| 852 | struct acpiphp_context *context; | 838 | struct acpiphp_context *context; |
| 853 | 839 | ||
| 854 | acpi_lock_hp_context(); | 840 | context = acpiphp_grab_context(adev); |
| 855 | context = acpiphp_get_context(adev); | 841 | if (!context) |
| 856 | if (!context || context->func.parent->is_going_away) { | ||
| 857 | acpi_unlock_hp_context(); | ||
| 858 | return -ENODATA; | 842 | return -ENODATA; |
| 859 | } | ||
| 860 | get_bridge(context->func.parent); | ||
| 861 | acpiphp_put_context(context); | ||
| 862 | acpi_unlock_hp_context(); | ||
| 863 | 843 | ||
| 864 | hotplug_event(type, context); | 844 | hotplug_event(type, context); |
| 865 | 845 | acpiphp_let_context_go(context); | |
| 866 | put_bridge(context->func.parent); | ||
| 867 | return 0; | 846 | return 0; |
| 868 | } | 847 | } |
| 869 | 848 | ||
