Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 96c9dda

Browse files
committed
Merge branch 'acpi-fixes'
* acpi-fixes: libata-acpi: add back ACPI based hotplug functionality ACPI / dock / PCI: Synchronous handling of dock events for PCI devices PCI / ACPI: Use boot-time resource allocation rules during hotplug ACPI / dock: Initialize ACPI dock subsystem upfront
2 parents 9e895ac + 4452152 commit 96c9dda

File tree

10 files changed

+194
-106
lines changed

10 files changed

+194
-106
lines changed

drivers/acpi/dock.c

Lines changed: 96 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,21 @@ struct dock_station {
6666
spinlock_t dd_lock;
6767
struct mutex hp_lock;
6868
struct list_head dependent_devices;
69-
struct list_head hotplug_devices;
7069

7170
struct list_head sibling;
7271
struct platform_device *dock_device;
7372
};
7473
static LIST_HEAD(dock_stations);
7574
static int dock_station_count;
75+
static DEFINE_MUTEX(hotplug_lock);
7676

7777
struct dock_dependent_device {
7878
struct list_head list;
79-
struct list_head hotplug_list;
8079
acpi_handle handle;
81-
const struct acpi_dock_ops *ops;
82-
void *context;
80+
const struct acpi_dock_ops *hp_ops;
81+
void *hp_context;
82+
unsigned int hp_refcount;
83+
void (*hp_release)(void *);
8384
};
8485

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

112113
dd->handle = handle;
113114
INIT_LIST_HEAD(&dd->list);
114-
INIT_LIST_HEAD(&dd->hotplug_list);
115115

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

123123
/**
124-
* dock_add_hotplug_device - associate a hotplug handler with the dock station
125-
* @ds: The dock station
126-
* @dd: The dependent device struct
127-
*
128-
* Add the dependent device to the dock's hotplug device list
124+
* dock_init_hotplug - Initialize a hotplug device on a docking station.
125+
* @dd: Dock-dependent device.
126+
* @ops: Dock operations to attach to the dependent device.
127+
* @context: Data to pass to the @ops callbacks and @release.
128+
* @init: Optional initialization routine to run after setting up context.
129+
* @release: Optional release routine to run on removal.
129130
*/
130-
static void
131-
dock_add_hotplug_device(struct dock_station *ds,
132-
struct dock_dependent_device *dd)
131+
static int dock_init_hotplug(struct dock_dependent_device *dd,
132+
const struct acpi_dock_ops *ops, void *context,
133+
void (*init)(void *), void (*release)(void *))
133134
{
134-
mutex_lock(&ds->hp_lock);
135-
list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
136-
mutex_unlock(&ds->hp_lock);
135+
int ret = 0;
136+
137+
mutex_lock(&hotplug_lock);
138+
139+
if (dd->hp_context) {
140+
ret = -EEXIST;
141+
} else {
142+
dd->hp_refcount = 1;
143+
dd->hp_ops = ops;
144+
dd->hp_context = context;
145+
dd->hp_release = release;
146+
}
147+
148+
if (!WARN_ON(ret) && init)
149+
init(context);
150+
151+
mutex_unlock(&hotplug_lock);
152+
return ret;
137153
}
138154

139155
/**
140-
* dock_del_hotplug_device - remove a hotplug handler from the dock station
141-
* @ds: The dock station
142-
* @dd: the dependent device struct
156+
* dock_release_hotplug - Decrement hotplug reference counter of dock device.
157+
* @dd: Dock-dependent device.
143158
*
144-
* Delete the dependent device from the dock's hotplug device list
159+
* Decrement the reference counter of @dd and if 0, detach its hotplug
160+
* operations from it, reset its context pointer and run the optional release
161+
* routine if present.
145162
*/
146-
static void
147-
dock_del_hotplug_device(struct dock_station *ds,
148-
struct dock_dependent_device *dd)
163+
static void dock_release_hotplug(struct dock_dependent_device *dd)
149164
{
150-
mutex_lock(&ds->hp_lock);
151-
list_del(&dd->hotplug_list);
152-
mutex_unlock(&ds->hp_lock);
165+
void (*release)(void *) = NULL;
166+
void *context = NULL;
167+
168+
mutex_lock(&hotplug_lock);
169+
170+
if (dd->hp_context && !--dd->hp_refcount) {
171+
dd->hp_ops = NULL;
172+
context = dd->hp_context;
173+
dd->hp_context = NULL;
174+
release = dd->hp_release;
175+
dd->hp_release = NULL;
176+
}
177+
178+
if (release && context)
179+
release(context);
180+
181+
mutex_unlock(&hotplug_lock);
182+
}
183+
184+
static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
185+
bool uevent)
186+
{
187+
acpi_notify_handler cb = NULL;
188+
bool run = false;
189+
190+
mutex_lock(&hotplug_lock);
191+
192+
if (dd->hp_context) {
193+
run = true;
194+
dd->hp_refcount++;
195+
if (dd->hp_ops)
196+
cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
197+
}
198+
199+
mutex_unlock(&hotplug_lock);
200+
201+
if (!run)
202+
return;
203+
204+
if (cb)
205+
cb(dd->handle, event, dd->hp_context);
206+
207+
dock_release_hotplug(dd);
153208
}
154209

155210
/**
@@ -360,9 +415,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
360415
/*
361416
* First call driver specific hotplug functions
362417
*/
363-
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
364-
if (dd->ops && dd->ops->handler)
365-
dd->ops->handler(dd->handle, event, dd->context);
418+
list_for_each_entry(dd, &ds->dependent_devices, list)
419+
dock_hotplug_event(dd, event, false);
366420

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

401-
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
402-
if (dd->ops && dd->ops->uevent)
403-
dd->ops->uevent(dd->handle, event, dd->context);
455+
list_for_each_entry(dd, &ds->dependent_devices, list)
456+
dock_hotplug_event(dd, event, true);
404457

405458
if (num != DOCK_EVENT)
406459
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
@@ -570,19 +623,24 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
570623
* @handle: the handle of the device
571624
* @ops: handlers to call after docking
572625
* @context: device specific data
626+
* @init: Optional initialization routine to run after registration
627+
* @release: Optional release routine to run on unregistration
573628
*
574629
* If a driver would like to perform a hotplug operation after a dock
575630
* event, they can register an acpi_notifiy_handler to be called by
576631
* the dock driver after _DCK is executed.
577632
*/
578-
int
579-
register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops,
580-
void *context)
633+
int register_hotplug_dock_device(acpi_handle handle,
634+
const struct acpi_dock_ops *ops, void *context,
635+
void (*init)(void *), void (*release)(void *))
581636
{
582637
struct dock_dependent_device *dd;
583638
struct dock_station *dock_station;
584639
int ret = -EINVAL;
585640

641+
if (WARN_ON(!context))
642+
return -EINVAL;
643+
586644
if (!dock_station_count)
587645
return -ENODEV;
588646

@@ -597,12 +655,8 @@ register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops
597655
* ops
598656
*/
599657
dd = find_dock_dependent_device(dock_station, handle);
600-
if (dd) {
601-
dd->ops = ops;
602-
dd->context = context;
603-
dock_add_hotplug_device(dock_station, dd);
658+
if (dd && !dock_init_hotplug(dd, ops, context, init, release))
604659
ret = 0;
605-
}
606660
}
607661

608662
return ret;
@@ -624,7 +678,7 @@ void unregister_hotplug_dock_device(acpi_handle handle)
624678
list_for_each_entry(dock_station, &dock_stations, sibling) {
625679
dd = find_dock_dependent_device(dock_station, handle);
626680
if (dd)
627-
dock_del_hotplug_device(dock_station, dd);
681+
dock_release_hotplug(dd);
628682
}
629683
}
630684
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
@@ -953,7 +1007,6 @@ static int __init dock_add(acpi_handle handle)
9531007
mutex_init(&dock_station->hp_lock);
9541008
spin_lock_init(&dock_station->dd_lock);
9551009
INIT_LIST_HEAD(&dock_station->sibling);
956-
INIT_LIST_HEAD(&dock_station->hotplug_devices);
9571010
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
9581011
INIT_LIST_HEAD(&dock_station->dependent_devices);
9591012

@@ -993,30 +1046,6 @@ static int __init dock_add(acpi_handle handle)
9931046
return ret;
9941047
}
9951048

996-
/**
997-
* dock_remove - free up resources related to the dock station
998-
*/
999-
static int dock_remove(struct dock_station *ds)
1000-
{
1001-
struct dock_dependent_device *dd, *tmp;
1002-
struct platform_device *dock_device = ds->dock_device;
1003-
1004-
if (!dock_station_count)
1005-
return 0;
1006-
1007-
/* remove dependent devices */
1008-
list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list)
1009-
kfree(dd);
1010-
1011-
list_del(&ds->sibling);
1012-
1013-
/* cleanup sysfs */
1014-
sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group);
1015-
platform_device_unregister(dock_device);
1016-
1017-
return 0;
1018-
}
1019-
10201049
/**
10211050
* find_dock_and_bay - look for dock stations and bays
10221051
* @handle: acpi handle of a device
@@ -1035,7 +1064,7 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
10351064
return AE_OK;
10361065
}
10371066

1038-
static int __init dock_init(void)
1067+
int __init acpi_dock_init(void)
10391068
{
10401069
if (acpi_disabled)
10411070
return 0;
@@ -1054,19 +1083,3 @@ static int __init dock_init(void)
10541083
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
10551084
return 0;
10561085
}
1057-
1058-
static void __exit dock_exit(void)
1059-
{
1060-
struct dock_station *tmp, *dock_station;
1061-
1062-
unregister_acpi_bus_notifier(&dock_acpi_notifier);
1063-
list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
1064-
dock_remove(dock_station);
1065-
}
1066-
1067-
/*
1068-
* Must be called before drivers of devices in dock, otherwise we can't know
1069-
* which devices are in a dock
1070-
*/
1071-
subsys_initcall(dock_init);
1072-
module_exit(dock_exit);

drivers/acpi/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ void acpi_container_init(void);
4040
#else
4141
static inline void acpi_container_init(void) {}
4242
#endif
43+
#ifdef CONFIG_ACPI_DOCK
44+
void acpi_dock_init(void);
45+
#else
46+
static inline void acpi_dock_init(void) {}
47+
#endif
4348
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
4449
void acpi_memory_hotplug_init(void);
4550
#else

drivers/acpi/scan.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,7 @@ int __init acpi_scan_init(void)
20422042
acpi_lpss_init();
20432043
acpi_container_init();
20442044
acpi_memory_hotplug_init();
2045+
acpi_dock_init();
20452046

20462047
mutex_lock(&acpi_scan_lock);
20472048
/*

drivers/ata/libata-acpi.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,10 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
156156

157157
spin_unlock_irqrestore(ap->lock, flags);
158158

159-
if (wait)
159+
if (wait) {
160160
ata_port_wait_eh(ap);
161+
flush_work(&ap->hotplug_task.work);
162+
}
161163
}
162164

163165
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
@@ -214,6 +216,39 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
214216
.uevent = ata_acpi_ap_uevent,
215217
};
216218

219+
void ata_acpi_hotplug_init(struct ata_host *host)
220+
{
221+
int i;
222+
223+
for (i = 0; i < host->n_ports; i++) {
224+
struct ata_port *ap = host->ports[i];
225+
acpi_handle handle;
226+
struct ata_device *dev;
227+
228+
if (!ap)
229+
continue;
230+
231+
handle = ata_ap_acpi_handle(ap);
232+
if (handle) {
233+
/* we might be on a docking station */
234+
register_hotplug_dock_device(handle,
235+
&ata_acpi_ap_dock_ops, ap,
236+
NULL, NULL);
237+
}
238+
239+
ata_for_each_dev(dev, &ap->link, ALL) {
240+
handle = ata_dev_acpi_handle(dev);
241+
if (!handle)
242+
continue;
243+
244+
/* we might be on a docking station */
245+
register_hotplug_dock_device(handle,
246+
&ata_acpi_dev_dock_ops,
247+
dev, NULL, NULL);
248+
}
249+
}
250+
}
251+
217252
/**
218253
* ata_acpi_dissociate - dissociate ATA host from ACPI objects
219254
* @host: target ATA host

drivers/ata/libata-core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6148,6 +6148,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
61486148
if (rc)
61496149
goto err_tadd;
61506150

6151+
ata_acpi_hotplug_init(host);
6152+
61516153
/* set cable, sata_spd_limit and report */
61526154
for (i = 0; i < host->n_ports; i++) {
61536155
struct ata_port *ap = host->ports[i];

drivers/ata/libata.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ extern int ata_acpi_register(void);
122122
extern void ata_acpi_unregister(void);
123123
extern void ata_acpi_bind(struct ata_device *dev);
124124
extern void ata_acpi_unbind(struct ata_device *dev);
125+
extern void ata_acpi_hotplug_init(struct ata_host *host);
125126
#else
126127
static inline void ata_acpi_dissociate(struct ata_host *host) { }
127128
static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -134,6 +135,7 @@ static inline int ata_acpi_register(void) { return 0; }
134135
static inline void ata_acpi_unregister(void) { }
135136
static inline void ata_acpi_bind(struct ata_device *dev) { }
136137
static inline void ata_acpi_unbind(struct ata_device *dev) { }
138+
static inline void ata_acpi_hotplug_init(struct ata_host *host) {}
137139
#endif
138140

139141
/* libata-scsi.c */

0 commit comments

Comments
 (0)