Skip to content

Commit

Permalink
Merge branch 'acpi-hotplug'
Browse files Browse the repository at this point in the history
* 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)
  • Loading branch information
Rafael J. Wysocki committed Nov 7, 2013
2 parents 679d998 + 7b98118 commit 63ff4d0
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 246 deletions.
25 changes: 3 additions & 22 deletions drivers/acpi/dock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
6 changes: 1 addition & 5 deletions drivers/acpi/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
96 changes: 46 additions & 50 deletions drivers/acpi/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
Expand All @@ -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 {
Expand All @@ -1175,28 +1162,59 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
}
return status;
}
EXPORT_SYMBOL(acpi_os_execute);

acpi_status acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context)
void acpi_os_wait_events_complete(void)
{
return __acpi_os_execute(type, function, context, 0);
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
}
EXPORT_SYMBOL(acpi_os_execute);

acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
void *context)
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)
{
return __acpi_os_execute(0, function, context, 1);
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);
}
EXPORT_SYMBOL(acpi_os_hotplug_execute);

void acpi_os_wait_events_complete(void)
acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
{
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
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;
}

EXPORT_SYMBOL(acpi_os_wait_events_complete);

acpi_status
acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
Expand Down Expand Up @@ -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);
51 changes: 14 additions & 37 deletions drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/apei.h>

#include "internal.h"

#define PREFIX "ACPI: "

#define _COMPONENT ACPI_PCI_COMPONENT
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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",
Expand All @@ -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
Expand Down
Loading

0 comments on commit 63ff4d0

Please sign in to comment.