Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 377358
b: refs/heads/master
c: 21a3101
h: refs/heads/master
v: v3
  • Loading branch information
Rafael J. Wysocki committed Jun 24, 2013
1 parent 5f692a0 commit a8fb250
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 59 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d66ecb7220a70ec3f6c0e38e4af28fb8b25d31c6
refs/heads/master: 21a31013f774c726bd199526cd673acc6432b21d
137 changes: 95 additions & 42 deletions trunk/drivers/acpi/dock.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,21 @@ struct dock_station {
spinlock_t dd_lock;
struct mutex hp_lock;
struct list_head dependent_devices;
struct list_head hotplug_devices;

struct list_head sibling;
struct platform_device *dock_device;
};
static LIST_HEAD(dock_stations);
static int dock_station_count;
static DEFINE_MUTEX(hotplug_lock);

struct dock_dependent_device {
struct list_head list;
struct list_head hotplug_list;
acpi_handle handle;
const struct acpi_dock_ops *ops;
void *context;
const struct acpi_dock_ops *hp_ops;
void *hp_context;
unsigned int hp_refcount;
void (*hp_release)(void *);
};

#define DOCK_DOCKING 0x00000001
Expand Down Expand Up @@ -111,7 +112,6 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)

dd->handle = handle;
INIT_LIST_HEAD(&dd->list);
INIT_LIST_HEAD(&dd->hotplug_list);

spin_lock(&ds->dd_lock);
list_add_tail(&dd->list, &ds->dependent_devices);
Expand All @@ -121,35 +121,90 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
}

/**
* dock_add_hotplug_device - associate a hotplug handler with the dock station
* @ds: The dock station
* @dd: The dependent device struct
*
* Add the dependent device to the dock's hotplug device list
* 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 void
dock_add_hotplug_device(struct dock_station *ds,
struct dock_dependent_device *dd)
static int dock_init_hotplug(struct dock_dependent_device *dd,
const struct acpi_dock_ops *ops, void *context,
void (*init)(void *), void (*release)(void *))
{
mutex_lock(&ds->hp_lock);
list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
mutex_unlock(&ds->hp_lock);
int ret = 0;

mutex_lock(&hotplug_lock);

if (dd->hp_context) {
ret = -EEXIST;
} else {
dd->hp_refcount = 1;
dd->hp_ops = ops;
dd->hp_context = context;
dd->hp_release = release;
}

if (!WARN_ON(ret) && init)
init(context);

mutex_unlock(&hotplug_lock);
return ret;
}

/**
* dock_del_hotplug_device - remove a hotplug handler from the dock station
* @ds: The dock station
* @dd: the dependent device struct
* dock_release_hotplug - Decrement hotplug reference counter of dock device.
* @dd: Dock-dependent device.
*
* Delete the dependent device from the dock's hotplug device list
* 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_del_hotplug_device(struct dock_station *ds,
struct dock_dependent_device *dd)
static void dock_release_hotplug(struct dock_dependent_device *dd)
{
mutex_lock(&ds->hp_lock);
list_del(&dd->hotplug_list);
mutex_unlock(&ds->hp_lock);
void (*release)(void *) = NULL;
void *context = NULL;

mutex_lock(&hotplug_lock);

if (dd->hp_context && !--dd->hp_refcount) {
dd->hp_ops = NULL;
context = dd->hp_context;
dd->hp_context = NULL;
release = dd->hp_release;
dd->hp_release = NULL;
}

if (release && context)
release(context);

mutex_unlock(&hotplug_lock);
}

static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
bool uevent)
{
acpi_notify_handler cb = NULL;
bool run = false;

mutex_lock(&hotplug_lock);

if (dd->hp_context) {
run = true;
dd->hp_refcount++;
if (dd->hp_ops)
cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
}

mutex_unlock(&hotplug_lock);

if (!run)
return;

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

dock_release_hotplug(dd);
}

/**
Expand Down Expand Up @@ -360,9 +415,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
/*
* First call driver specific hotplug functions
*/
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
if (dd->ops && dd->ops->handler)
dd->ops->handler(dd->handle, event, dd->context);
list_for_each_entry(dd, &ds->dependent_devices, list)
dock_hotplug_event(dd, event, false);

/*
* Now make sure that an acpi_device is created for each
Expand Down Expand Up @@ -398,9 +452,8 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
if (num == DOCK_EVENT)
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);

list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
if (dd->ops && dd->ops->uevent)
dd->ops->uevent(dd->handle, event, dd->context);
list_for_each_entry(dd, &ds->dependent_devices, list)
dock_hotplug_event(dd, event, true);

if (num != DOCK_EVENT)
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
Expand Down Expand Up @@ -570,19 +623,24 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
* @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)
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;
int ret = -EINVAL;

if (WARN_ON(!context))
return -EINVAL;

if (!dock_station_count)
return -ENODEV;

Expand All @@ -597,12 +655,8 @@ register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops
* ops
*/
dd = find_dock_dependent_device(dock_station, handle);
if (dd) {
dd->ops = ops;
dd->context = context;
dock_add_hotplug_device(dock_station, dd);
if (dd && !dock_init_hotplug(dd, ops, context, init, release))
ret = 0;
}
}

return ret;
Expand All @@ -624,7 +678,7 @@ void unregister_hotplug_dock_device(acpi_handle handle)
list_for_each_entry(dock_station, &dock_stations, sibling) {
dd = find_dock_dependent_device(dock_station, handle);
if (dd)
dock_del_hotplug_device(dock_station, dd);
dock_release_hotplug(dd);
}
}
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
Expand Down Expand Up @@ -953,7 +1007,6 @@ static int __init dock_add(acpi_handle handle)
mutex_init(&dock_station->hp_lock);
spin_lock_init(&dock_station->dd_lock);
INIT_LIST_HEAD(&dock_station->sibling);
INIT_LIST_HEAD(&dock_station->hotplug_devices);
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
INIT_LIST_HEAD(&dock_station->dependent_devices);

Expand Down
46 changes: 32 additions & 14 deletions trunk/drivers/pci/hotplug/acpiphp_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static DEFINE_MUTEX(bridge_mutex);
static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
static void free_bridge(struct kref *kref);

Expand Down Expand Up @@ -147,7 +148,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,


static const struct acpi_dock_ops acpiphp_dock_ops = {
.handler = handle_hotplug_event_func,
.handler = hotplug_event_func,
};

/* Check whether the PCI device is managed by native PCIe hotplug driver */
Expand Down Expand Up @@ -179,6 +180,20 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
return true;
}

static void acpiphp_dock_init(void *data)
{
struct acpiphp_func *func = data;

get_bridge(func->slot->bridge);
}

static void acpiphp_dock_release(void *data)
{
struct acpiphp_func *func = data;

put_bridge(func->slot->bridge);
}

/* callback routine to register each ACPI PCI slot object */
static acpi_status
register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
Expand Down Expand Up @@ -298,7 +313,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
*/
newfunc->flags &= ~FUNC_HAS_EJ0;
if (register_hotplug_dock_device(handle,
&acpiphp_dock_ops, newfunc))
&acpiphp_dock_ops, newfunc,
acpiphp_dock_init, acpiphp_dock_release))
dbg("failed to register dock device\n");

/* we need to be notified when dock events happen
Expand Down Expand Up @@ -1068,22 +1084,12 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
}

static void _handle_hotplug_event_func(struct work_struct *work)
static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
{
struct acpiphp_func *func;
struct acpiphp_func *func = context;
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
struct acpi_hp_work *hp_work;
acpi_handle handle;
u32 type;

hp_work = container_of(work, struct acpi_hp_work, work);
handle = hp_work->handle;
type = hp_work->type;
func = (struct acpiphp_func *)hp_work->context;

acpi_scan_lock_acquire();

acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);

Expand Down Expand Up @@ -1116,6 +1122,18 @@ static void _handle_hotplug_event_func(struct work_struct *work)
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
break;
}
}

static void _handle_hotplug_event_func(struct work_struct *work)
{
struct acpi_hp_work *hp_work;
struct acpiphp_func *func;

hp_work = container_of(work, struct acpi_hp_work, work);
func = hp_work->context;
acpi_scan_lock_acquire();

hotplug_event_func(hp_work->handle, hp_work->type, func);

acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_func */
Expand Down
8 changes: 6 additions & 2 deletions trunk/include/acpi/acpi_drivers.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ extern int register_dock_notifier(struct notifier_block *nb);
extern void unregister_dock_notifier(struct notifier_block *nb);
extern int register_hotplug_dock_device(acpi_handle handle,
const struct acpi_dock_ops *ops,
void *context);
void *context,
void (*init)(void *),
void (*release)(void *));
extern void unregister_hotplug_dock_device(acpi_handle handle);
#else
static inline int is_dock_device(acpi_handle handle)
Expand All @@ -139,7 +141,9 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
}
static inline int register_hotplug_dock_device(acpi_handle handle,
const struct acpi_dock_ops *ops,
void *context)
void *context,
void (*init)(void *),
void (*release)(void *))
{
return -ENODEV;
}
Expand Down

0 comments on commit a8fb250

Please sign in to comment.