diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-21 01:10:18 +0100 | 
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-21 01:10:18 +0100 | 
| 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);  static DEFINE_MUTEX(bridge_mutex);  static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); +static void acpiphp_post_dock_fixup(struct acpi_device *adev);  static void acpiphp_sanitize_bus(struct pci_bus *bus);  static void acpiphp_set_hpp_values(struct pci_bus *bus);  static void hotplug_event(u32 type, struct acpiphp_context *context); @@ -80,7 +81,8 @@ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev)  		return NULL;  	context->refcount = 1; -	acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event, NULL); +	acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event, +			    acpiphp_post_dock_fixup);  	return context;  } @@ -130,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)  	kref_put(&bridge->ref, free_bridge);  } +static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev) +{ +	struct acpiphp_context *context; + +	acpi_lock_hp_context(); +	context = acpiphp_get_context(adev); +	if (!context || context->func.parent->is_going_away) { +		acpi_unlock_hp_context(); +		return NULL; +	} +	get_bridge(context->func.parent); +	acpiphp_put_context(context); +	acpi_unlock_hp_context(); +	return context; +} + +static void acpiphp_let_context_go(struct acpiphp_context *context) +{ +	put_bridge(context->func.parent); +} +  static void free_bridge(struct kref *kref)  {  	struct acpiphp_context *context; @@ -164,28 +187,29 @@ static void free_bridge(struct kref *kref)  	acpi_unlock_hp_context();  } -/* - * the _DCK method can do funny things... and sometimes not - * hah-hah funny. +/** + * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices. + * @adev: ACPI device object corresponding to a PCI device.   * - * TBD - figure out a way to only call fixups for - * systems that require them. + * TBD - figure out a way to only call fixups for systems that require them.   */ -static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) +static void acpiphp_post_dock_fixup(struct acpi_device *adev)  { -	struct acpiphp_context *context = data; -	struct pci_bus *bus = context->func.slot->bus; +	struct acpiphp_context *context = acpiphp_grab_context(adev); +	struct pci_bus *bus;  	u32 buses; -	if (!bus->self) +	if (!context)  		return; +	bus = context->func.slot->bus; +	if (!bus->self) +		goto out; +  	/* fixup bad _DCK function that rewrites  	 * secondary bridge on slot  	 */ -	pci_read_config_dword(bus->self, -			PCI_PRIMARY_BUS, -			&buses); +	pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses);  	if (((buses >> 8) & 0xff) != bus->busn_res.start) {  		buses = (buses & 0xff000000) @@ -194,24 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)  			| ((unsigned int)(bus->busn_res.end) << 16);  		pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);  	} -} -static void dock_event(acpi_handle handle, u32 type, void *data) -{ -	struct acpi_device *adev; - -	adev = acpi_bus_get_acpi_device(handle); -	if (adev) { -		acpiphp_hotplug_event(adev, type); -		acpi_bus_put_acpi_device(adev); -	} + out: +	acpiphp_let_context_go(context);  } -static const struct acpi_dock_ops acpiphp_dock_ops = { -	.fixup = post_dock_fixups, -	.handler = dock_event, -}; -  /* Check whether the PCI device is managed by native PCIe hotplug driver */  static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)  { @@ -241,20 +252,6 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)  	return true;  } -static void acpiphp_dock_init(void *data) -{ -	struct acpiphp_context *context = data; - -	get_bridge(context->func.parent); -} - -static void acpiphp_dock_release(void *data) -{ -	struct acpiphp_context *context = data; - -	put_bridge(context->func.parent); -} -  /**   * acpiphp_add_context - Add ACPIPHP context to an ACPI device object.   * @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,  	newfunc = &context->func;  	newfunc->function = function;  	newfunc->parent = bridge; +	acpi_unlock_hp_context(); -	if (acpi_has_method(handle, "_EJ0")) +	/* +	 * If this is a dock device, its _EJ0 should be executed by the dock +	 * notify handler after calling _DCK. +	 */ +	if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0"))  		newfunc->flags = FUNC_HAS_EJ0;  	if (acpi_has_method(handle, "_STA"))  		newfunc->flags |= FUNC_HAS_STA; -	acpi_unlock_hp_context(); -  	/* search for objects that share the same slot */  	list_for_each_entry(slot, &bridge->slots, node)  		if (slot->device == device) @@ -369,18 +369,6 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,  				       &val, 60*1000))  		slot->flags |= SLOT_ENABLED; -	if (is_dock_device(adev)) { -		/* we don't want to call this device's _EJ0 -		 * because we want the dock notify handler -		 * to call it after it calls _DCK -		 */ -		newfunc->flags &= ~FUNC_HAS_EJ0; -		if (register_hotplug_dock_device(handle, -			&acpiphp_dock_ops, context, -			acpiphp_dock_init, acpiphp_dock_release)) -			pr_debug("failed to register dock device\n"); -	} -  	return AE_OK;  } @@ -411,11 +399,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)  		list_for_each_entry(func, &slot->funcs, sibling) {  			struct acpi_device *adev = func_to_acpi_device(func); -			if (is_dock_device(adev)) -				unregister_hotplug_dock_device(adev->handle); -  			acpi_lock_hp_context();  			adev->hp->event = NULL; +			adev->hp->fixup = NULL;  			acpi_unlock_hp_context();  		}  		slot->flags |= SLOT_IS_GOING_AWAY; @@ -851,19 +837,12 @@ static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type)  {  	struct acpiphp_context *context; -	acpi_lock_hp_context(); -	context = acpiphp_get_context(adev); -	if (!context || context->func.parent->is_going_away) { -		acpi_unlock_hp_context(); +	context = acpiphp_grab_context(adev); +	if (!context)  		return -ENODATA; -	} -	get_bridge(context->func.parent); -	acpiphp_put_context(context); -	acpi_unlock_hp_context();  	hotplug_event(type, context); - -	put_bridge(context->func.parent); +	acpiphp_let_context_go(context);  	return 0;  } | 
