Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 15 additions & 26 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#define pr_fmt(fmt) "ACPI: " fmt

#include <linux/async.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
Expand Down Expand Up @@ -2358,46 +2359,34 @@ static int acpi_dev_get_next_consumer_dev_cb(struct acpi_dep_data *dep, void *da
return 0;
}

struct acpi_scan_clear_dep_work {
struct work_struct work;
struct acpi_device *adev;
};

static void acpi_scan_clear_dep_fn(struct work_struct *work)
static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
{
struct acpi_scan_clear_dep_work *cdw;

cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
struct acpi_device *adev = to_acpi_device(dev);

acpi_scan_lock_acquire();
acpi_bus_attach(cdw->adev, (void *)true);
acpi_bus_attach(adev, (void *)true);
acpi_scan_lock_release();

acpi_dev_put(cdw->adev);
kfree(cdw);
acpi_dev_put(adev);
}

static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
{
struct acpi_scan_clear_dep_work *cdw;

if (adev->dep_unmet)
return false;

cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
if (!cdw)
return false;

cdw->adev = adev;
INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
/*
* Since the work function may block on the lock until the entire
* initial enumeration of devices is complete, put it into the unbound
* workqueue.
* Async schedule the deferred acpi_scan_clear_dep_fn() since:
* - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
* be acquired under acpi_dep_list_lock (held here)
* - the deferred work at boot stage is ensured to be finished
* before userspace init task by the async_synchronize_full()
* barrier
*
* Use _nocall variant since it'll return on failure instead of
* run the function synchronously.
*/
queue_work(system_unbound_wq, &cdw->work);

return true;
return async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev);
}

static void acpi_scan_delete_dep_data(struct acpi_dep_data *dep)
Expand Down
Loading