summaryrefslogtreecommitdiff
path: root/drivers/acpi/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r--drivers/acpi/scan.c223
1 files changed, 112 insertions, 111 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index a184529d8fa4..bc973fbd70b2 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -479,9 +479,8 @@ static void acpi_device_del(struct acpi_device *device)
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
if (!strcmp(acpi_device_bus_id->bus_id,
acpi_device_hid(device))) {
- if (acpi_device_bus_id->instance_no > 0)
- acpi_device_bus_id->instance_no--;
- else {
+ ida_simple_remove(&acpi_device_bus_id->instance_ida, device->pnp.instance_no);
+ if (ida_is_empty(&acpi_device_bus_id->instance_ida)) {
list_del(&acpi_device_bus_id->node);
kfree_const(acpi_device_bus_id->bus_id);
kfree(acpi_device_bus_id);
@@ -531,7 +530,7 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used)
* used by the device.
*/
acpi_power_transition(adev, ACPI_STATE_D3_COLD);
- put_device(&adev->dev);
+ acpi_dev_put(adev);
}
}
@@ -561,7 +560,7 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context)
* prevents attempts to register device objects identical to those being
* deleted from happening concurrently (such attempts result from
* hotplug events handled via the ACPI hotplug workqueue). It also will
- * run after all of the work items submitted previosuly, which helps
+ * run after all of the work items submitted previously, which helps
* those work items to ensure that they are not accessing stale device
* objects.
*/
@@ -605,8 +604,7 @@ EXPORT_SYMBOL(acpi_bus_get_device);
static void get_acpi_device(void *dev)
{
- if (dev)
- get_device(&((struct acpi_device *)dev)->dev);
+ acpi_dev_get(dev);
}
struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
@@ -616,7 +614,7 @@ struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
void acpi_bus_put_acpi_device(struct acpi_device *adev)
{
- put_device(&adev->dev);
+ acpi_dev_put(adev);
}
static struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id)
@@ -631,6 +629,21 @@ static struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id)
return NULL;
}
+static int acpi_device_set_name(struct acpi_device *device,
+ struct acpi_device_bus_id *acpi_device_bus_id)
+{
+ struct ida *instance_ida = &acpi_device_bus_id->instance_ida;
+ int result;
+
+ result = ida_simple_get(instance_ida, 0, ACPI_MAX_DEVICE_INSTANCES, GFP_KERNEL);
+ if (result < 0)
+ return result;
+
+ device->pnp.instance_no = result;
+ dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, result);
+ return 0;
+}
+
int acpi_device_add(struct acpi_device *device,
void (*release)(struct device *))
{
@@ -665,7 +678,9 @@ int acpi_device_add(struct acpi_device *device,
acpi_device_bus_id = acpi_device_bus_id_match(acpi_device_hid(device));
if (acpi_device_bus_id) {
- acpi_device_bus_id->instance_no++;
+ result = acpi_device_set_name(device, acpi_device_bus_id);
+ if (result)
+ goto err_unlock;
} else {
acpi_device_bus_id = kzalloc(sizeof(*acpi_device_bus_id),
GFP_KERNEL);
@@ -681,9 +696,16 @@ int acpi_device_add(struct acpi_device *device,
goto err_unlock;
}
+ ida_init(&acpi_device_bus_id->instance_ida);
+
+ result = acpi_device_set_name(device, acpi_device_bus_id);
+ if (result) {
+ kfree(acpi_device_bus_id);
+ goto err_unlock;
+ }
+
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
}
- dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
if (device->parent)
list_add_tail(&device->node, &device->parent->children);
@@ -734,27 +756,25 @@ static bool acpi_info_matches_ids(struct acpi_device_info *info,
const char * const ids[])
{
struct acpi_pnp_device_id_list *cid_list = NULL;
- int i;
+ int i, index;
if (!(info->valid & ACPI_VALID_HID))
return false;
+ index = match_string(ids, -1, info->hardware_id.string);
+ if (index >= 0)
+ return true;
+
if (info->valid & ACPI_VALID_CID)
cid_list = &info->compatible_id_list;
- for (i = 0; ids[i]; i++) {
- int j;
+ if (!cid_list)
+ return false;
- if (!strcmp(info->hardware_id.string, ids[i]))
+ for (i = 0; i < cid_list->count; i++) {
+ index = match_string(ids, -1, cid_list->ids[i].string);
+ if (index >= 0)
return true;
-
- if (!cid_list)
- continue;
-
- for (j = 0; j < cid_list->count; j++) {
- if (!strcmp(cid_list->ids[j].string, ids[i]))
- return true;
- }
}
return false;
@@ -1284,8 +1304,9 @@ static bool acpi_object_is_system_bus(acpi_handle handle)
}
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
- int device_type, struct acpi_device_info *info)
+ int device_type)
{
+ struct acpi_device_info *info = NULL;
struct acpi_pnp_device_id_list *cid_list;
int i;
@@ -1296,6 +1317,7 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
break;
}
+ acpi_get_object_info(handle, &info);
if (!info) {
pr_err(PREFIX "%s: Error reading device info\n",
__func__);
@@ -1321,6 +1343,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
if (info->valid & ACPI_VALID_CLS)
acpi_add_id(pnp, info->class_code.string);
+ kfree(info);
+
/*
* Some devices don't reliably have _HIDs & _CIDs, so add
* synthetic HIDs to make sure drivers can find them.
@@ -1626,17 +1650,16 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
}
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
- int type, unsigned long long sta,
- struct acpi_device_info *info)
+ int type)
{
INIT_LIST_HEAD(&device->pnp.ids);
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
fwnode_init(&device->fwnode, &acpi_device_fwnode_ops);
- acpi_set_device_status(device, sta);
+ acpi_set_device_status(device, ACPI_STA_DEFAULT);
acpi_device_get_busid(device);
- acpi_set_pnp_ids(handle, &device->pnp, type, info);
+ acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
@@ -1647,6 +1670,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device_initialize(&device->dev);
dev_set_uevent_suppress(&device->dev, true);
acpi_init_coherency(device);
+ /* Assume there are unmet deps to start with. */
+ device->dep_unmet = 1;
}
void acpi_device_add_finalize(struct acpi_device *device)
@@ -1655,33 +1680,30 @@ void acpi_device_add_finalize(struct acpi_device *device)
kobject_uevent(&device->dev.kobj, KOBJ_ADD);
}
+static void acpi_scan_init_status(struct acpi_device *adev)
+{
+ if (acpi_bus_get_status(adev))
+ acpi_set_device_status(adev, 0);
+}
+
static int acpi_add_single_object(struct acpi_device **child,
- acpi_handle handle, int type,
- unsigned long long sta)
+ acpi_handle handle, int type)
{
- struct acpi_device_info *info = NULL;
struct acpi_device *device;
int result;
- if (handle != ACPI_ROOT_OBJECT && type == ACPI_BUS_TYPE_DEVICE)
- acpi_get_object_info(handle, &info);
-
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
- if (!device) {
- kfree(info);
+ if (!device)
return -ENOMEM;
- }
- acpi_init_device_object(device, handle, type, sta, info);
- kfree(info);
+ acpi_init_device_object(device, handle, type);
/*
- * For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so
- * that we can call acpi_bus_get_status() and use its quirk handling.
- * Note this must be done before the get power-/wakeup_dev-flags calls.
+ * Getting the status is delayed till here so that we can call
+ * acpi_bus_get_status() and use its quirk handling. Note that
+ * this must be done before the get power-/wakeup_dev-flags calls.
*/
- if (type == ACPI_BUS_TYPE_DEVICE)
- if (acpi_bus_get_status(device) < 0)
- acpi_set_device_status(device, 0);
+ if (type == ACPI_BUS_TYPE_DEVICE || type == ACPI_BUS_TYPE_PROCESSOR)
+ acpi_scan_init_status(device);
acpi_bus_get_power_flags(device);
acpi_bus_get_wakeup_device_flags(device);
@@ -1738,50 +1760,6 @@ static bool acpi_device_should_be_hidden(acpi_handle handle)
return true;
}
-static int acpi_bus_type_and_status(acpi_handle handle, int *type,
- unsigned long long *sta)
-{
- acpi_status status;
- acpi_object_type acpi_type;
-
- status = acpi_get_type(handle, &acpi_type);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- switch (acpi_type) {
- case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
- case ACPI_TYPE_DEVICE:
- if (acpi_device_should_be_hidden(handle))
- return -ENODEV;
-
- *type = ACPI_BUS_TYPE_DEVICE;
- /*
- * acpi_add_single_object updates this once we've an acpi_device
- * so that acpi_bus_get_status' quirk handling can be used.
- */
- *sta = ACPI_STA_DEFAULT;
- break;
- case ACPI_TYPE_PROCESSOR:
- *type = ACPI_BUS_TYPE_PROCESSOR;
- status = acpi_bus_get_status_handle(handle, sta);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- break;
- case ACPI_TYPE_THERMAL:
- *type = ACPI_BUS_TYPE_THERMAL;
- *sta = ACPI_STA_DEFAULT;
- break;
- case ACPI_TYPE_POWER:
- *type = ACPI_BUS_TYPE_POWER;
- *sta = ACPI_STA_DEFAULT;
- break;
- default:
- return -ENODEV;
- }
-
- return 0;
-}
-
bool acpi_device_is_present(const struct acpi_device *adev)
{
return adev->status.present || adev->status.functional;
@@ -1850,7 +1828,7 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
}
}
-static u32 acpi_scan_check_dep(acpi_handle handle)
+static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
{
struct acpi_handle_list dep_devices;
acpi_status status;
@@ -1863,7 +1841,8 @@ static u32 acpi_scan_check_dep(acpi_handle handle)
* 2. ACPI nodes describing USB ports.
* Still, checking for _HID catches more then just these cases ...
*/
- if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID"))
+ if (!check_dep || !acpi_has_method(handle, "_DEP") ||
+ !acpi_has_method(handle, "_HID"))
return 0;
status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices);
@@ -1910,6 +1889,8 @@ static void acpi_scan_dep_init(struct acpi_device *adev)
{
struct acpi_dep_data *dep;
+ adev->dep_unmet = 0;
+
mutex_lock(&acpi_dep_list_lock);
list_for_each_entry(dep, &acpi_dep_list, node) {
@@ -1926,38 +1907,59 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
struct acpi_device **adev_p)
{
struct acpi_device *device = NULL;
- unsigned long long sta;
+ acpi_object_type acpi_type;
int type;
- int result;
acpi_bus_get_device(handle, &device);
if (device)
goto out;
- result = acpi_bus_type_and_status(handle, &type, &sta);
- if (result)
+ if (ACPI_FAILURE(acpi_get_type(handle, &acpi_type)))
return AE_OK;
- if (type == ACPI_BUS_TYPE_POWER) {
- acpi_add_power_resource(handle);
- return AE_OK;
- }
+ switch (acpi_type) {
+ case ACPI_TYPE_DEVICE:
+ if (acpi_device_should_be_hidden(handle))
+ return AE_OK;
- if (type == ACPI_BUS_TYPE_DEVICE && check_dep) {
- u32 count = acpi_scan_check_dep(handle);
- /* Bail out if the number of recorded dependencies is not 0. */
- if (count > 0) {
+ /* Bail out if there are dependencies. */
+ if (acpi_scan_check_dep(handle, check_dep) > 0) {
acpi_bus_scan_second_pass = true;
return AE_CTRL_DEPTH;
}
+
+ fallthrough;
+ case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
+ type = ACPI_BUS_TYPE_DEVICE;
+ break;
+
+ case ACPI_TYPE_PROCESSOR:
+ type = ACPI_BUS_TYPE_PROCESSOR;
+ break;
+
+ case ACPI_TYPE_THERMAL:
+ type = ACPI_BUS_TYPE_THERMAL;
+ break;
+
+ case ACPI_TYPE_POWER:
+ acpi_add_power_resource(handle);
+ fallthrough;
+ default:
+ return AE_OK;
}
- acpi_add_single_object(&device, handle, type, sta);
+ acpi_add_single_object(&device, handle, type);
if (!device)
return AE_CTRL_DEPTH;
acpi_scan_init_hotplug(device);
- if (!check_dep)
+ /*
+ * If check_dep is true at this point, the device has no dependencies,
+ * or the creation of the device object would have been postponed above.
+ */
+ if (check_dep)
+ device->dep_unmet = 0;
+ else
acpi_scan_dep_init(device);
out:
@@ -2220,8 +2222,7 @@ int acpi_bus_register_early_device(int type)
struct acpi_device *device = NULL;
int result;
- result = acpi_add_single_object(&device, NULL,
- type, ACPI_STA_DEFAULT);
+ result = acpi_add_single_object(&device, NULL, type);
if (result)
return result;
@@ -2241,8 +2242,7 @@ static int acpi_bus_scan_fixed(void)
struct acpi_device *device = NULL;
result = acpi_add_single_object(&device, NULL,
- ACPI_BUS_TYPE_POWER_BUTTON,
- ACPI_STA_DEFAULT);
+ ACPI_BUS_TYPE_POWER_BUTTON);
if (result)
return result;
@@ -2258,8 +2258,7 @@ static int acpi_bus_scan_fixed(void)
struct acpi_device *device = NULL;
result = acpi_add_single_object(&device, NULL,
- ACPI_BUS_TYPE_SLEEP_BUTTON,
- ACPI_STA_DEFAULT);
+ ACPI_BUS_TYPE_SLEEP_BUTTON);
if (result)
return result;
@@ -2355,11 +2354,13 @@ int __init acpi_scan_init(void)
acpi_detach_data(acpi_root->handle,
acpi_scan_drop_device);
acpi_device_del(acpi_root);
- put_device(&acpi_root->dev);
+ acpi_bus_put_acpi_device(acpi_root);
goto out;
}
}
+ acpi_turn_off_unused_power_resources();
+
acpi_scan_initialized = true;
out: