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 /drivers/pci/hotplug/acpiphp_glue.c | |
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>
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 119 |
1 files changed, 49 insertions, 70 deletions
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 | ||