2014-02-19 01:18:40

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 0/9] ACPI / dock / PCI / SATA: Simplify ACPI dock handling

Hi All,

This series is on top of the current linux-next and it removes one of the
ugliest, in my opinion, things related to ACPI dock support, which is the
registration and unregistration of dock operations that makes it necessary
to register dock devices *twice* with the dock driver.

[1/9] After recent changes ACPIPHP doesn't need to clear the event
callback (introduced in linux-next) for dock stations.
[2/9] Add .fixup() callback to struct acpi_hotplug_context for PCI devices
located in dock stations.
[3/9] Store ACPI device object pointers instead of ACPI handles in the internal
data structures used by the dock driver.
[4/9] Make the dock driver use callback pointers from the hotplug contexts of
ACPI device objects and modify ACPIPHP to use that mechanism (instead of
registering a special set of dock operations for each device).
[5/9] Add .uevent() callback to struct acpi_hotplug_context for SATA devices
located in dock stations.
[6/9] Make SATA ACPI support code use hotplug contexts of ACPI device objects
(instead of dock operations).
[7/9] Drop struct acpi_dock_ops and all code related to it (no more users).
[8/9] Drop remove_dock_dependent_devices() (this is a cleanup that doesn't
really depend on the rest of the series).
[9/9] Update the copyright notice in dock.c.

Thanks!

--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.


2014-02-19 01:18:35

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 8/9] ACPI / dock: Drop remove_dock_dependent_devices()

From: Rafael J. Wysocki <[email protected]>

Since remove_dock_dependent_devices() is only called from acpi_dock_add()
and it only is called if the add_dock_dependent_device() adding the
dock station to its own list of dependent devices has failed, it is not
really necessary, because the dock station's list of dependent devices
is guaranteed to be empty at that point. Drop it, then.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/dock.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)

Index: linux-pm/drivers/acpi/dock.c
===================================================================
--- linux-pm.orig/drivers/acpi/dock.c
+++ linux-pm/drivers/acpi/dock.c
@@ -114,16 +114,6 @@ static int add_dock_dependent_device(str
return 0;
}

-static void remove_dock_dependent_devices(struct dock_station *ds)
-{
- struct dock_dependent_device *dd, *aux;
-
- list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
- list_del(&dd->list);
- kfree(dd);
- }
-}
-
static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
enum dock_callback_type cb_type)
{
@@ -674,8 +664,8 @@ void acpi_dock_add(struct acpi_device *a
return;

err_rmgroup:
- remove_dock_dependent_devices(dock_station);
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
+
err_unregister:
platform_device_unregister(dd);
acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);

2014-02-19 01:19:03

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 2/9] ACPI / hotplug: Add .fixup() callback to struct acpi_hotplug_context

From: Rafael J. Wysocki <[email protected]>

In order for the ACPI dock station code to be able to use the
callbacks pointed to by the ACPI device objects' hotplug contexts
add a .fixup() callback pointer to struct acpi_hotplug_context.
That callback will be useful to handle PCI devices located in
dock stations.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/pci/hotplug/acpiphp_glue.c | 2 +-
include/acpi/acpi_bus.h | 5 ++++-
2 files changed, 5 insertions(+), 2 deletions(-)

Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -146,6 +146,7 @@ struct acpi_scan_handler {
struct acpi_hotplug_context {
struct acpi_device *self;
int (*event)(struct acpi_device *, u32);
+ void (*fixup)(struct acpi_device *);
};

/*
@@ -368,10 +369,12 @@ static inline void acpi_set_device_statu

static inline void acpi_set_hp_context(struct acpi_device *adev,
struct acpi_hotplug_context *hp,
- int (*event)(struct acpi_device *, u32))
+ int (*event)(struct acpi_device *, u32),
+ void (*fixup)(struct acpi_device *))
{
hp->self = adev;
hp->event = event;
+ hp->fixup = fixup;
adev->hp = hp;
}

Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -80,7 +80,7 @@ static struct acpiphp_context *acpiphp_i
return NULL;

context->refcount = 1;
- acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event);
+ acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event, NULL);
return context;
}

2014-02-19 01:19:00

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 1/9] ACPI / hotplug / PCI: Do not clear event callback pointer for docks

From: Rafael J. Wysocki <[email protected]>

After recent changes adding dock station handling to the ACPI hotplug
core, it is not necessary to clear the .event() pointer in the
ACPIPHP device hotplug context for dock stations any more, so don't
do that.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/pci/hotplug/acpiphp_glue.c | 7 -------
1 file changed, 7 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -307,13 +307,6 @@ static acpi_status acpiphp_add_context(a
if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_STA;

- /*
- * Dock stations' notify handler should be used for dock devices instead
- * of the common one, so clear hp.event in their contexts.
- */
- if (acpi_has_method(handle, "_DCK"))
- context->hp.event = NULL;
-
acpi_unlock_hp_context();

/* search for objects that share the same slot */

2014-02-19 01:19:46

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 3/9] ACPI / dock: Use ACPI device object pointers instead of ACPI handles

From: Rafael J. Wysocki <[email protected]>

Rework the ACPI dock station driver to store ACPI device object
pointers instead of ACPI handles in its internal data structures.

The purpose is moslty to make subsequent simplifications possible,
but also this allows the overall code size to be reduced slightly.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/dock.c | 104 ++++++++++++++-----------------------
drivers/pci/hotplug/acpiphp_glue.c | 6 +-
include/acpi/acpi_drivers.h | 4 -
3 files changed, 47 insertions(+), 67 deletions(-)

Index: linux-pm/drivers/acpi/dock.c
===================================================================
--- linux-pm.orig/drivers/acpi/dock.c
+++ linux-pm/drivers/acpi/dock.c
@@ -72,7 +72,7 @@ static DEFINE_MUTEX(hotplug_lock);

struct dock_dependent_device {
struct list_head list;
- acpi_handle handle;
+ struct acpi_device *adev;
const struct acpi_dock_ops *hp_ops;
void *hp_context;
unsigned int hp_refcount;
@@ -98,12 +98,13 @@ enum dock_callback_type {
*****************************************************************************/
/**
* add_dock_dependent_device - associate a device with the dock station
- * @ds: The dock station
- * @handle: handle of the dependent device
+ * @ds: Dock station.
+ * @adev: Dependent ACPI device object.
*
* Add the dependent device to the dock's dependent device list.
*/
-static int add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+static int add_dock_dependent_device(struct dock_station *ds,
+ struct acpi_device *adev)
{
struct dock_dependent_device *dd;

@@ -111,7 +112,7 @@ static int add_dock_dependent_device(str
if (!dd)
return -ENOMEM;

- dd->handle = handle;
+ dd->adev = adev;
INIT_LIST_HEAD(&dd->list);
list_add_tail(&dd->list, &ds->dependent_devices);

@@ -212,7 +213,7 @@ static void dock_hotplug_event(struct do
return;

if (cb)
- cb(dd->handle, event, dd->hp_context);
+ cb(dd->adev->handle, event, dd->hp_context);

dock_release_hotplug(dd);
}
@@ -231,18 +232,18 @@ static struct dock_station *find_dock_st
/**
* find_dock_dependent_device - get a device dependent on this dock
* @ds: the dock station
- * @handle: the acpi_handle of the device we want
+ * @adev: ACPI device object to find.
*
* iterate over the dependent device list for this dock. If the
* dependent device matches the handle, return.
*/
static struct dock_dependent_device *
-find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
{
struct dock_dependent_device *dd;

list_for_each_entry(dd, &ds->dependent_devices, list)
- if (handle == dd->handle)
+ if (adev == dd->adev)
return dd;

return NULL;
@@ -252,10 +253,9 @@ void register_dock_dependent_device(stru
acpi_handle dshandle)
{
struct dock_station *ds = find_dock_station(dshandle);
- acpi_handle handle = adev->handle;

- if (ds && !find_dock_dependent_device(ds, handle))
- add_dock_dependent_device(ds, handle);
+ if (ds && !find_dock_dependent_device(ds, adev))
+ add_dock_dependent_device(ds, adev);
}

/*****************************************************************************
@@ -264,24 +264,24 @@ void register_dock_dependent_device(stru

/**
* is_dock_device - see if a device is on a dock station
- * @handle: acpi handle of the device
+ * @adev: ACPI device object to check.
*
* If this device is either the dock station itself,
* or is a device dependent on the dock station, then it
* is a dock device
*/
-int is_dock_device(acpi_handle handle)
+int is_dock_device(struct acpi_device *adev)
{
struct dock_station *dock_station;

if (!dock_station_count)
return 0;

- if (acpi_dock_match(handle))
+ if (acpi_dock_match(adev->handle))
return 1;

list_for_each_entry(dock_station, &dock_stations, sibling)
- if (find_dock_dependent_device(dock_station, handle))
+ if (find_dock_dependent_device(dock_station, adev))
return 1;

return 0;
@@ -309,43 +309,6 @@ static int dock_present(struct dock_stat
}

/**
- * dock_create_acpi_device - add new devices to acpi
- * @handle - handle of the device to add
- *
- * This function will create a new acpi_device for the given
- * handle if one does not exist already. This should cause
- * acpi to scan for drivers for the given devices, and call
- * matching driver's add routine.
- */
-static void dock_create_acpi_device(acpi_handle handle)
-{
- struct acpi_device *device = NULL;
- int ret;
-
- acpi_bus_get_device(handle, &device);
- if (!acpi_device_enumerated(device)) {
- ret = acpi_bus_scan(handle);
- if (ret)
- pr_debug("error adding bus, %x\n", -ret);
- }
-}
-
-/**
- * dock_remove_acpi_device - remove the acpi_device struct from acpi
- * @handle - the handle of the device to remove
- *
- * Tell acpi to remove the acpi_device. This should cause any loaded
- * driver to have it's remove routine called.
- */
-static void dock_remove_acpi_device(acpi_handle handle)
-{
- struct acpi_device *device;
-
- if (!acpi_bus_get_device(handle, &device))
- acpi_bus_trim(device);
-}
-
-/**
* hot_remove_dock_devices - Remove dock station devices.
* @ds: Dock station.
*/
@@ -362,7 +325,7 @@ static void hot_remove_dock_devices(stru
dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);

list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
- dock_remove_acpi_device(dd->handle);
+ acpi_bus_trim(dd->adev);
}

/**
@@ -388,12 +351,20 @@ static void hotplug_dock_devices(struct
dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);

/*
- * Now make sure that an acpi_device is created for each dependent
- * device. That will cause scan handlers to be attached to device
- * objects or acpi_drivers to be stopped/started if they are present.
+ * Check if all devices have been enumerated already. If not, run
+ * acpi_bus_scan() for them and that will cause scan handlers to be
+ * attached to device objects or acpi_drivers to be stopped/started if
+ * they are present.
*/
- list_for_each_entry(dd, &ds->dependent_devices, list)
- dock_create_acpi_device(dd->handle);
+ list_for_each_entry(dd, &ds->dependent_devices, list) {
+ struct acpi_device *adev = dd->adev;
+
+ if (!acpi_device_enumerated(adev)) {
+ int ret = acpi_bus_scan(adev->handle);
+ if (ret)
+ dev_dbg(&adev->dev, "scan error %d\n", -ret);
+ }
+ }
}

static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -514,6 +485,7 @@ int register_hotplug_dock_device(acpi_ha
{
struct dock_dependent_device *dd;
struct dock_station *dock_station;
+ struct acpi_device *adev;
int ret = -EINVAL;

if (WARN_ON(!context))
@@ -522,6 +494,10 @@ int register_hotplug_dock_device(acpi_ha
if (!dock_station_count)
return -ENODEV;

+ ret = acpi_bus_get_device(handle, &adev);
+ if (ret)
+ return ret;
+
/*
* make sure this handle is for a device dependent on the dock,
* this would include the dock station itself
@@ -532,7 +508,7 @@ int register_hotplug_dock_device(acpi_ha
* separately, so there are two 'dock stations' which need the
* ops
*/
- dd = find_dock_dependent_device(dock_station, handle);
+ dd = find_dock_dependent_device(dock_station, adev);
if (dd && !dock_init_hotplug(dd, ops, context, init, release))
ret = 0;
}
@@ -549,12 +525,16 @@ void unregister_hotplug_dock_device(acpi
{
struct dock_dependent_device *dd;
struct dock_station *dock_station;
+ struct acpi_device *adev;

if (!dock_station_count)
return;

+ if (acpi_bus_get_device(handle, &adev))
+ return;
+
list_for_each_entry(dock_station, &dock_stations, sibling) {
- dd = find_dock_dependent_device(dock_station, handle);
+ dd = find_dock_dependent_device(dock_station, adev);
if (dd)
dock_release_hotplug(dd);
}
@@ -807,7 +787,7 @@ void acpi_dock_add(struct acpi_device *a
goto err_unregister;

/* add the dock station as a device dependent on itself */
- ret = add_dock_dependent_device(dock_station, handle);
+ ret = add_dock_dependent_device(dock_station, adev);
if (ret)
goto err_rmgroup;

Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -334,7 +334,7 @@ static acpi_status acpiphp_add_context(a
* by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
* expose slots to user space in those cases.
*/
- if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle))
+ if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
&& !(pdev && device_is_managed_by_native_pciehp(pdev))) {
unsigned long long sun;
int retval;
@@ -369,7 +369,7 @@ static acpi_status acpiphp_add_context(a
&val, 60*1000))
slot->flags |= SLOT_ENABLED;

- if (is_dock_device(handle)) {
+ 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
@@ -411,7 +411,7 @@ static void cleanup_bridge(struct acpiph
list_for_each_entry(func, &slot->funcs, sibling) {
struct acpi_device *adev = func_to_acpi_device(func);

- if (is_dock_device(adev->handle))
+ if (is_dock_device(adev))
unregister_hotplug_dock_device(adev->handle);

acpi_lock_hp_context();
Index: linux-pm/include/acpi/acpi_drivers.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_drivers.h
+++ linux-pm/include/acpi/acpi_drivers.h
@@ -116,7 +116,7 @@ struct acpi_dock_ops {
};

#ifdef CONFIG_ACPI_DOCK
-extern int is_dock_device(acpi_handle handle);
+extern int is_dock_device(struct acpi_device *adev);
extern int register_hotplug_dock_device(acpi_handle handle,
const struct acpi_dock_ops *ops,
void *context,
@@ -124,7 +124,7 @@ extern int register_hotplug_dock_device(
void (*release)(void *));
extern void unregister_hotplug_dock_device(acpi_handle handle);
#else
-static inline int is_dock_device(acpi_handle handle)
+static inline int is_dock_device(struct acpi_device *adev)
{
return 0;
}

2014-02-19 01:20:02

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 4/9] ACPI / dock: Use callback pointers from devices' ACPI hotplug contexts

From: Rafael J. Wysocki <[email protected]>

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 <[email protected]>
---
drivers/acpi/dock.c | 29 +++++++++
drivers/pci/hotplug/acpiphp_glue.c | 119 +++++++++++++++----------------------
2 files changed, 78 insertions(+), 70 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/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_i
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 acp
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 *kre
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
| ((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_
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(a
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(a
&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 acpiph
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
{
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;
}

Index: linux-pm/drivers/acpi/dock.c
===================================================================
--- linux-pm.orig/drivers/acpi/dock.c
+++ linux-pm/drivers/acpi/dock.c
@@ -185,9 +185,38 @@ static void dock_release_hotplug(struct
static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
enum dock_callback_type cb_type)
{
+ struct acpi_device *adev = dd->adev;
acpi_notify_handler cb = NULL;
bool run = false;

+ acpi_lock_hp_context();
+
+ if (!adev->hp)
+ goto no_context;
+
+ if (cb_type == DOCK_CALL_FIXUP) {
+ void (*fixup)(struct acpi_device *);
+
+ fixup = adev->hp->fixup;
+ if (fixup) {
+ acpi_unlock_hp_context();
+ fixup(adev);
+ return;
+ }
+ } else {
+ int (*notify)(struct acpi_device *, u32);
+
+ notify = adev->hp->event;
+ if (notify) {
+ acpi_unlock_hp_context();
+ notify(adev, event);
+ return;
+ }
+ }
+
+ no_context:
+ acpi_unlock_hp_context();
+
mutex_lock(&hotplug_lock);

if (dd->hp_context) {

2014-02-19 01:18:33

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 9/9] ACPI / dock: Update copyright notice

From: Rafael J. Wysocki <[email protected]>

Update the copyright notice of the ACPI dock driver to reflect the
fact that substantial changes have been made to it recently.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/dock.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

Index: linux-pm/drivers/acpi/dock.c
===================================================================
--- linux-pm.orig/drivers/acpi/dock.c
+++ linux-pm/drivers/acpi/dock.c
@@ -1,7 +1,9 @@
/*
* dock.c - ACPI dock station driver
*
- * Copyright (C) 2006 Kristen Carlson Accardi <[email protected]>
+ * Copyright (C) 2006, 2014, Intel Corp.
+ * Author: Kristen Carlson Accardi <[email protected]>
+ * Rafael J. Wysocki <[email protected]>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*

2014-02-19 01:20:40

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 5/9] ACPI / dock: Add .uevent() callback to struct acpi_hotplug_context

From: Rafael J. Wysocki <[email protected]>

In order to avoid the need to register special ACPI dock
operations for SATA devices add a .uevent() callback pointer to
struct acpi_hotplug_context and make dock_hotplug_event() use that
callback if available. Also rename the existing .event() callback
in struct acpi_hotplug_context to .notify() to avoid possible
confusion in the future.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/dock.c | 11 ++++++++++-
drivers/acpi/scan.c | 8 ++++----
drivers/pci/hotplug/acpiphp_glue.c | 8 ++++----
include/acpi/acpi_bus.h | 9 ++++++---
4 files changed, 24 insertions(+), 12 deletions(-)

Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -145,7 +145,8 @@ struct acpi_scan_handler {

struct acpi_hotplug_context {
struct acpi_device *self;
- int (*event)(struct acpi_device *, u32);
+ int (*notify)(struct acpi_device *, u32);
+ void (*uevent)(struct acpi_device *, u32);
void (*fixup)(struct acpi_device *);
};

@@ -369,11 +370,13 @@ static inline void acpi_set_device_statu

static inline void acpi_set_hp_context(struct acpi_device *adev,
struct acpi_hotplug_context *hp,
- int (*event)(struct acpi_device *, u32),
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32),
void (*fixup)(struct acpi_device *))
{
hp->self = adev;
- hp->event = event;
+ hp->notify = notify;
+ hp->uevent = uevent;
hp->fixup = fixup;
adev->hp = hp;
}
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -496,17 +496,17 @@ void acpi_device_hotplug(void *data, u32
goto err_out;
}
} else {
- int (*event)(struct acpi_device *, u32);
+ int (*notify)(struct acpi_device *, u32);

acpi_lock_hp_context();
- event = adev->hp ? adev->hp->event : NULL;
+ notify = adev->hp ? adev->hp->notify : NULL;
acpi_unlock_hp_context();
/*
* There may be additional notify handlers for device objects
* without the .event() callback, so ignore them here.
*/
- if (event)
- error = event(adev, src);
+ if (notify)
+ error = notify(adev, src);
else
goto out;
}
Index: linux-pm/drivers/acpi/dock.c
===================================================================
--- linux-pm.orig/drivers/acpi/dock.c
+++ linux-pm/drivers/acpi/dock.c
@@ -203,10 +203,19 @@ static void dock_hotplug_event(struct do
fixup(adev);
return;
}
+ } else if (cb_type == DOCK_CALL_UEVENT) {
+ void (*uevent)(struct acpi_device *, u32);
+
+ uevent = adev->hp->uevent;
+ if (uevent) {
+ acpi_unlock_hp_context();
+ uevent(adev, event);
+ return;
+ }
} else {
int (*notify)(struct acpi_device *, u32);

- notify = adev->hp->event;
+ notify = adev->hp->notify;
if (notify) {
acpi_unlock_hp_context();
notify(adev, event);
Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -59,7 +59,7 @@
static LIST_HEAD(bridge_list);
static DEFINE_MUTEX(bridge_mutex);

-static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type);
+static int acpiphp_hotplug_notify(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);
@@ -81,7 +81,7 @@ static struct acpiphp_context *acpiphp_i
return NULL;

context->refcount = 1;
- acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event,
+ acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL,
acpiphp_post_dock_fixup);
return context;
}
@@ -400,7 +400,7 @@ static void cleanup_bridge(struct acpiph
struct acpi_device *adev = func_to_acpi_device(func);

acpi_lock_hp_context();
- adev->hp->event = NULL;
+ adev->hp->notify = NULL;
adev->hp->fixup = NULL;
acpi_unlock_hp_context();
}
@@ -833,7 +833,7 @@ static void hotplug_event(u32 type, stru
put_bridge(bridge);
}

-static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type)
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type)
{
struct acpiphp_context *context;

2014-02-19 01:21:02

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

From: Rafael J. Wysocki <[email protected]>

Modify the SATA subsystem to add hotplug contexts to ACPI companions
of SATA devices and ports instead of registering special ACPI dock
operations using register_hotplug_dock_device().

That change will allow the entire code handling those special ACPI
dock operations to be dropped in the next commit.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/ata/libata-acpi.c | 76 +++++++++++++++++++++++++++++-----------------
1 file changed, 49 insertions(+), 27 deletions(-)

Index: linux-pm/drivers/ata/libata-acpi.c
===================================================================
--- linux-pm.orig/drivers/ata/libata-acpi.c
+++ linux-pm/drivers/ata/libata-acpi.c
@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct at
dev->gtf_cache = NULL;
}

+struct ata_acpi_hotplug_context {
+ struct acpi_hotplug_context hp;
+ union {
+ struct ata_port *ap;
+ struct ata_device *dev;
+ } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
/**
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device
* @dev: the acpi_handle returned will correspond to this device
@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(stru
ata_port_wait_eh(ap);
}

-static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
-
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+ return 0;
}

-static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_port *ap = data;
-
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+ return 0;
}

static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_p
}
}

-static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{
- ata_acpi_uevent(data, NULL, event);
+ ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
}

-static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_uevent(dev->link->ap, dev, event);
}

-static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
- .handler = ata_acpi_dev_notify_dock,
- .uevent = ata_acpi_dev_uevent,
-};
-
-static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
- .handler = ata_acpi_ap_notify_dock,
- .uevent = ata_acpi_ap_uevent,
-};
-
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *adev;
+ struct ata_acpi_hotplug_context *context;

if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
@@ -188,9 +189,19 @@ void ata_acpi_bind_port(struct ata_port
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;

- /* we might be on a docking station */
- register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
- &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+ adev = ACPI_COMPANION(&ap->tdev);
+ if (!adev)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
+
+ context->data.ap = ap;
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+ ata_acpi_ap_uevent, NULL);
+ acpi_unlock_hp_context();
}

void ata_acpi_bind_dev(struct ata_device *dev)
@@ -198,7 +209,8 @@ void ata_acpi_bind_dev(struct ata_device
struct ata_port *ap = dev->link->ap;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
- struct acpi_device *parent;
+ struct acpi_device *parent, *adev;
+ struct ata_acpi_hotplug_context *context;
u64 adr;

/*
@@ -221,9 +233,19 @@ void ata_acpi_bind_dev(struct ata_device
}

acpi_preset_companion(&dev->tdev, parent, adr);
+ adev = ACPI_COMPANION(&dev->tdev);
+ if (!adev)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;

- register_hotplug_dock_device(ata_dev_acpi_handle(dev),
- &ata_acpi_dev_dock_ops, dev, NULL, NULL);
+ context->data.dev = dev;
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+ ata_acpi_dev_uevent, NULL);
+ acpi_unlock_hp_context();
}

/**

2014-02-19 01:21:24

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 7/9] ACPI / dock: Drop struct acpi_dock_ops and all code related to it

From: Rafael J. Wysocki <[email protected]>

Since struct acpi_dock_ops and the code handling it don't have any
users any more after the previous changes, drop that structure and
the code related to it altogether.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/dock.c | 167 --------------------------------------------
include/acpi/acpi_drivers.h | 22 -----
2 files changed, 2 insertions(+), 187 deletions(-)

Index: linux-pm/include/acpi/acpi_drivers.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_drivers.h
+++ linux-pm/include/acpi/acpi_drivers.h
@@ -109,36 +109,14 @@ 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(struct acpi_device *adev);
-extern int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops,
- void *context,
- void (*init)(void *),
- void (*release)(void *));
-extern void unregister_hotplug_dock_device(acpi_handle handle);
#else
static inline int is_dock_device(struct acpi_device *adev)
{
return 0;
}
-static inline int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops,
- void *context,
- void (*init)(void *),
- void (*release)(void *))
-{
- return -ENODEV;
-}
-static inline void unregister_hotplug_dock_device(acpi_handle handle)
-{
-}
#endif /* CONFIG_ACPI_DOCK */

#endif /*__ACPI_DRIVERS_H__*/
Index: linux-pm/drivers/acpi/dock.c
===================================================================
--- linux-pm.orig/drivers/acpi/dock.c
+++ linux-pm/drivers/acpi/dock.c
@@ -68,15 +68,10 @@ struct dock_station {
};
static LIST_HEAD(dock_stations);
static int dock_station_count;
-static DEFINE_MUTEX(hotplug_lock);

struct dock_dependent_device {
struct list_head list;
struct acpi_device *adev;
- const struct acpi_dock_ops *hp_ops;
- void *hp_context;
- unsigned int hp_refcount;
- void (*hp_release)(void *);
};

#define DOCK_DOCKING 0x00000001
@@ -129,70 +124,15 @@ static void remove_dock_dependent_device
}
}

-/**
- * dock_init_hotplug - Initialize a hotplug device on a docking station.
- * @dd: Dock-dependent device.
- * @ops: Dock operations to attach to the dependent device.
- * @context: Data to pass to the @ops callbacks and @release.
- * @init: Optional initialization routine to run after setting up context.
- * @release: Optional release routine to run on removal.
- */
-static int dock_init_hotplug(struct dock_dependent_device *dd,
- const struct acpi_dock_ops *ops, void *context,
- void (*init)(void *), void (*release)(void *))
-{
- int ret = 0;
-
- mutex_lock(&hotplug_lock);
- if (WARN_ON(dd->hp_context)) {
- ret = -EEXIST;
- } else {
- dd->hp_refcount = 1;
- dd->hp_ops = ops;
- dd->hp_context = context;
- dd->hp_release = release;
- if (init)
- init(context);
- }
- mutex_unlock(&hotplug_lock);
- return ret;
-}
-
-/**
- * dock_release_hotplug - Decrement hotplug reference counter of dock device.
- * @dd: Dock-dependent device.
- *
- * Decrement the reference counter of @dd and if 0, detach its hotplug
- * operations from it, reset its context pointer and run the optional release
- * routine if present.
- */
-static void dock_release_hotplug(struct dock_dependent_device *dd)
-{
- mutex_lock(&hotplug_lock);
- if (dd->hp_context && !--dd->hp_refcount) {
- void (*release)(void *) = dd->hp_release;
- void *context = dd->hp_context;
-
- dd->hp_ops = NULL;
- dd->hp_context = NULL;
- dd->hp_release = NULL;
- if (release)
- release(context);
- }
- mutex_unlock(&hotplug_lock);
-}
-
static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
enum dock_callback_type cb_type)
{
struct acpi_device *adev = dd->adev;
- acpi_notify_handler cb = NULL;
- bool run = false;

acpi_lock_hp_context();

if (!adev->hp)
- goto no_context;
+ goto out;

if (cb_type == DOCK_CALL_FIXUP) {
void (*fixup)(struct acpi_device *);
@@ -223,37 +163,8 @@ static void dock_hotplug_event(struct do
}
}

- no_context:
+ out:
acpi_unlock_hp_context();
-
- mutex_lock(&hotplug_lock);
-
- if (dd->hp_context) {
- run = true;
- dd->hp_refcount++;
- 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);
-
- if (!run)
- return;
-
- if (cb)
- cb(dd->adev->handle, event, dd->hp_context);
-
- dock_release_hotplug(dd);
}

static struct dock_station *find_dock_station(acpi_handle handle)
@@ -506,80 +417,6 @@ static int dock_in_progress(struct dock_
}

/**
- * register_hotplug_dock_device - register a hotplug function
- * @handle: the handle of the device
- * @ops: handlers to call after docking
- * @context: device specific data
- * @init: Optional initialization routine to run after registration
- * @release: Optional release routine to run on unregistration
- *
- * If a driver would like to perform a hotplug operation after a dock
- * event, they can register an acpi_notifiy_handler to be called by
- * the dock driver after _DCK is executed.
- */
-int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops, void *context,
- void (*init)(void *), void (*release)(void *))
-{
- struct dock_dependent_device *dd;
- struct dock_station *dock_station;
- struct acpi_device *adev;
- int ret = -EINVAL;
-
- if (WARN_ON(!context))
- return -EINVAL;
-
- if (!dock_station_count)
- return -ENODEV;
-
- ret = acpi_bus_get_device(handle, &adev);
- if (ret)
- return ret;
-
- /*
- * make sure this handle is for a device dependent on the dock,
- * this would include the dock station itself
- */
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- /*
- * An ATA bay can be in a dock and itself can be ejected
- * separately, so there are two 'dock stations' which need the
- * ops
- */
- dd = find_dock_dependent_device(dock_station, adev);
- if (dd && !dock_init_hotplug(dd, ops, context, init, release))
- ret = 0;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
-
-/**
- * unregister_hotplug_dock_device - remove yourself from the hotplug list
- * @handle: the acpi handle of the device
- */
-void unregister_hotplug_dock_device(acpi_handle handle)
-{
- struct dock_dependent_device *dd;
- struct dock_station *dock_station;
- struct acpi_device *adev;
-
- if (!dock_station_count)
- return;
-
- if (acpi_bus_get_device(handle, &adev))
- return;
-
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- dd = find_dock_dependent_device(dock_station, adev);
- if (dd)
- dock_release_hotplug(dd);
- }
-}
-EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
-
-/**
* handle_eject_request - handle an undock request checking for error conditions
*
* Check to make sure the dock device is still present, then undock and

2014-02-19 02:42:06

by Aaron Lu

[permalink] [raw]
Subject: Re: [PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

On 02/19/2014 09:30 AM, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
>
> Modify the SATA subsystem to add hotplug contexts to ACPI companions
> of SATA devices and ports instead of registering special ACPI dock
> operations using register_hotplug_dock_device().
>
> That change will allow the entire code handling those special ACPI
> dock operations to be dropped in the next commit.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>
> ---
> drivers/ata/libata-acpi.c | 76 +++++++++++++++++++++++++++++-----------------
> 1 file changed, 49 insertions(+), 27 deletions(-)
>
> Index: linux-pm/drivers/ata/libata-acpi.c
> ===================================================================
> --- linux-pm.orig/drivers/ata/libata-acpi.c
> +++ linux-pm/drivers/ata/libata-acpi.c
> @@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct at
> dev->gtf_cache = NULL;
> }
>
> +struct ata_acpi_hotplug_context {
> + struct acpi_hotplug_context hp;
> + union {
> + struct ata_port *ap;
> + struct ata_device *dev;
> + } data;
> +};
> +
> +#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
> +
> /**
> * ata_dev_acpi_handle - provide the acpi_handle for an ata_device
> * @dev: the acpi_handle returned will correspond to this device
> @@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(stru
> ata_port_wait_eh(ap);
> }
>
> -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
> +static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
> {
> - struct ata_device *dev = data;
> -
> + struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
> ata_acpi_handle_hotplug(dev->link->ap, dev, event);
> + return 0;
> }
>
> -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
> +static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
> {
> - struct ata_port *ap = data;
> -
> - ata_acpi_handle_hotplug(ap, NULL, event);
> + ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
> + return 0;
> }
>
> static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
> @@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_p
> }
> }
>
> -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
> +static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
> {
> - ata_acpi_uevent(data, NULL, event);
> + ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
> }
>
> -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
> +static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
> {
> - struct ata_device *dev = data;
> + struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
> ata_acpi_uevent(dev->link->ap, dev, event);
> }
>
> -static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
> - .handler = ata_acpi_dev_notify_dock,
> - .uevent = ata_acpi_dev_uevent,
> -};
> -
> -static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
> - .handler = ata_acpi_ap_notify_dock,
> - .uevent = ata_acpi_ap_uevent,
> -};
> -
> /* bind acpi handle to pata port */
> void ata_acpi_bind_port(struct ata_port *ap)
> {
> struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
> + struct acpi_device *adev;
> + struct ata_acpi_hotplug_context *context;
>
> if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
> return;
> @@ -188,9 +189,19 @@ void ata_acpi_bind_port(struct ata_port
> if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
> ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
>
> - /* we might be on a docking station */
> - register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
> - &ata_acpi_ap_dock_ops, ap, NULL, NULL);
> + adev = ACPI_COMPANION(&ap->tdev);
> + if (!adev)
> + return;
> +
> + context = kzalloc(sizeof(*context), GFP_KERNEL);
> + if (!context)
> + return;

The context isn't freed on ATA driver detach, which doesn't normally
happen though.

Thanks,
Aaron

2014-02-19 16:25:52

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

On Wednesday, February 19, 2014 10:42:20 AM Aaron Lu wrote:
> On 02/19/2014 09:30 AM, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <[email protected]>
> >
> > Modify the SATA subsystem to add hotplug contexts to ACPI companions
> > of SATA devices and ports instead of registering special ACPI dock
> > operations using register_hotplug_dock_device().
> >
> > That change will allow the entire code handling those special ACPI
> > dock operations to be dropped in the next commit.
> >
> > Signed-off-by: Rafael J. Wysocki <[email protected]>
> > ---
> > drivers/ata/libata-acpi.c | 76 +++++++++++++++++++++++++++++-----------------
> > 1 file changed, 49 insertions(+), 27 deletions(-)
> >
> > Index: linux-pm/drivers/ata/libata-acpi.c
> > ===================================================================
> > --- linux-pm.orig/drivers/ata/libata-acpi.c
> > +++ linux-pm/drivers/ata/libata-acpi.c
> > @@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct at
> > dev->gtf_cache = NULL;
> > }
> >
> > +struct ata_acpi_hotplug_context {
> > + struct acpi_hotplug_context hp;
> > + union {
> > + struct ata_port *ap;
> > + struct ata_device *dev;
> > + } data;
> > +};
> > +
> > +#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
> > +
> > /**
> > * ata_dev_acpi_handle - provide the acpi_handle for an ata_device
> > * @dev: the acpi_handle returned will correspond to this device
> > @@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(stru
> > ata_port_wait_eh(ap);
> > }
> >
> > -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
> > +static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
> > {
> > - struct ata_device *dev = data;
> > -
> > + struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
> > ata_acpi_handle_hotplug(dev->link->ap, dev, event);
> > + return 0;
> > }
> >
> > -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
> > +static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
> > {
> > - struct ata_port *ap = data;
> > -
> > - ata_acpi_handle_hotplug(ap, NULL, event);
> > + ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
> > + return 0;
> > }
> >
> > static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
> > @@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_p
> > }
> > }
> >
> > -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
> > +static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
> > {
> > - ata_acpi_uevent(data, NULL, event);
> > + ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
> > }
> >
> > -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
> > +static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
> > {
> > - struct ata_device *dev = data;
> > + struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
> > ata_acpi_uevent(dev->link->ap, dev, event);
> > }
> >
> > -static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
> > - .handler = ata_acpi_dev_notify_dock,
> > - .uevent = ata_acpi_dev_uevent,
> > -};
> > -
> > -static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
> > - .handler = ata_acpi_ap_notify_dock,
> > - .uevent = ata_acpi_ap_uevent,
> > -};
> > -
> > /* bind acpi handle to pata port */
> > void ata_acpi_bind_port(struct ata_port *ap)
> > {
> > struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
> > + struct acpi_device *adev;
> > + struct ata_acpi_hotplug_context *context;
> >
> > if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
> > return;
> > @@ -188,9 +189,19 @@ void ata_acpi_bind_port(struct ata_port
> > if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
> > ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
> >
> > - /* we might be on a docking station */
> > - register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
> > - &ata_acpi_ap_dock_ops, ap, NULL, NULL);
> > + adev = ACPI_COMPANION(&ap->tdev);
> > + if (!adev)
> > + return;
> > +
> > + context = kzalloc(sizeof(*context), GFP_KERNEL);
> > + if (!context)
> > + return;
>
> The context isn't freed on ATA driver detach, which doesn't normally
> happen though.

Yes, but it will happen for ATA devices in docks and bays. However,
the struct acpi_device objects won't go away then and we only need to initialize
the contexts once, so it should be sufficient to simply return from here if
the context is already there.

I'll send an updated patch with that change later today.

Thanks,
Rafael

2014-02-20 01:32:29

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update][PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

From: Rafael J. Wysocki <[email protected]>

Modify the SATA subsystem to add hotplug contexts to ACPI companions
of SATA devices and ports instead of registering special ACPI dock
operations using register_hotplug_dock_device().

That change will allow the entire code handling those special ACPI
dock operations to be dropped in the next commit.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---

As noted by Aaron, the hotplug contexts are not freed during ATA device
unregistration, but that is not necessary, because the struct acpi_device
things they are attached to never go away. However, they obviously should
not be created more than once per struct acpi_device, so I've modified the
patch to skip the creation of hotplug contexts for devices that already
have them.

Thanks,
Rafael

---
drivers/ata/libata-acpi.c | 76 +++++++++++++++++++++++++++++-----------------
1 file changed, 49 insertions(+), 27 deletions(-)

Index: linux-pm/drivers/ata/libata-acpi.c
===================================================================
--- linux-pm.orig/drivers/ata/libata-acpi.c
+++ linux-pm/drivers/ata/libata-acpi.c
@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct at
dev->gtf_cache = NULL;
}

+struct ata_acpi_hotplug_context {
+ struct acpi_hotplug_context hp;
+ union {
+ struct ata_port *ap;
+ struct ata_device *dev;
+ } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
/**
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device
* @dev: the acpi_handle returned will correspond to this device
@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(stru
ata_port_wait_eh(ap);
}

-static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
-
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+ return 0;
}

-static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_port *ap = data;
-
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+ return 0;
}

static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_p
}
}

-static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{
- ata_acpi_uevent(data, NULL, event);
+ ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
}

-static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_uevent(dev->link->ap, dev, event);
}

-static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
- .handler = ata_acpi_dev_notify_dock,
- .uevent = ata_acpi_dev_uevent,
-};
-
-static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
- .handler = ata_acpi_ap_notify_dock,
- .uevent = ata_acpi_ap_uevent,
-};
-
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *adev;
+ struct ata_acpi_hotplug_context *context;

if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
@@ -188,9 +189,19 @@ void ata_acpi_bind_port(struct ata_port
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;

- /* we might be on a docking station */
- register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
- &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+ adev = ACPI_COMPANION(&ap->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
+
+ context->data.ap = ap;
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+ ata_acpi_ap_uevent, NULL);
+ acpi_unlock_hp_context();
}

void ata_acpi_bind_dev(struct ata_device *dev)
@@ -198,7 +209,8 @@ void ata_acpi_bind_dev(struct ata_device
struct ata_port *ap = dev->link->ap;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
- struct acpi_device *parent;
+ struct acpi_device *parent, *adev;
+ struct ata_acpi_hotplug_context *context;
u64 adr;

/*
@@ -221,9 +233,19 @@ void ata_acpi_bind_dev(struct ata_device
}

acpi_preset_companion(&dev->tdev, parent, adr);
+ adev = ACPI_COMPANION(&dev->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;

- register_hotplug_dock_device(ata_dev_acpi_handle(dev),
- &ata_acpi_dev_dock_ops, dev, NULL, NULL);
+ context->data.dev = dev;
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+ ata_acpi_dev_uevent, NULL);
+ acpi_unlock_hp_context();
}

/**

2014-02-20 08:23:33

by Aaron Lu

[permalink] [raw]
Subject: Re: [Update][PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

On 02/20/2014 09:47 AM, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
>
> Modify the SATA subsystem to add hotplug contexts to ACPI companions
> of SATA devices and ports instead of registering special ACPI dock
> operations using register_hotplug_dock_device().
>
> That change will allow the entire code handling those special ACPI
> dock operations to be dropped in the next commit.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>

Reviewed-by: Aaron Lu <[email protected]>

2014-02-20 14:26:45

by [email protected]

[permalink] [raw]
Subject: Re: [Update][PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

On Thu, Feb 20, 2014 at 02:47:19AM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
>
> Modify the SATA subsystem to add hotplug contexts to ACPI companions
> of SATA devices and ports instead of registering special ACPI dock
> operations using register_hotplug_dock_device().
>
> That change will allow the entire code handling those special ACPI
> dock operations to be dropped in the next commit.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>
> ---
>
> As noted by Aaron, the hotplug contexts are not freed during ATA device
> unregistration, but that is not necessary, because the struct acpi_device
> things they are attached to never go away. However, they obviously should
> not be created more than once per struct acpi_device, so I've modified the
> patch to skip the creation of hotplug contexts for devices that already
> have them.

Please feel free to route with the rest of acpi changes.

Acked-by: Tejun Heo <[email protected]>

Thanks.

--
tejun

2014-02-20 23:45:01

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [Update][PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

On Thursday, February 20, 2014 09:26:39 AM Tejun Heo wrote:
> On Thu, Feb 20, 2014 at 02:47:19AM +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <[email protected]>
> >
> > Modify the SATA subsystem to add hotplug contexts to ACPI companions
> > of SATA devices and ports instead of registering special ACPI dock
> > operations using register_hotplug_dock_device().
> >
> > That change will allow the entire code handling those special ACPI
> > dock operations to be dropped in the next commit.
> >
> > Signed-off-by: Rafael J. Wysocki <[email protected]>
> > ---
> >
> > As noted by Aaron, the hotplug contexts are not freed during ATA device
> > unregistration, but that is not necessary, because the struct acpi_device
> > things they are attached to never go away. However, they obviously should
> > not be created more than once per struct acpi_device, so I've modified the
> > patch to skip the creation of hotplug contexts for devices that already
> > have them.
>
> Please feel free to route with the rest of acpi changes.

I will.

> Acked-by: Tejun Heo <[email protected]>

Thanks!

--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2014-02-22 00:00:21

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update 2x][PATCH 6/9] ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices

From: Rafael J. Wysocki <[email protected]>

Modify the SATA subsystem to add hotplug contexts to ACPI companions
of SATA devices and ports instead of registering special ACPI dock
operations using register_hotplug_dock_device().

That change will allow the entire code handling those special ACPI
dock operations to be dropped in the next commit.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Reviewed-by: Aaron Lu <[email protected]>
Acked-by: Tejun Heo <[email protected]>
---

The previous version caused modular builds of libata-acpi.c to fail because
of the ACPI hotplug context locking wrappers that aren't exported to modules.
I (hopefully) fixed that by introducing a wrapper around acpi_set_hp_context()
that does the locking and is exported.

I retained the Reviewed-by and ACK above, because the change was only cosmetic,
so please let me know if that's not appropriate.

Rafael

---
drivers/acpi/scan.c | 11 +++++++
drivers/ata/libata-acpi.c | 72 ++++++++++++++++++++++++++++------------------
include/acpi/acpi_bus.h | 5 +++
3 files changed, 61 insertions(+), 27 deletions(-)

Index: linux-pm/drivers/ata/libata-acpi.c
===================================================================
--- linux-pm.orig/drivers/ata/libata-acpi.c
+++ linux-pm/drivers/ata/libata-acpi.c
@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct at
dev->gtf_cache = NULL;
}

+struct ata_acpi_hotplug_context {
+ struct acpi_hotplug_context hp;
+ union {
+ struct ata_port *ap;
+ struct ata_device *dev;
+ } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
/**
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device
* @dev: the acpi_handle returned will correspond to this device
@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(stru
ata_port_wait_eh(ap);
}

-static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
-
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+ return 0;
}

-static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_port *ap = data;
-
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+ return 0;
}

static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_p
}
}

-static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{
- ata_acpi_uevent(data, NULL, event);
+ ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
}

-static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_uevent(dev->link->ap, dev, event);
}

-static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
- .handler = ata_acpi_dev_notify_dock,
- .uevent = ata_acpi_dev_uevent,
-};
-
-static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
- .handler = ata_acpi_ap_notify_dock,
- .uevent = ata_acpi_ap_uevent,
-};
-
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *adev;
+ struct ata_acpi_hotplug_context *context;

if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
@@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;

- /* we might be on a docking station */
- register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
- &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+ adev = ACPI_COMPANION(&ap->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
+
+ context->data.ap = ap;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+ ata_acpi_ap_uevent);
}

void ata_acpi_bind_dev(struct ata_device *dev)
@@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device
struct ata_port *ap = dev->link->ap;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
- struct acpi_device *parent;
+ struct acpi_device *parent, *adev;
+ struct ata_acpi_hotplug_context *context;
u64 adr;

/*
@@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device
}

acpi_preset_companion(&dev->tdev, parent, adr);
+ adev = ACPI_COMPANION(&dev->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;

- register_hotplug_dock_device(ata_dev_acpi_handle(dev),
- &ata_acpi_dev_dock_ops, dev, NULL, NULL);
+ context->data.dev = dev;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+ ata_acpi_dev_uevent);
}

/**
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -71,6 +71,17 @@ void acpi_unlock_hp_context(void)
mutex_unlock(&acpi_hp_context_lock);
}

+void acpi_initialize_hp_context(struct acpi_device *adev,
+ struct acpi_hotplug_context *hp,
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32))
+{
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, hp, notify, uevent, NULL);
+ acpi_unlock_hp_context();
+}
+EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
+
int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{
if (!handler || !handler->attach)
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -381,6 +381,11 @@ static inline void acpi_set_hp_context(s
adev->hp = hp;
}

+void acpi_initialize_hp_context(struct acpi_device *adev,
+ struct acpi_hotplug_context *hp,
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32));
+
/* acpi_device.dev.bus == &acpi_bus_type */
extern struct bus_type acpi_bus_type;