mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge branch 'acpi-bus'
Merge ACPI device object management changes for v5.20-rc1. - Use the facilities provided by the driver core and some additional helpers to handle the children of a given ACPI device object in multiple places instead of using the children and node list heads in struct acpi_device which is error prone (Rafael Wysocki). - Fix ACPI-related device reference counting issue in the hisi_lpc bus driver (Yang Yingliang). - Drop the children and node list heads that are not needed any more from struct acpi_device (Rafael Wysocki). - Drop driver member from struct acpi_device (Uwe Kleine-König). - Drop redundant check from acpi_device_remove() (Uwe Kleine-König). * acpi-bus: ACPI: bus: Drop unused list heads from struct acpi_device hisi_lpc: Use acpi_dev_for_each_child() bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe() ACPI: bus: Drop driver member of struct acpi_device ACPI: bus: Drop redundant check in acpi_device_remove() mfd: core: Use acpi_dev_for_each_child() ACPI / MMC: PM: Unify fixing up device power soundwire: Use acpi_dev_for_each_child() platform/x86/thinkpad_acpi: Use acpi_dev_for_each_child() ACPI: scan: Walk ACPI device's children using driver core ACPI: bus: Introduce acpi_dev_for_each_child_reverse() ACPI: video: Use acpi_dev_for_each_child() ACPI: bus: Export acpi_dev_for_each_child() to modules ACPI: property: Use acpi_dev_for_each_child() for child lookup ACPI: container: Use acpi_dev_for_each_child() USB: ACPI: Replace usb_acpi_find_port() with acpi_find_child_by_adr() thunderbolt: ACPI: Replace tb_acpi_find_port() with acpi_find_child_by_adr() ACPI: glue: Introduce acpi_find_child_by_adr() ACPI: glue: Introduce acpi_dev_has_children() ACPI: glue: Use acpi_dev_for_each_child()
This commit is contained in:
commit
d60b6b0bc0
@ -1150,24 +1150,25 @@ acpi_video_get_device_type(struct acpi_video_bus *video,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
struct acpi_video_bus *video)
|
||||
static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg)
|
||||
{
|
||||
unsigned long long device_id;
|
||||
int status, device_type;
|
||||
struct acpi_video_device *data;
|
||||
struct acpi_video_bus *video = arg;
|
||||
struct acpi_video_device_attrib *attribute;
|
||||
struct acpi_video_device *data;
|
||||
unsigned long long device_id;
|
||||
acpi_status status;
|
||||
int device_type;
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
|
||||
/* Some device omits _ADR, we skip them instead of fail */
|
||||
status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
|
||||
/* Skip devices without _ADR instead of failing. */
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
goto exit;
|
||||
|
||||
data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
|
||||
if (!data)
|
||||
if (!data) {
|
||||
dev_dbg(&device->dev, "Cannot attach\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
|
||||
@ -1230,7 +1231,9 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
list_add_tail(&data->entry, &video->video_device_list);
|
||||
mutex_unlock(&video->device_list_lock);
|
||||
|
||||
return status;
|
||||
exit:
|
||||
video->child_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1542,9 +1545,6 @@ static int
|
||||
acpi_video_bus_get_devices(struct acpi_video_bus *video,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
int status = 0;
|
||||
struct acpi_device *dev;
|
||||
|
||||
/*
|
||||
* There are systems where video module known to work fine regardless
|
||||
* of broken _DOD and ignoring returned value here doesn't cause
|
||||
@ -1552,16 +1552,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
|
||||
*/
|
||||
acpi_video_device_enumerate(video);
|
||||
|
||||
list_for_each_entry(dev, &device->children, node) {
|
||||
|
||||
status = acpi_video_bus_get_one_device(dev, video);
|
||||
if (status) {
|
||||
dev_err(&dev->dev, "Can't attach device\n");
|
||||
break;
|
||||
}
|
||||
video->child_count++;
|
||||
}
|
||||
return status;
|
||||
return acpi_dev_for_each_child(device, acpi_video_bus_get_one_device, video);
|
||||
}
|
||||
|
||||
/* acpi_video interface */
|
||||
|
@ -464,7 +464,6 @@ out_free:
|
||||
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
struct acpi_driver *driver;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
bool hotplug_event = false;
|
||||
|
||||
@ -516,10 +515,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
if (!adev)
|
||||
goto err;
|
||||
|
||||
driver = adev->driver;
|
||||
if (driver && driver->ops.notify &&
|
||||
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
|
||||
driver->ops.notify(adev, type);
|
||||
if (adev->dev.driver) {
|
||||
struct acpi_driver *driver = to_acpi_driver(adev->dev.driver);
|
||||
|
||||
if (driver && driver->ops.notify &&
|
||||
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
|
||||
driver->ops.notify(adev, type);
|
||||
}
|
||||
|
||||
if (!hotplug_event) {
|
||||
acpi_bus_put_acpi_device(adev);
|
||||
@ -538,8 +540,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_device *device = data;
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver);
|
||||
|
||||
device->driver->ops.notify(device, event);
|
||||
acpi_drv->ops.notify(device, event);
|
||||
}
|
||||
|
||||
static void acpi_notify_device_fixed(void *data)
|
||||
@ -1032,8 +1035,6 @@ static int acpi_device_probe(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
acpi_dev->driver = acpi_drv;
|
||||
|
||||
pr_debug("Driver [%s] successfully bound to device [%s]\n",
|
||||
acpi_drv->name, acpi_dev->pnp.bus_id);
|
||||
|
||||
@ -1043,7 +1044,6 @@ static int acpi_device_probe(struct device *dev)
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
|
||||
acpi_dev->driver = NULL;
|
||||
acpi_dev->driver_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
@ -1059,15 +1059,14 @@ static int acpi_device_probe(struct device *dev)
|
||||
static void acpi_device_remove(struct device *dev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
struct acpi_driver *acpi_drv = acpi_dev->driver;
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
|
||||
|
||||
if (acpi_drv->ops.notify)
|
||||
acpi_device_remove_notify_handler(acpi_dev);
|
||||
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
|
||||
if (acpi_drv) {
|
||||
if (acpi_drv->ops.notify)
|
||||
acpi_device_remove_notify_handler(acpi_dev);
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
}
|
||||
acpi_dev->driver = NULL;
|
||||
acpi_dev->driver_data = NULL;
|
||||
|
||||
put_device(dev);
|
||||
@ -1101,6 +1100,7 @@ static int acpi_dev_for_one_check(struct device *dev, void *context)
|
||||
|
||||
return adwc->fn(to_acpi_device(dev), adwc->data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_for_each_child);
|
||||
|
||||
int acpi_dev_for_each_child(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *), void *data)
|
||||
@ -1113,6 +1113,18 @@ int acpi_dev_for_each_child(struct acpi_device *adev,
|
||||
return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check);
|
||||
}
|
||||
|
||||
int acpi_dev_for_each_child_reverse(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *),
|
||||
void *data)
|
||||
{
|
||||
struct acpi_dev_walk_context adwc = {
|
||||
.fn = fn,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
return device_for_each_child_reverse(&adev->dev, &adwc, acpi_dev_for_one_check);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Initialization/Cleanup
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -23,17 +23,18 @@ static const struct acpi_device_id container_device_ids[] = {
|
||||
|
||||
#ifdef CONFIG_ACPI_CONTAINER
|
||||
|
||||
static int check_offline(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
if (acpi_scan_is_offline(adev, false))
|
||||
return 0;
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int acpi_container_offline(struct container_dev *cdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
|
||||
struct acpi_device *child;
|
||||
|
||||
/* Check all of the dependent devices' physical companions. */
|
||||
list_for_each_entry(child, &adev->children, node)
|
||||
if (!acpi_scan_is_offline(child, false))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL);
|
||||
}
|
||||
|
||||
static void acpi_container_release(struct device *dev)
|
||||
|
@ -369,6 +369,28 @@ int acpi_device_fix_up_power(struct acpi_device *device)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_device_fix_up_power);
|
||||
|
||||
static int fix_up_power_if_applicable(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
if (adev->status.present && adev->status.enabled)
|
||||
acpi_device_fix_up_power(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_device_fix_up_power_extended - Force device and its children into D0.
|
||||
* @adev: Parent device object whose power state is to be fixed up.
|
||||
*
|
||||
* Call acpi_device_fix_up_power() for @adev and its children so long as they
|
||||
* are reported as present and enabled.
|
||||
*/
|
||||
void acpi_device_fix_up_power_extended(struct acpi_device *adev)
|
||||
{
|
||||
acpi_device_fix_up_power(adev);
|
||||
acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended);
|
||||
|
||||
int acpi_device_update_power(struct acpi_device *device, int *state_p)
|
||||
{
|
||||
int state;
|
||||
|
@ -376,7 +376,7 @@ eject_store(struct device *d, struct device_attribute *attr,
|
||||
return -EINVAL;
|
||||
|
||||
if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
|
||||
&& !acpi_device->driver)
|
||||
&& !d->driver)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_get_type(acpi_device->handle, ¬_used);
|
||||
|
@ -77,12 +77,22 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
|
||||
#define FIND_CHILD_MIN_SCORE 1
|
||||
#define FIND_CHILD_MAX_SCORE 2
|
||||
|
||||
static int match_any(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool acpi_dev_has_children(struct acpi_device *adev)
|
||||
{
|
||||
return acpi_dev_for_each_child(adev, match_any, NULL) > 0;
|
||||
}
|
||||
|
||||
static int find_child_checks(struct acpi_device *adev, bool check_children)
|
||||
{
|
||||
unsigned long long sta;
|
||||
acpi_status status;
|
||||
|
||||
if (check_children && list_empty(&adev->children))
|
||||
if (check_children && !acpi_dev_has_children(adev))
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
|
||||
@ -105,54 +115,97 @@ static int find_child_checks(struct acpi_device *adev, bool check_children)
|
||||
return FIND_CHILD_MAX_SCORE;
|
||||
}
|
||||
|
||||
struct find_child_walk_data {
|
||||
struct acpi_device *adev;
|
||||
u64 address;
|
||||
int score;
|
||||
bool check_sta;
|
||||
bool check_children;
|
||||
};
|
||||
|
||||
static int check_one_child(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct find_child_walk_data *wd = data;
|
||||
int score;
|
||||
|
||||
if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address)
|
||||
return 0;
|
||||
|
||||
if (!wd->adev) {
|
||||
/*
|
||||
* This is the first matching object, so save it. If it is not
|
||||
* necessary to look for any other matching objects, stop the
|
||||
* search.
|
||||
*/
|
||||
wd->adev = adev;
|
||||
return !(wd->check_sta || wd->check_children);
|
||||
}
|
||||
|
||||
/*
|
||||
* There is more than one matching device object with the same _ADR
|
||||
* value. That really is unexpected, so we are kind of beyond the scope
|
||||
* of the spec here. We have to choose which one to return, though.
|
||||
*
|
||||
* First, get the score for the previously found object and terminate
|
||||
* the walk if it is maximum.
|
||||
*/
|
||||
if (!wd->score) {
|
||||
score = find_child_checks(wd->adev, wd->check_children);
|
||||
if (score == FIND_CHILD_MAX_SCORE)
|
||||
return 1;
|
||||
|
||||
wd->score = score;
|
||||
}
|
||||
/*
|
||||
* Second, if the object that has just been found has a better score,
|
||||
* replace the previously found one with it and terminate the walk if
|
||||
* the new score is maximum.
|
||||
*/
|
||||
score = find_child_checks(adev, wd->check_children);
|
||||
if (score > wd->score) {
|
||||
wd->adev = adev;
|
||||
if (score == FIND_CHILD_MAX_SCORE)
|
||||
return 1;
|
||||
|
||||
wd->score = score;
|
||||
}
|
||||
|
||||
/* Continue, because there may be better matches. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct acpi_device *acpi_find_child(struct acpi_device *parent,
|
||||
u64 address, bool check_children,
|
||||
bool check_sta)
|
||||
{
|
||||
struct find_child_walk_data wd = {
|
||||
.address = address,
|
||||
.check_children = check_children,
|
||||
.check_sta = check_sta,
|
||||
.adev = NULL,
|
||||
.score = 0,
|
||||
};
|
||||
|
||||
if (parent)
|
||||
acpi_dev_for_each_child(parent, check_one_child, &wd);
|
||||
|
||||
return wd.adev;
|
||||
}
|
||||
|
||||
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
|
||||
u64 address, bool check_children)
|
||||
{
|
||||
struct acpi_device *adev, *ret = NULL;
|
||||
int ret_score = 0;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(adev, &parent->children, node) {
|
||||
acpi_bus_address addr = acpi_device_adr(adev);
|
||||
int score;
|
||||
|
||||
if (!adev->pnp.type.bus_address || addr != address)
|
||||
continue;
|
||||
|
||||
if (!ret) {
|
||||
/* This is the first matching object. Save it. */
|
||||
ret = adev;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* There is more than one matching device object with the same
|
||||
* _ADR value. That really is unexpected, so we are kind of
|
||||
* beyond the scope of the spec here. We have to choose which
|
||||
* one to return, though.
|
||||
*
|
||||
* First, check if the previously found object is good enough
|
||||
* and return it if so. Second, do the same for the object that
|
||||
* we've just found.
|
||||
*/
|
||||
if (!ret_score) {
|
||||
ret_score = find_child_checks(ret, check_children);
|
||||
if (ret_score == FIND_CHILD_MAX_SCORE)
|
||||
return ret;
|
||||
}
|
||||
score = find_child_checks(adev, check_children);
|
||||
if (score == FIND_CHILD_MAX_SCORE) {
|
||||
return adev;
|
||||
} else if (score > ret_score) {
|
||||
ret = adev;
|
||||
ret_score = score;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return acpi_find_child(parent, address, check_children, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_find_child_device);
|
||||
|
||||
struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
|
||||
acpi_bus_address adr)
|
||||
{
|
||||
return acpi_find_child(adev, adr, false, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_find_child_by_adr);
|
||||
|
||||
static void acpi_physnode_link_name(char *buf, unsigned int node_id)
|
||||
{
|
||||
if (node_id > 0)
|
||||
|
@ -1012,6 +1012,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode,
|
||||
propname, proptype, val, nval);
|
||||
}
|
||||
|
||||
static int stop_on_next(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct acpi_device **ret_p = data;
|
||||
|
||||
if (!*ret_p) {
|
||||
*ret_p = adev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Skip until the "previous" object is found. */
|
||||
if (*ret_p == adev)
|
||||
*ret_p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_get_next_subnode - Return the next child node handle for a fwnode
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
@ -1020,35 +1036,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
const struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
const struct list_head *head;
|
||||
struct list_head *next;
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
|
||||
if ((!child || is_acpi_device_node(child)) && adev) {
|
||||
struct acpi_device *child_adev;
|
||||
struct acpi_device *child_adev = to_acpi_device_node(child);
|
||||
|
||||
head = &adev->children;
|
||||
if (list_empty(head))
|
||||
goto nondev;
|
||||
acpi_dev_for_each_child(adev, stop_on_next, &child_adev);
|
||||
if (child_adev)
|
||||
return acpi_fwnode_handle(child_adev);
|
||||
|
||||
if (child) {
|
||||
adev = to_acpi_device_node(child);
|
||||
next = adev->node.next;
|
||||
if (next == head) {
|
||||
child = NULL;
|
||||
goto nondev;
|
||||
}
|
||||
child_adev = list_entry(next, struct acpi_device, node);
|
||||
} else {
|
||||
child_adev = list_first_entry(head, struct acpi_device,
|
||||
node);
|
||||
}
|
||||
return acpi_fwnode_handle(child_adev);
|
||||
child = NULL;
|
||||
}
|
||||
|
||||
nondev:
|
||||
if (!child || is_acpi_data_node(child)) {
|
||||
const struct acpi_data_node *data = to_acpi_data_node(fwnode);
|
||||
const struct list_head *head;
|
||||
struct list_head *next;
|
||||
struct acpi_data_node *dn;
|
||||
|
||||
/*
|
||||
|
@ -334,10 +334,9 @@ static int acpi_scan_device_check(struct acpi_device *adev)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int acpi_scan_bus_check(struct acpi_device *adev)
|
||||
static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_scan_handler *handler = adev->handler;
|
||||
struct acpi_device *child;
|
||||
int error;
|
||||
|
||||
acpi_bus_get_status(adev);
|
||||
@ -353,19 +352,14 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
|
||||
dev_warn(&adev->dev, "Namespace scan failure\n");
|
||||
return error;
|
||||
}
|
||||
list_for_each_entry(child, &adev->children, node) {
|
||||
error = acpi_scan_bus_check(child);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return 0;
|
||||
return acpi_dev_for_each_child(adev, acpi_scan_bus_check, NULL);
|
||||
}
|
||||
|
||||
static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
|
||||
{
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
return acpi_scan_bus_check(adev);
|
||||
return acpi_scan_bus_check(adev, NULL);
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
return acpi_scan_device_check(adev);
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
@ -471,8 +465,6 @@ static void acpi_device_del(struct acpi_device *device)
|
||||
struct acpi_device_bus_id *acpi_device_bus_id;
|
||||
|
||||
mutex_lock(&acpi_device_lock);
|
||||
if (device->parent)
|
||||
list_del(&device->node);
|
||||
|
||||
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
|
||||
if (!strcmp(acpi_device_bus_id->bus_id,
|
||||
@ -488,6 +480,7 @@ static void acpi_device_del(struct acpi_device *device)
|
||||
}
|
||||
|
||||
list_del(&device->wakeup_list);
|
||||
|
||||
mutex_unlock(&acpi_device_lock);
|
||||
|
||||
acpi_power_add_remove_device(device, false);
|
||||
@ -680,8 +673,6 @@ static int __acpi_device_add(struct acpi_device *device,
|
||||
* -------
|
||||
* Link this device to its parent and siblings.
|
||||
*/
|
||||
INIT_LIST_HEAD(&device->children);
|
||||
INIT_LIST_HEAD(&device->node);
|
||||
INIT_LIST_HEAD(&device->wakeup_list);
|
||||
INIT_LIST_HEAD(&device->physical_node_list);
|
||||
INIT_LIST_HEAD(&device->del_list);
|
||||
@ -721,9 +712,6 @@ static int __acpi_device_add(struct acpi_device *device,
|
||||
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
|
||||
}
|
||||
|
||||
if (device->parent)
|
||||
list_add_tail(&device->node, &device->parent->children);
|
||||
|
||||
if (device->wakeup.flags.valid)
|
||||
list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
|
||||
|
||||
@ -752,9 +740,6 @@ static int __acpi_device_add(struct acpi_device *device,
|
||||
err:
|
||||
mutex_lock(&acpi_device_lock);
|
||||
|
||||
if (device->parent)
|
||||
list_del(&device->node);
|
||||
|
||||
list_del(&device->wakeup_list);
|
||||
|
||||
err_unlock:
|
||||
@ -2187,9 +2172,8 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
|
||||
{
|
||||
struct acpi_device *child;
|
||||
bool skip = !first_pass && device->flags.visited;
|
||||
acpi_handle ejd;
|
||||
int ret;
|
||||
@ -2206,7 +2190,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
device->flags.initialized = false;
|
||||
acpi_device_clear_enumerated(device);
|
||||
device->flags.power_manageable = 0;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (device->handler)
|
||||
goto ok;
|
||||
@ -2224,7 +2208,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
|
||||
ret = acpi_scan_attach_handler(device);
|
||||
if (ret < 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
device->flags.match_driver = true;
|
||||
if (ret > 0 && !device->flags.enumeration_by_parent) {
|
||||
@ -2234,19 +2218,20 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
|
||||
ret = device_attach(&device->dev);
|
||||
if (ret < 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (device->pnp.type.platform_id || device->flags.enumeration_by_parent)
|
||||
acpi_default_enumeration(device);
|
||||
else
|
||||
acpi_device_set_enumerated(device);
|
||||
|
||||
ok:
|
||||
list_for_each_entry(child, &device->children, node)
|
||||
acpi_bus_attach(child, first_pass);
|
||||
ok:
|
||||
acpi_dev_for_each_child(device, acpi_bus_attach, first_pass);
|
||||
|
||||
if (!skip && device->handler && device->handler->hotplug.notify_online)
|
||||
device->handler->hotplug.notify_online(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_dev_get_first_consumer_dev_cb(struct acpi_dep_data *dep, void *data)
|
||||
@ -2274,7 +2259,7 @@ static void acpi_scan_clear_dep_fn(struct work_struct *work)
|
||||
cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
acpi_bus_attach(cdw->adev, true);
|
||||
acpi_bus_attach(cdw->adev, (void *)true);
|
||||
acpi_scan_lock_release();
|
||||
|
||||
acpi_dev_put(cdw->adev);
|
||||
@ -2432,7 +2417,7 @@ int acpi_bus_scan(acpi_handle handle)
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
acpi_bus_attach(device, true);
|
||||
acpi_bus_attach(device, (void *)true);
|
||||
|
||||
if (!acpi_bus_scan_second_pass)
|
||||
return 0;
|
||||
@ -2446,25 +2431,17 @@ int acpi_bus_scan(acpi_handle handle)
|
||||
acpi_bus_check_add_2, NULL, NULL,
|
||||
(void **)&device);
|
||||
|
||||
acpi_bus_attach(device, false);
|
||||
acpi_bus_attach(device, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_scan);
|
||||
|
||||
/**
|
||||
* acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
|
||||
* @adev: Root of the ACPI namespace scope to walk.
|
||||
*
|
||||
* Must be called under acpi_scan_lock.
|
||||
*/
|
||||
void acpi_bus_trim(struct acpi_device *adev)
|
||||
static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_scan_handler *handler = adev->handler;
|
||||
struct acpi_device *child;
|
||||
|
||||
list_for_each_entry_reverse(child, &adev->children, node)
|
||||
acpi_bus_trim(child);
|
||||
acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL);
|
||||
|
||||
adev->flags.match_driver = false;
|
||||
if (handler) {
|
||||
@ -2482,6 +2459,19 @@ void acpi_bus_trim(struct acpi_device *adev)
|
||||
acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
|
||||
adev->flags.initialized = false;
|
||||
acpi_device_clear_enumerated(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
|
||||
* @adev: Root of the ACPI namespace scope to walk.
|
||||
*
|
||||
* Must be called under acpi_scan_lock.
|
||||
*/
|
||||
void acpi_bus_trim(struct acpi_device *adev)
|
||||
{
|
||||
acpi_bus_trim_one(adev, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_bus_trim);
|
||||
|
||||
|
@ -379,7 +379,7 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
|
||||
|
||||
/*
|
||||
* hisi_lpc_acpi_set_io_res - set the resources for a child
|
||||
* @child: the device node to be updated the I/O resource
|
||||
* @adev: ACPI companion of the device node to be updated the I/O resource
|
||||
* @hostdev: the device node associated with host controller
|
||||
* @res: double pointer to be set to the address of translated resources
|
||||
* @num_res: pointer to variable to hold the number of translated resources
|
||||
@ -390,31 +390,24 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
|
||||
* host-relative address resource. This function will return the translated
|
||||
* logical PIO addresses for each child devices resources.
|
||||
*/
|
||||
static int hisi_lpc_acpi_set_io_res(struct device *child,
|
||||
static int hisi_lpc_acpi_set_io_res(struct acpi_device *adev,
|
||||
struct device *hostdev,
|
||||
const struct resource **res, int *num_res)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
struct acpi_device *host;
|
||||
struct acpi_device *host = to_acpi_device(adev->dev.parent);
|
||||
struct resource_entry *rentry;
|
||||
LIST_HEAD(resource_list);
|
||||
struct resource *resources;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if (!child || !hostdev)
|
||||
return -EINVAL;
|
||||
|
||||
host = to_acpi_device(hostdev);
|
||||
adev = to_acpi_device(child);
|
||||
|
||||
if (!adev->status.present) {
|
||||
dev_dbg(child, "device is not present\n");
|
||||
dev_dbg(&adev->dev, "device is not present\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (acpi_device_enumerated(adev)) {
|
||||
dev_dbg(child, "has been enumerated\n");
|
||||
dev_dbg(&adev->dev, "has been enumerated\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -425,7 +418,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child,
|
||||
*/
|
||||
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
|
||||
if (count <= 0) {
|
||||
dev_dbg(child, "failed to get resources\n");
|
||||
dev_dbg(&adev->dev, "failed to get resources\n");
|
||||
return count ? count : -EIO;
|
||||
}
|
||||
|
||||
@ -454,7 +447,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child,
|
||||
continue;
|
||||
ret = hisi_lpc_acpi_xlat_io_res(adev, host, &resources[i]);
|
||||
if (ret) {
|
||||
dev_err(child, "translate IO range %pR failed (%d)\n",
|
||||
dev_err(&adev->dev, "translate IO range %pR failed (%d)\n",
|
||||
&resources[i], ret);
|
||||
return ret;
|
||||
}
|
||||
@ -471,6 +464,12 @@ static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_lpc_acpi_clear_enumerated(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
acpi_device_clear_enumerated(adev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hisi_lpc_acpi_cell {
|
||||
const char *hid;
|
||||
const char *name;
|
||||
@ -480,13 +479,92 @@ struct hisi_lpc_acpi_cell {
|
||||
|
||||
static void hisi_lpc_acpi_remove(struct device *hostdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(hostdev);
|
||||
struct acpi_device *child;
|
||||
|
||||
device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev);
|
||||
acpi_dev_for_each_child(ACPI_COMPANION(hostdev),
|
||||
hisi_lpc_acpi_clear_enumerated, NULL);
|
||||
}
|
||||
|
||||
list_for_each_entry(child, &adev->children, node)
|
||||
acpi_device_clear_enumerated(child);
|
||||
static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
|
||||
{
|
||||
const char *hid = acpi_device_hid(child);
|
||||
struct device *hostdev = data;
|
||||
const struct hisi_lpc_acpi_cell *cell;
|
||||
struct platform_device *pdev;
|
||||
const struct resource *res;
|
||||
bool found = false;
|
||||
int num_res;
|
||||
int ret;
|
||||
|
||||
ret = hisi_lpc_acpi_set_io_res(child, hostdev, &res, &num_res);
|
||||
if (ret) {
|
||||
dev_warn(hostdev, "set resource fail (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cell = (struct hisi_lpc_acpi_cell []){
|
||||
/* ipmi */
|
||||
{
|
||||
.hid = "IPI0001",
|
||||
.name = "hisi-lpc-ipmi",
|
||||
},
|
||||
/* 8250-compatible uart */
|
||||
{
|
||||
.hid = "HISI1031",
|
||||
.name = "serial8250",
|
||||
.pdata = (struct plat_serial8250_port []) {
|
||||
{
|
||||
.iobase = res->start,
|
||||
.uartclk = 1843200,
|
||||
.iotype = UPIO_PORT,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
},
|
||||
{}
|
||||
},
|
||||
.pdata_size = 2 *
|
||||
sizeof(struct plat_serial8250_port),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
for (; cell && cell->name; cell++) {
|
||||
if (!strcmp(cell->hid, hid)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_warn(hostdev,
|
||||
"could not find cell for child device (%s), discarding\n",
|
||||
hid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
pdev->dev.parent = hostdev;
|
||||
ACPI_COMPANION_SET(&pdev->dev, child);
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, num_res);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add_data(pdev, cell->pdata, cell->pdata_size);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
acpi_device_set_enumerated(child);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
platform_device_put(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -501,94 +579,14 @@ static void hisi_lpc_acpi_remove(struct device *hostdev)
|
||||
*/
|
||||
static int hisi_lpc_acpi_probe(struct device *hostdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(hostdev);
|
||||
struct acpi_device *child;
|
||||
int ret;
|
||||
|
||||
/* Only consider the children of the host */
|
||||
list_for_each_entry(child, &adev->children, node) {
|
||||
const char *hid = acpi_device_hid(child);
|
||||
const struct hisi_lpc_acpi_cell *cell;
|
||||
struct platform_device *pdev;
|
||||
const struct resource *res;
|
||||
bool found = false;
|
||||
int num_res;
|
||||
ret = acpi_dev_for_each_child(ACPI_COMPANION(hostdev),
|
||||
hisi_lpc_acpi_add_child, hostdev);
|
||||
if (ret)
|
||||
hisi_lpc_acpi_remove(hostdev);
|
||||
|
||||
ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res,
|
||||
&num_res);
|
||||
if (ret) {
|
||||
dev_warn(hostdev, "set resource fail (%d)\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cell = (struct hisi_lpc_acpi_cell []){
|
||||
/* ipmi */
|
||||
{
|
||||
.hid = "IPI0001",
|
||||
.name = "hisi-lpc-ipmi",
|
||||
},
|
||||
/* 8250-compatible uart */
|
||||
{
|
||||
.hid = "HISI1031",
|
||||
.name = "serial8250",
|
||||
.pdata = (struct plat_serial8250_port []) {
|
||||
{
|
||||
.iobase = res->start,
|
||||
.uartclk = 1843200,
|
||||
.iotype = UPIO_PORT,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
},
|
||||
{}
|
||||
},
|
||||
.pdata_size = 2 *
|
||||
sizeof(struct plat_serial8250_port),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
for (; cell && cell->name; cell++) {
|
||||
if (!strcmp(cell->hid, hid)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_warn(hostdev,
|
||||
"could not find cell for child device (%s), discarding\n",
|
||||
hid);
|
||||
continue;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pdev->dev.parent = hostdev;
|
||||
ACPI_COMPANION_SET(&pdev->dev, child);
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, num_res);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add_data(pdev, cell->pdata,
|
||||
cell->pdata_size);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
acpi_device_set_enumerated(child);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
hisi_lpc_acpi_remove(hostdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,29 @@ int mfd_cell_disable(struct platform_device *pdev)
|
||||
EXPORT_SYMBOL(mfd_cell_disable);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
struct match_ids_walk_data {
|
||||
struct acpi_device_id *ids;
|
||||
struct acpi_device *adev;
|
||||
};
|
||||
|
||||
static int match_device_ids(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct match_ids_walk_data *wd = data;
|
||||
|
||||
if (!acpi_match_device_ids(adev, wd->ids)) {
|
||||
wd->adev = adev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell_acpi_match *match = cell->acpi_match;
|
||||
struct acpi_device *parent, *child;
|
||||
struct acpi_device *adev = NULL;
|
||||
struct acpi_device *parent;
|
||||
|
||||
parent = ACPI_COMPANION(pdev->dev.parent);
|
||||
if (!parent)
|
||||
@ -83,14 +100,14 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
if (match) {
|
||||
if (match->pnpid) {
|
||||
struct acpi_device_id ids[2] = {};
|
||||
struct match_ids_walk_data wd = {
|
||||
.adev = NULL,
|
||||
.ids = ids,
|
||||
};
|
||||
|
||||
strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
|
||||
list_for_each_entry(child, &parent->children, node) {
|
||||
if (!acpi_match_device_ids(child, ids)) {
|
||||
adev = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
acpi_dev_for_each_child(parent, match_device_ids, &wd);
|
||||
adev = wd.adev;
|
||||
} else {
|
||||
adev = acpi_find_child_device(parent, match->adr, false);
|
||||
}
|
||||
|
@ -775,8 +775,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct sdhci_acpi_slot *slot;
|
||||
struct acpi_device *device, *child;
|
||||
const struct dmi_system_id *id;
|
||||
struct acpi_device *device;
|
||||
struct sdhci_acpi_host *c;
|
||||
struct sdhci_host *host;
|
||||
struct resource *iomem;
|
||||
@ -796,10 +796,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
|
||||
slot = sdhci_acpi_get_slot(device);
|
||||
|
||||
/* Power on the SDHCI controller and its children */
|
||||
acpi_device_fix_up_power(device);
|
||||
list_for_each_entry(child, &device->children, node)
|
||||
if (child->status.present && child->status.enabled)
|
||||
acpi_device_fix_up_power(child);
|
||||
acpi_device_fix_up_power_extended(device);
|
||||
|
||||
if (sdhci_acpi_byt_defer(dev))
|
||||
return -EPROBE_DEFER;
|
||||
|
@ -1240,16 +1240,11 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||
#ifdef CONFIG_ACPI
|
||||
static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct acpi_device *device, *child;
|
||||
struct acpi_device *device;
|
||||
|
||||
device = ACPI_COMPANION(&slot->chip->pdev->dev);
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
acpi_device_fix_up_power(device);
|
||||
list_for_each_entry(child, &device->children, node)
|
||||
if (child->status.present && child->status.enabled)
|
||||
acpi_device_fix_up_power(child);
|
||||
if (device)
|
||||
acpi_device_fix_up_power_extended(device);
|
||||
}
|
||||
#else
|
||||
static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {}
|
||||
|
@ -6842,6 +6842,31 @@ static const struct backlight_ops ibm_backlight_data = {
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static int __init tpacpi_evaluate_bcl(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
int rc;
|
||||
|
||||
status = acpi_evaluate_object(adev->handle, "_BCL", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
|
||||
obj = buffer.pointer;
|
||||
if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
|
||||
acpi_handle_info(adev->handle,
|
||||
"Unknown _BCL data, please report this to %s\n",
|
||||
TPACPI_MAIL);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = obj->package.count;
|
||||
}
|
||||
kfree(obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call _BCL method of video device. On some ThinkPads this will
|
||||
* switch the firmware to the ACPI brightness control mode.
|
||||
@ -6849,37 +6874,13 @@ static const struct backlight_ops ibm_backlight_data = {
|
||||
|
||||
static int __init tpacpi_query_bcl_levels(acpi_handle handle)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
struct acpi_device *device, *child;
|
||||
int rc;
|
||||
struct acpi_device *device;
|
||||
|
||||
device = acpi_fetch_acpi_dev(handle);
|
||||
if (!device)
|
||||
return 0;
|
||||
|
||||
rc = 0;
|
||||
list_for_each_entry(child, &device->children, node) {
|
||||
acpi_status status = acpi_evaluate_object(child->handle, "_BCL",
|
||||
NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
continue;
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)buffer.pointer;
|
||||
if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
|
||||
pr_err("Unknown _BCL data, please report this to %s\n",
|
||||
TPACPI_MAIL);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = obj->package.count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(buffer.pointer);
|
||||
return rc;
|
||||
return acpi_dev_for_each_child(device, tpacpi_evaluate_bcl, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,6 +127,71 @@ static bool find_slave(struct sdw_bus *bus,
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sdw_acpi_child_walk_data {
|
||||
struct sdw_bus *bus;
|
||||
struct acpi_device *adev;
|
||||
struct sdw_slave_id id;
|
||||
bool ignore_unique_id;
|
||||
};
|
||||
|
||||
static int sdw_acpi_check_duplicate(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct sdw_acpi_child_walk_data *cwd = data;
|
||||
struct sdw_bus *bus = cwd->bus;
|
||||
struct sdw_slave_id id;
|
||||
|
||||
if (adev == cwd->adev)
|
||||
return 0;
|
||||
|
||||
if (!find_slave(bus, adev, &id))
|
||||
return 0;
|
||||
|
||||
if (cwd->id.sdw_version != id.sdw_version || cwd->id.mfg_id != id.mfg_id ||
|
||||
cwd->id.part_id != id.part_id || cwd->id.class_id != id.class_id)
|
||||
return 0;
|
||||
|
||||
if (cwd->id.unique_id != id.unique_id) {
|
||||
dev_dbg(bus->dev,
|
||||
"Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
cwd->id.unique_id, id.unique_id, cwd->id.mfg_id,
|
||||
cwd->id.part_id);
|
||||
cwd->ignore_unique_id = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(bus->dev,
|
||||
"Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, cwd->id.part_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int sdw_acpi_find_one(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct sdw_bus *bus = data;
|
||||
struct sdw_acpi_child_walk_data cwd = {
|
||||
.bus = bus,
|
||||
.adev = adev,
|
||||
.ignore_unique_id = true,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!find_slave(bus, adev, &cwd.id))
|
||||
return 0;
|
||||
|
||||
/* Brute-force O(N^2) search for duplicates. */
|
||||
ret = acpi_dev_for_each_child(ACPI_COMPANION(bus->dev),
|
||||
sdw_acpi_check_duplicate, &cwd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cwd.ignore_unique_id)
|
||||
cwd.id.unique_id = SDW_IGNORED_UNIQUE_ID;
|
||||
|
||||
/* Ignore errors and continue. */
|
||||
sdw_slave_add(bus, &cwd.id, acpi_fwnode_handle(adev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
|
||||
* @bus: SDW bus instance
|
||||
@ -135,8 +200,7 @@ static bool find_slave(struct sdw_bus *bus,
|
||||
*/
|
||||
int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
||||
{
|
||||
struct acpi_device *adev, *parent;
|
||||
struct acpi_device *adev2, *parent2;
|
||||
struct acpi_device *parent;
|
||||
|
||||
parent = ACPI_COMPANION(bus->dev);
|
||||
if (!parent) {
|
||||
@ -144,54 +208,7 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
list_for_each_entry(adev, &parent->children, node) {
|
||||
struct sdw_slave_id id;
|
||||
struct sdw_slave_id id2;
|
||||
bool ignore_unique_id = true;
|
||||
|
||||
if (!find_slave(bus, adev, &id))
|
||||
continue;
|
||||
|
||||
/* brute-force O(N^2) search for duplicates */
|
||||
parent2 = parent;
|
||||
list_for_each_entry(adev2, &parent2->children, node) {
|
||||
|
||||
if (adev == adev2)
|
||||
continue;
|
||||
|
||||
if (!find_slave(bus, adev2, &id2))
|
||||
continue;
|
||||
|
||||
if (id.sdw_version != id2.sdw_version ||
|
||||
id.mfg_id != id2.mfg_id ||
|
||||
id.part_id != id2.part_id ||
|
||||
id.class_id != id2.class_id)
|
||||
continue;
|
||||
|
||||
if (id.unique_id != id2.unique_id) {
|
||||
dev_dbg(bus->dev,
|
||||
"Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
|
||||
ignore_unique_id = false;
|
||||
} else {
|
||||
dev_err(bus->dev,
|
||||
"Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore_unique_id)
|
||||
id.unique_id = SDW_IGNORED_UNIQUE_ID;
|
||||
|
||||
/*
|
||||
* don't error check for sdw_slave_add as we want to continue
|
||||
* adding Slaves
|
||||
*/
|
||||
sdw_slave_add(bus, &id, acpi_fwnode_handle(adev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return acpi_dev_for_each_child(parent, sdw_acpi_find_one, bus);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -301,37 +301,22 @@ static bool tb_acpi_bus_match(struct device *dev)
|
||||
return tb_is_switch(dev) || tb_is_usb4_port_device(dev);
|
||||
}
|
||||
|
||||
static struct acpi_device *tb_acpi_find_port(struct acpi_device *adev,
|
||||
const struct tb_port *port)
|
||||
{
|
||||
struct acpi_device *port_adev;
|
||||
|
||||
if (!adev)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Device routers exists under the downstream facing USB4 port
|
||||
* of the parent router. Their _ADR is always 0.
|
||||
*/
|
||||
list_for_each_entry(port_adev, &adev->children, node) {
|
||||
if (acpi_device_adr(port_adev) == port->port)
|
||||
return port_adev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
|
||||
{
|
||||
struct acpi_device *adev = NULL;
|
||||
struct tb_switch *parent_sw;
|
||||
|
||||
/*
|
||||
* Device routers exists under the downstream facing USB4 port
|
||||
* of the parent router. Their _ADR is always 0.
|
||||
*/
|
||||
parent_sw = tb_switch_parent(sw);
|
||||
if (parent_sw) {
|
||||
struct tb_port *port = tb_port_at(tb_route(sw), parent_sw);
|
||||
struct acpi_device *port_adev;
|
||||
|
||||
port_adev = tb_acpi_find_port(ACPI_COMPANION(&parent_sw->dev), port);
|
||||
port_adev = acpi_find_child_by_adr(ACPI_COMPANION(&parent_sw->dev),
|
||||
port->port);
|
||||
if (port_adev)
|
||||
adev = acpi_find_child_device(port_adev, 0, false);
|
||||
} else {
|
||||
@ -364,8 +349,8 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
|
||||
if (tb_is_switch(dev))
|
||||
return tb_acpi_switch_find_companion(tb_to_switch(dev));
|
||||
else if (tb_is_usb4_port_device(dev))
|
||||
return tb_acpi_find_port(ACPI_COMPANION(dev->parent),
|
||||
tb_to_usb4_port_device(dev)->port);
|
||||
return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
|
||||
tb_to_usb4_port_device(dev)->port->port);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -124,22 +124,6 @@ out:
|
||||
*/
|
||||
#define USB_ACPI_LOCATION_VALID (1 << 31)
|
||||
|
||||
static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
|
||||
int raw)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(adev, &parent->children, node) {
|
||||
if (acpi_device_adr(adev) == raw)
|
||||
return adev;
|
||||
}
|
||||
|
||||
return acpi_find_child_device(parent, raw, false);
|
||||
}
|
||||
|
||||
static struct acpi_device *
|
||||
usb_acpi_get_companion_for_port(struct usb_port *port_dev)
|
||||
{
|
||||
@ -170,7 +154,7 @@ usb_acpi_get_companion_for_port(struct usb_port *port_dev)
|
||||
port1 = port_dev->portnum;
|
||||
}
|
||||
|
||||
return usb_acpi_find_port(adev, port1);
|
||||
return acpi_find_child_by_adr(adev, port1);
|
||||
}
|
||||
|
||||
static struct acpi_device *
|
||||
|
@ -365,8 +365,6 @@ struct acpi_device {
|
||||
acpi_handle handle; /* no handle for fixed hardware */
|
||||
struct fwnode_handle fwnode;
|
||||
struct acpi_device *parent;
|
||||
struct list_head children;
|
||||
struct list_head node;
|
||||
struct list_head wakeup_list;
|
||||
struct list_head del_list;
|
||||
struct acpi_device_status status;
|
||||
@ -379,7 +377,6 @@ struct acpi_device {
|
||||
struct acpi_device_data data;
|
||||
struct acpi_scan_handler *handler;
|
||||
struct acpi_hotplug_context *hp;
|
||||
struct acpi_driver *driver;
|
||||
const struct acpi_gpio_mapping *driver_gpios;
|
||||
void *driver_data;
|
||||
struct device dev;
|
||||
@ -483,6 +480,9 @@ extern struct bus_type acpi_bus_type;
|
||||
int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data);
|
||||
int acpi_dev_for_each_child(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *), void *data);
|
||||
int acpi_dev_for_each_child_reverse(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *),
|
||||
void *data);
|
||||
|
||||
/*
|
||||
* Events
|
||||
@ -521,6 +521,7 @@ const char *acpi_power_state_string(int state);
|
||||
int acpi_device_set_power(struct acpi_device *device, int state);
|
||||
int acpi_bus_init_power(struct acpi_device *device);
|
||||
int acpi_device_fix_up_power(struct acpi_device *device);
|
||||
void acpi_device_fix_up_power_extended(struct acpi_device *adev);
|
||||
int acpi_bus_update_power(acpi_handle handle, int *state_p);
|
||||
int acpi_device_update_power(struct acpi_device *device, int *state_p);
|
||||
bool acpi_bus_power_manageable(acpi_handle handle);
|
||||
@ -622,6 +623,8 @@ static inline int acpi_dma_configure(struct device *dev,
|
||||
}
|
||||
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
|
||||
u64 address, bool check_children);
|
||||
struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
|
||||
acpi_bus_address adr);
|
||||
int acpi_is_root_bridge(acpi_handle);
|
||||
struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user