From 142cf1b68fa0e1710f3623875d5c269cbbc2f005 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:22 +0200 Subject: [PATCH] base: platform: name the device already during allocation The device name is usually required when assigning resources like clocks to platform devices. The problem is that the device name is not know before platform_device_add is called and that can be too late as the drivers may have already requested the resources when the function returns. By naming the device already in platform_device_alloc, the resources can be assigned before platform_device_add is called. This change allows different kinds of probe drivers to pass forward their resources to the actual driver. The first place where we need it is dwc3 controllers host glue code (drivers/usb/dwc3/host.c) to pass the phy's to xhci. Change-Id: I1a5a6009ad053e44054b86b5a675142f301dfefc Signed-off-by: Heikki Krogerus Cc: Greg Kroah-Hartman Signed-off-by: memeka --- drivers/base/platform.c | 69 ++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c4af00385502..1fd5430d4a62 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -230,11 +230,41 @@ void platform_device_put(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(platform_device_put); +static int pdev_set_name(struct platform_device *pdev) +{ + int ret; + + switch (pdev->id) { + default: + return dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); + case PLATFORM_DEVID_NONE: + return dev_set_name(&pdev->dev, "%s", pdev->name); + case PLATFORM_DEVID_AUTO: + /* + * Automatically allocated device ID. We mark it as such so + * that we remember it must be freed, and we append a suffix + * to avoid namespace collision with explicit IDs. + */ + ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); + if (ret < 0) + return ret; + pdev->id = ret; + pdev->id_auto = true; + return dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, + pdev->id); + } + + return 0; +} + static void platform_device_release(struct device *dev) { struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); + if (pa->pdev.id_auto) + ida_simple_remove(&platform_devid_ida, pa->pdev.id); + of_device_node_put(&pa->pdev.dev); kfree(pa->pdev.dev.platform_data); kfree(pa->pdev.mfd_cell); @@ -263,6 +293,10 @@ struct platform_device *platform_device_alloc(const char *name, int id) device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; arch_setup_pdev_archdata(&pa->pdev); + if (pdev_set_name(&pa->pdev)) { + kfree(pa); + return NULL; + } } return pa ? &pa->pdev : NULL; @@ -359,28 +393,6 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; - switch (pdev->id) { - default: - dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - break; - case PLATFORM_DEVID_NONE: - dev_set_name(&pdev->dev, "%s", pdev->name); - break; - case PLATFORM_DEVID_AUTO: - /* - * Automatically allocated device ID. We mark it as such so - * that we remember it must be freed, and we append a suffix - * to avoid namespace collision with explicit IDs. - */ - ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); - if (ret < 0) - goto err_out; - pdev->id = ret; - pdev->id_auto = true; - dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); - break; - } - for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; @@ -421,7 +433,6 @@ int platform_device_add(struct platform_device *pdev) release_resource(r); } - err_out: return ret; } EXPORT_SYMBOL_GPL(platform_device_add); @@ -442,11 +453,6 @@ void platform_device_del(struct platform_device *pdev) device_remove_properties(&pdev->dev); device_del(&pdev->dev); - if (pdev->id_auto) { - ida_simple_remove(&platform_devid_ida, pdev->id); - pdev->id = PLATFORM_DEVID_AUTO; - } - for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; if (r->parent) @@ -462,8 +468,15 @@ EXPORT_SYMBOL_GPL(platform_device_del); */ int platform_device_register(struct platform_device *pdev) { + int ret; + device_initialize(&pdev->dev); arch_setup_pdev_archdata(pdev); + + ret = pdev_set_name(pdev); + if (ret) + return ret; + return platform_device_add(pdev); } EXPORT_SYMBOL_GPL(platform_device_register);