mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
Merge branch 'acpi-hotplug'
* acpi-hotplug: ACPI / hotplug: Consolidate deferred execution of ACPI hotplug routines ACPI / hotplug: Do not execute "insert in progress" _OST ACPI / hotplug: Carry out PCI root eject directly ACPI / hotplug: Merge device hot-removal routines ACPI / hotplug: Make acpi_bus_hot_remove_device() internal ACPI / hotplug: Simplify device ejection routines ACPI / hotplug: Fix handle_root_bridge_removal() ACPI / hotplug: Refuse to hot-remove all objects with disabled hotplug ACPI / scan: Start matching drivers after trying scan handlers ACPI: Remove acpi_pci_slot_init() headers from internal.h Conflicts: include/acpi/acpiosxf.h (with the 'acpica' branch)
This commit is contained in:
commit
63ff4d0765
@ -669,39 +669,20 @@ static void dock_notify(struct dock_station *ds, u32 event)
|
||||
}
|
||||
}
|
||||
|
||||
struct dock_data {
|
||||
struct dock_station *ds;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
static void acpi_dock_deferred_cb(void *context)
|
||||
static void acpi_dock_deferred_cb(void *data, u32 event)
|
||||
{
|
||||
struct dock_data *data = context;
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
dock_notify(data->ds, data->event);
|
||||
dock_notify(data, event);
|
||||
acpi_scan_lock_release();
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct dock_data *dd;
|
||||
|
||||
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
|
||||
&& event != ACPI_NOTIFY_EJECT_REQUEST)
|
||||
return;
|
||||
|
||||
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
|
||||
if (dd) {
|
||||
acpi_status status;
|
||||
|
||||
dd->ds = data;
|
||||
dd->event = event;
|
||||
status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
|
||||
if (ACPI_FAILURE(status))
|
||||
kfree(dd);
|
||||
}
|
||||
acpi_hotplug_execute(acpi_dock_deferred_cb, data, event);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,11 +26,6 @@
|
||||
acpi_status acpi_os_initialize1(void);
|
||||
int init_acpi_device_notify(void);
|
||||
int acpi_scan_init(void);
|
||||
#ifdef CONFIG_ACPI_PCI_SLOT
|
||||
void acpi_pci_slot_init(void);
|
||||
#else
|
||||
static inline void acpi_pci_slot_init(void) { }
|
||||
#endif
|
||||
void acpi_pci_root_init(void);
|
||||
void acpi_pci_link_init(void);
|
||||
void acpi_pci_root_hp_init(void);
|
||||
@ -92,6 +87,7 @@ void acpi_device_add_finalize(struct acpi_device *device);
|
||||
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
|
||||
int acpi_bind_one(struct device *dev, acpi_handle handle);
|
||||
int acpi_unbind_one(struct device *dev);
|
||||
void acpi_bus_device_eject(void *data, u32 ost_src);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Power Resource
|
||||
|
@ -61,7 +61,6 @@ struct acpi_os_dpc {
|
||||
acpi_osd_exec_callback function;
|
||||
void *context;
|
||||
struct work_struct work;
|
||||
int wait;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
||||
@ -1087,9 +1086,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
|
||||
{
|
||||
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
|
||||
|
||||
if (dpc->wait)
|
||||
acpi_os_wait_events_complete();
|
||||
|
||||
dpc->function(dpc->context);
|
||||
kfree(dpc);
|
||||
}
|
||||
@ -1109,8 +1105,8 @@ static void acpi_os_execute_deferred(struct work_struct *work)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context, int hp)
|
||||
acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_os_dpc *dpc;
|
||||
@ -1137,20 +1133,11 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||
dpc->context = context;
|
||||
|
||||
/*
|
||||
* We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq
|
||||
* because the hotplug code may call driver .remove() functions,
|
||||
* which invoke flush_scheduled_work/acpi_os_wait_events_complete
|
||||
* to flush these workqueues.
|
||||
*
|
||||
* To prevent lockdep from complaining unnecessarily, make sure that
|
||||
* there is a different static lockdep key for each workqueue by using
|
||||
* INIT_WORK() for each of them separately.
|
||||
*/
|
||||
if (hp) {
|
||||
queue = kacpi_hotplug_wq;
|
||||
dpc->wait = 1;
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
} else if (type == OSL_NOTIFY_HANDLER) {
|
||||
if (type == OSL_NOTIFY_HANDLER) {
|
||||
queue = kacpi_notify_wq;
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
} else {
|
||||
@ -1175,28 +1162,59 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context)
|
||||
{
|
||||
return __acpi_os_execute(type, function, context, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_os_execute);
|
||||
|
||||
acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
|
||||
void *context)
|
||||
{
|
||||
return __acpi_os_execute(0, function, context, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_os_hotplug_execute);
|
||||
|
||||
void acpi_os_wait_events_complete(void)
|
||||
{
|
||||
flush_workqueue(kacpid_wq);
|
||||
flush_workqueue(kacpi_notify_wq);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_wait_events_complete);
|
||||
struct acpi_hp_work {
|
||||
struct work_struct work;
|
||||
acpi_hp_callback func;
|
||||
void *data;
|
||||
u32 src;
|
||||
};
|
||||
|
||||
static void acpi_hotplug_work_fn(struct work_struct *work)
|
||||
{
|
||||
struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work);
|
||||
|
||||
acpi_os_wait_events_complete();
|
||||
hpw->func(hpw->data, hpw->src);
|
||||
kfree(hpw);
|
||||
}
|
||||
|
||||
acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
|
||||
{
|
||||
struct acpi_hp_work *hpw;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Scheduling function [%p(%p, %u)] for deferred execution.\n",
|
||||
func, data, src));
|
||||
|
||||
hpw = kmalloc(sizeof(*hpw), GFP_KERNEL);
|
||||
if (!hpw)
|
||||
return AE_NO_MEMORY;
|
||||
|
||||
INIT_WORK(&hpw->work, acpi_hotplug_work_fn);
|
||||
hpw->func = func;
|
||||
hpw->data = data;
|
||||
hpw->src = src;
|
||||
/*
|
||||
* We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because
|
||||
* the hotplug code may call driver .remove() functions, which may
|
||||
* invoke flush_scheduled_work()/acpi_os_wait_events_complete() to flush
|
||||
* these workqueues.
|
||||
*/
|
||||
if (!queue_work(kacpi_hotplug_wq, &hpw->work)) {
|
||||
kfree(hpw);
|
||||
return AE_ERROR;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
|
||||
acpi_status
|
||||
acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
|
||||
@ -1845,25 +1863,3 @@ void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
|
||||
{
|
||||
__acpi_os_prepare_extended_sleep = func;
|
||||
}
|
||||
|
||||
|
||||
void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
|
||||
void (*func)(struct work_struct *work))
|
||||
{
|
||||
struct acpi_hp_work *hp_work;
|
||||
int ret;
|
||||
|
||||
hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
|
||||
if (!hp_work)
|
||||
return;
|
||||
|
||||
hp_work->handle = handle;
|
||||
hp_work->type = type;
|
||||
hp_work->context = context;
|
||||
|
||||
INIT_WORK(&hp_work->work, func);
|
||||
ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
|
||||
if (!ret)
|
||||
kfree(hp_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_acpi_hp_work);
|
||||
|
@ -39,6 +39,8 @@
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/apei.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define PREFIX "ACPI: "
|
||||
|
||||
#define _COMPONENT ACPI_PCI_COMPONENT
|
||||
@ -590,39 +592,10 @@ static void handle_root_bridge_insertion(acpi_handle handle)
|
||||
acpi_handle_err(handle, "cannot add bridge to acpi list\n");
|
||||
}
|
||||
|
||||
static void handle_root_bridge_removal(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_eject_event *ej_event;
|
||||
|
||||
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
|
||||
if (!ej_event) {
|
||||
/* Inform firmware the hot-remove operation has error */
|
||||
(void) acpi_evaluate_hotplug_ost(device->handle,
|
||||
ACPI_NOTIFY_EJECT_REQUEST,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ej_event->device = device;
|
||||
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
|
||||
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
|
||||
if (ACPI_FAILURE(status))
|
||||
kfree(ej_event);
|
||||
}
|
||||
|
||||
static void _handle_hotplug_event_root(struct work_struct *work)
|
||||
static void hotplug_event_root(void *data, u32 type)
|
||||
{
|
||||
acpi_handle handle = data;
|
||||
struct acpi_pci_root *root;
|
||||
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;
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
|
||||
@ -652,9 +625,15 @@ static void _handle_hotplug_event_root(struct work_struct *work)
|
||||
/* request device eject */
|
||||
acpi_handle_printk(KERN_DEBUG, handle,
|
||||
"Device eject notify on %s\n", __func__);
|
||||
if (root)
|
||||
handle_root_bridge_removal(root->device);
|
||||
break;
|
||||
if (!root)
|
||||
break;
|
||||
|
||||
get_device(&root->device->dev);
|
||||
|
||||
acpi_scan_lock_release();
|
||||
|
||||
acpi_bus_device_eject(root->device, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
return;
|
||||
default:
|
||||
acpi_handle_warn(handle,
|
||||
"notify_handler: unknown event type 0x%x\n",
|
||||
@ -663,14 +642,12 @@ static void _handle_hotplug_event_root(struct work_struct *work)
|
||||
}
|
||||
|
||||
acpi_scan_lock_release();
|
||||
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
|
||||
}
|
||||
|
||||
static void handle_hotplug_event_root(acpi_handle handle, u32 type,
|
||||
void *context)
|
||||
{
|
||||
alloc_acpi_hp_work(handle, type, context,
|
||||
_handle_hotplug_event_root);
|
||||
acpi_hotplug_execute(hotplug_event_root, handle, type);
|
||||
}
|
||||
|
||||
static acpi_status __init
|
||||
|
@ -125,8 +125,8 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
|
||||
}
|
||||
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
|
||||
|
||||
static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
|
||||
void *data, void **ret_p)
|
||||
static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data,
|
||||
void **ret_p)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_device_physical_node *pn;
|
||||
@ -136,6 +136,11 @@ static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
|
||||
if (acpi_bus_get_device(handle, &device))
|
||||
return AE_OK;
|
||||
|
||||
if (device->handler && !device->handler->hotplug.enabled) {
|
||||
*ret_p = &device->dev;
|
||||
return AE_SUPPORT;
|
||||
}
|
||||
|
||||
mutex_lock(&device->physical_node_lock);
|
||||
|
||||
list_for_each_entry(pn, &device->physical_node_list, node) {
|
||||
@ -168,8 +173,8 @@ static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl,
|
||||
void *data, void **ret_p)
|
||||
static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data,
|
||||
void **ret_p)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_device_physical_node *pn;
|
||||
@ -214,26 +219,32 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
* If the first pass is successful, the second one isn't needed, though.
|
||||
*/
|
||||
errdev = NULL;
|
||||
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
|
||||
NULL, acpi_bus_offline_companions,
|
||||
(void *)false, (void **)&errdev);
|
||||
acpi_bus_offline_companions(handle, 0, (void *)false, (void **)&errdev);
|
||||
status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
|
||||
NULL, acpi_bus_offline, (void *)false,
|
||||
(void **)&errdev);
|
||||
if (status == AE_SUPPORT) {
|
||||
dev_warn(errdev, "Offline disabled.\n");
|
||||
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
|
||||
acpi_bus_online, NULL, NULL, NULL);
|
||||
put_device(&device->dev);
|
||||
return -EPERM;
|
||||
}
|
||||
acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev);
|
||||
if (errdev) {
|
||||
errdev = NULL;
|
||||
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
|
||||
NULL, acpi_bus_offline_companions,
|
||||
(void *)true , (void **)&errdev);
|
||||
NULL, acpi_bus_offline, (void *)true,
|
||||
(void **)&errdev);
|
||||
if (!errdev || acpi_force_hot_remove)
|
||||
acpi_bus_offline_companions(handle, 0, (void *)true,
|
||||
(void **)&errdev);
|
||||
acpi_bus_offline(handle, 0, (void *)true,
|
||||
(void **)&errdev);
|
||||
|
||||
if (errdev && !acpi_force_hot_remove) {
|
||||
dev_warn(errdev, "Offline failed.\n");
|
||||
acpi_bus_online_companions(handle, 0, NULL, NULL);
|
||||
acpi_bus_online(handle, 0, NULL, NULL);
|
||||
acpi_walk_namespace(ACPI_TYPE_ANY, handle,
|
||||
ACPI_UINT32_MAX,
|
||||
acpi_bus_online_companions, NULL,
|
||||
NULL, NULL);
|
||||
ACPI_UINT32_MAX, acpi_bus_online,
|
||||
NULL, NULL, NULL);
|
||||
put_device(&device->dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -274,10 +285,10 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_bus_device_eject(void *context)
|
||||
void acpi_bus_device_eject(void *data, u32 ost_src)
|
||||
{
|
||||
acpi_handle handle = context;
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_device *device = data;
|
||||
acpi_handle handle = device->handle;
|
||||
struct acpi_scan_handler *handler;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
int error;
|
||||
@ -285,38 +296,41 @@ static void acpi_bus_device_eject(void *context)
|
||||
lock_device_hotplug();
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
acpi_bus_get_device(handle, &device);
|
||||
if (!device)
|
||||
goto err_out;
|
||||
|
||||
handler = device->handler;
|
||||
if (!handler || !handler->hotplug.enabled) {
|
||||
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
|
||||
goto err_out;
|
||||
put_device(&device->dev);
|
||||
goto err_support;
|
||||
}
|
||||
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
|
||||
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
|
||||
|
||||
if (ost_src == ACPI_NOTIFY_EJECT_REQUEST)
|
||||
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
|
||||
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
|
||||
|
||||
if (handler->hotplug.mode == AHM_CONTAINER)
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
|
||||
|
||||
get_device(&device->dev);
|
||||
error = acpi_scan_hot_remove(device);
|
||||
if (error)
|
||||
if (error == -EPERM) {
|
||||
goto err_support;
|
||||
} else if (error) {
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
unlock_device_hotplug();
|
||||
return;
|
||||
|
||||
err_support:
|
||||
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
|
||||
err_out:
|
||||
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
|
||||
NULL);
|
||||
acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
|
||||
static void acpi_scan_bus_device_check(void *data, u32 ost_source)
|
||||
{
|
||||
acpi_handle handle = data;
|
||||
struct acpi_device *device = NULL;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
int error;
|
||||
@ -331,8 +345,6 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
acpi_evaluate_hotplug_ost(handle, ost_source,
|
||||
ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
|
||||
error = acpi_bus_scan(handle);
|
||||
if (error) {
|
||||
acpi_handle_warn(handle, "Namespace scan failure\n");
|
||||
@ -353,18 +365,6 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
|
||||
unlock_device_hotplug();
|
||||
}
|
||||
|
||||
static void acpi_scan_bus_check(void *context)
|
||||
{
|
||||
acpi_scan_bus_device_check((acpi_handle)context,
|
||||
ACPI_NOTIFY_BUS_CHECK);
|
||||
}
|
||||
|
||||
static void acpi_scan_device_check(void *context)
|
||||
{
|
||||
acpi_scan_bus_device_check((acpi_handle)context,
|
||||
ACPI_NOTIFY_DEVICE_CHECK);
|
||||
}
|
||||
|
||||
static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
|
||||
{
|
||||
u32 ost_status;
|
||||
@ -395,8 +395,8 @@ static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
|
||||
|
||||
static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
acpi_osd_exec_callback callback;
|
||||
struct acpi_scan_handler *handler = data;
|
||||
struct acpi_device *adev;
|
||||
acpi_status status;
|
||||
|
||||
if (!handler->hotplug.enabled)
|
||||
@ -405,57 +405,36 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
|
||||
callback = acpi_scan_bus_check;
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
|
||||
callback = acpi_scan_device_check;
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
|
||||
callback = acpi_bus_device_eject;
|
||||
break;
|
||||
status = acpi_bus_get_device(handle, &adev);
|
||||
if (ACPI_FAILURE(status))
|
||||
goto err_out;
|
||||
|
||||
get_device(&adev->dev);
|
||||
status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return;
|
||||
|
||||
put_device(&adev->dev);
|
||||
goto err_out;
|
||||
default:
|
||||
/* non-hotplug event; possibly handled by other handler */
|
||||
return;
|
||||
}
|
||||
status = acpi_os_hotplug_execute(callback, handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
acpi_evaluate_hotplug_ost(handle, type,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
|
||||
NULL);
|
||||
status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return;
|
||||
|
||||
err_out:
|
||||
acpi_evaluate_hotplug_ost(handle, type,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_bus_hot_remove_device: hot-remove a device and its children
|
||||
* @context: struct acpi_eject_event pointer (freed in this func)
|
||||
*
|
||||
* Hot-remove a device and its children. This function frees up the
|
||||
* memory space passed by arg context, so that the caller may call
|
||||
* this function asynchronously through acpi_os_hotplug_execute().
|
||||
*/
|
||||
void acpi_bus_hot_remove_device(void *context)
|
||||
{
|
||||
struct acpi_eject_event *ej_event = context;
|
||||
struct acpi_device *device = ej_event->device;
|
||||
acpi_handle handle = device->handle;
|
||||
int error;
|
||||
|
||||
lock_device_hotplug();
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
error = acpi_scan_hot_remove(device);
|
||||
if (error && handle)
|
||||
acpi_evaluate_hotplug_ost(handle, ej_event->event,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
|
||||
NULL);
|
||||
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
unlock_device_hotplug();
|
||||
kfree(context);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
|
||||
|
||||
static ssize_t real_power_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -487,10 +466,8 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct acpi_device *acpi_device = to_acpi_device(d);
|
||||
struct acpi_eject_event *ej_event;
|
||||
acpi_object_type not_used;
|
||||
acpi_status status;
|
||||
int ret;
|
||||
|
||||
if (!count || buf[0] != '1')
|
||||
return -EINVAL;
|
||||
@ -503,28 +480,18 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
|
||||
if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
|
||||
return -ENODEV;
|
||||
|
||||
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
|
||||
if (!ej_event) {
|
||||
ret = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
|
||||
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
|
||||
ej_event->device = acpi_device;
|
||||
ej_event->event = ACPI_OST_EC_OSPM_EJECT;
|
||||
get_device(&acpi_device->dev);
|
||||
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
|
||||
status = acpi_hotplug_execute(acpi_bus_device_eject, acpi_device,
|
||||
ACPI_OST_EC_OSPM_EJECT);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return count;
|
||||
|
||||
put_device(&acpi_device->dev);
|
||||
kfree(ej_event);
|
||||
ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
|
||||
|
||||
err_out:
|
||||
acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
|
||||
return ret;
|
||||
return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
|
||||
@ -1676,7 +1643,6 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
||||
|
||||
void acpi_device_add_finalize(struct acpi_device *device)
|
||||
{
|
||||
device->flags.match_driver = true;
|
||||
dev_set_uevent_suppress(&device->dev, false);
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_ADD);
|
||||
}
|
||||
@ -1915,8 +1881,12 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
|
||||
return AE_OK;
|
||||
|
||||
ret = acpi_scan_attach_handler(device);
|
||||
if (ret)
|
||||
return ret > 0 ? AE_OK : AE_CTRL_DEPTH;
|
||||
if (ret < 0)
|
||||
return AE_CTRL_DEPTH;
|
||||
|
||||
device->flags.match_driver = true;
|
||||
if (ret > 0)
|
||||
return AE_OK;
|
||||
|
||||
ret = device_attach(&device->dev);
|
||||
return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
|
||||
|
@ -875,21 +875,17 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
put_bridge(bridge);
|
||||
}
|
||||
|
||||
static void hotplug_event_work(struct work_struct *work)
|
||||
static void hotplug_event_work(void *data, u32 type)
|
||||
{
|
||||
struct acpiphp_context *context;
|
||||
struct acpi_hp_work *hp_work;
|
||||
struct acpiphp_context *context = data;
|
||||
acpi_handle handle = context->handle;
|
||||
|
||||
hp_work = container_of(work, struct acpi_hp_work, work);
|
||||
context = hp_work->context;
|
||||
acpi_scan_lock_acquire();
|
||||
|
||||
hotplug_event(hp_work->handle, hp_work->type, context);
|
||||
hotplug_event(handle, type, context);
|
||||
|
||||
acpi_scan_lock_release();
|
||||
acpi_evaluate_hotplug_ost(hp_work->handle, hp_work->type,
|
||||
ACPI_OST_SC_SUCCESS, NULL);
|
||||
kfree(hp_work); /* allocated in handle_hotplug_event() */
|
||||
acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
|
||||
put_bridge(context->func.parent);
|
||||
}
|
||||
|
||||
@ -940,10 +936,10 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
|
||||
mutex_lock(&acpiphp_context_lock);
|
||||
context = acpiphp_get_context(handle);
|
||||
if (context) {
|
||||
if (context && !WARN_ON(context->handle != handle)) {
|
||||
get_bridge(context->func.parent);
|
||||
acpiphp_put_context(context);
|
||||
alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
|
||||
acpi_hotplug_execute(hotplug_event_work, context, type);
|
||||
mutex_unlock(&acpiphp_context_lock);
|
||||
return;
|
||||
}
|
||||
|
@ -339,20 +339,6 @@ struct acpi_bus_event {
|
||||
u32 data;
|
||||
};
|
||||
|
||||
struct acpi_eject_event {
|
||||
struct acpi_device *device;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
struct acpi_hp_work {
|
||||
struct work_struct work;
|
||||
acpi_handle handle;
|
||||
u32 type;
|
||||
void *context;
|
||||
};
|
||||
void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
|
||||
void (*func)(struct work_struct *work));
|
||||
|
||||
extern struct kobject *acpi_kobj;
|
||||
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
|
||||
void acpi_bus_private_data_handler(acpi_handle, void *);
|
||||
@ -391,7 +377,6 @@ int acpi_scan_add_handler(struct acpi_scan_handler *handler);
|
||||
int acpi_bus_register_driver(struct acpi_driver *driver);
|
||||
void acpi_bus_unregister_driver(struct acpi_driver *driver);
|
||||
int acpi_bus_scan(acpi_handle handle);
|
||||
void acpi_bus_hot_remove_device(void *context);
|
||||
void acpi_bus_trim(struct acpi_device *start);
|
||||
acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
|
||||
int acpi_match_device_ids(struct acpi_device *device,
|
||||
@ -399,6 +384,9 @@ int acpi_match_device_ids(struct acpi_device *device,
|
||||
int acpi_create_dir(struct acpi_device *);
|
||||
void acpi_remove_dir(struct acpi_device *);
|
||||
|
||||
typedef void (*acpi_hp_callback)(void *data, u32 src);
|
||||
|
||||
acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src);
|
||||
|
||||
/**
|
||||
* module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
|
||||
|
@ -243,9 +243,6 @@ void acpi_os_gpe_count(u32 gpe_number);
|
||||
|
||||
void acpi_os_fixed_event_count(u32 fixed_event_number);
|
||||
|
||||
acpi_status
|
||||
acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __ACLINUX_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user