aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/acpiphp_glue.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-20 19:10:18 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-20 19:10:18 -0500
commitedf5bf34d40804fbef32f240a79b74ffc69a658b (patch)
treecc254893c5eb42fd4bc35b2098be614006f68d1a /drivers/pci/hotplug/acpiphp_glue.c
parent3b52b21fa1f44c8956e21dfba645eda959111b5e (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.c119
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);
60static DEFINE_MUTEX(bridge_mutex); 60static DEFINE_MUTEX(bridge_mutex);
61 61
62static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); 62static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type);
63static void acpiphp_post_dock_fixup(struct acpi_device *adev);
63static void acpiphp_sanitize_bus(struct pci_bus *bus); 64static void acpiphp_sanitize_bus(struct pci_bus *bus);
64static void acpiphp_set_hpp_values(struct pci_bus *bus); 65static void acpiphp_set_hpp_values(struct pci_bus *bus);
65static void hotplug_event(u32 type, struct acpiphp_context *context); 66static 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
135static 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
151static void acpiphp_let_context_go(struct acpiphp_context *context)
152{
153 put_bridge(context->func.parent);
154}
155
133static void free_bridge(struct kref *kref) 156static 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 */
174static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) 196static 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
199static 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
210static 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 */
216static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) 227static 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
244static void acpiphp_dock_init(void *data)
245{
246 struct acpiphp_context *context = data;
247
248 get_bridge(context->func.parent);
249}
250
251static 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