Currently ACPI device instance ID won't be released when hot-remvoing an ACPI device. When hot-replacing an ACPI device for several times, the ACPI device instance ID will keep on increasing, which is a little inconvenient. So use IDA to manage ACPI device instance IDs. Signed-off-by: Jiang Liu <liuj97@xxxxxxxxx> Signed-off-by: Gaohuai Han <hangaohuai@xxxxxxxxxx> --- drivers/acpi/scan.c | 90 +++++++++++++++++++++++++++++++++----------------- 1 files changed, 59 insertions(+), 31 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c8a1f3b..7ae9675 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -12,6 +12,7 @@ #include <linux/dmi.h> #include <acpi/acpi_drivers.h> +#include <linux/idr.h> #include "internal.h" @@ -35,7 +36,7 @@ LIST_HEAD(acpi_wakeup_device_list); struct acpi_device_bus_id{ char bus_id[15]; - unsigned int instance_no; + struct ida ida; struct list_head node; }; @@ -449,11 +450,58 @@ struct bus_type acpi_bus_type = { .uevent = acpi_device_uevent, }; +static int acpi_device_get_id_name(struct acpi_device *device) +{ + int result = -ENOENT; + struct acpi_device_bus_id *bus_id; + const char *hid = acpi_device_hid(device); + + list_for_each_entry(bus_id, &acpi_bus_id_list, node) + if (!strcmp(bus_id->bus_id, hid)) { + result = 0; + break; + } + if (result) { + bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); + if (bus_id) { + ida_init(&bus_id->ida); + strcpy(bus_id->bus_id, hid); + list_add_tail(&bus_id->node, &acpi_bus_id_list); + } + } + + if (!bus_id) + result = -ENOMEM; + else + do { + if (!ida_pre_get(&bus_id->ida, GFP_KERNEL)) + break; + result = ida_get_new(&bus_id->ida, &device->dev.id); + } while (result == -EAGAIN); + + if (!result) + dev_set_name(&device->dev, "%s:%02x", + bus_id->bus_id, device->dev.id); + + return result; +} + +static void acpi_device_release_id(struct acpi_device *device) +{ + struct acpi_device_bus_id *bus_id; + const char *hid = acpi_device_hid(device); + + list_for_each_entry(bus_id, &acpi_bus_id_list, node) { + if (!strcmp(bus_id->bus_id, hid)) { + ida_remove(&bus_id->ida, device->dev.id); + break; + } + } +} + static int acpi_device_register(struct acpi_device *device) { int result; - struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; - int found = 0; /* * Linkage @@ -464,33 +512,12 @@ static int acpi_device_register(struct acpi_device *device) INIT_LIST_HEAD(&device->node); INIT_LIST_HEAD(&device->wakeup_list); - new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); - if (!new_bus_id) { - printk(KERN_ERR PREFIX "Memory allocation error\n"); - return -ENOMEM; - } - mutex_lock(&acpi_device_lock); - /* - * Find suitable bus_id and instance number in acpi_bus_id_list - * If failed, create one and link it into acpi_bus_id_list - */ - 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))) { - acpi_device_bus_id->instance_no++; - found = 1; - kfree(new_bus_id); - break; - } - } - if (!found) { - acpi_device_bus_id = new_bus_id; - strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device)); - acpi_device_bus_id->instance_no = 0; - list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); + result = acpi_device_get_id_name(device); + if (result) { + dev_err(&device->dev, "fail to allocate instance ID\n"); + goto out_unlock; } - 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); @@ -506,7 +533,7 @@ static int acpi_device_register(struct acpi_device *device) result = device_register(&device->dev); if (result) { dev_err(&device->dev, "Error registering device\n"); - goto end; + goto out_unlink; } result = acpi_device_setup_files(device); @@ -516,11 +543,12 @@ static int acpi_device_register(struct acpi_device *device) device->removal_type = ACPI_BUS_REMOVAL_NORMAL; return 0; -end: +out_unlink: mutex_lock(&acpi_device_lock); if (device->parent) list_del(&device->node); list_del(&device->wakeup_list); +out_unlock: mutex_unlock(&acpi_device_lock); return result; } @@ -530,8 +558,8 @@ static void acpi_device_unregister(struct acpi_device *device, int type) mutex_lock(&acpi_device_lock); if (device->parent) list_del(&device->node); - list_del(&device->wakeup_list); + acpi_device_release_id(device); mutex_unlock(&acpi_device_lock); acpi_detach_data(device->handle, acpi_bus_data_handler); -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html