Commit 723de0f9171e ("staging: most: remove device from interface structure") moved registration of driver-provided struct device to the most subsystem, but did not properly update dim2 driver to work with that change. After most subsystem passes driver's dev to register_device(), it becomes refcounted, and can be only deallocated in the release method. Provide that by: - not using devres to allocate the device, - moving shutdown actions from _remove() to the device release method, - not calling shutdown actions in _probe() after the device becomes refcounted. Also, driver used to register it's dev itself, to provide a custom attribute. With the modified most subsystem, this causes duplicate registration of the same device object. Fix that by adding that custom attribute to the platform device - that is a better location for a platform-specific attribute anyway. Fixes: 723de0f9171e ("staging: most: remove device from interface structure") Signed-off-by: Nikita Yushchenko <nikita.yoush@xxxxxxxxxxxxxxxxxx> --- drivers/staging/most/dim2/dim2.c | 60 ++++++++++++++++++------------- drivers/staging/most/dim2/sysfs.c | 5 ++- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c index e8b03fa90e80..7ef142b9faef 100644 --- a/drivers/staging/most/dim2/dim2.c +++ b/drivers/staging/most/dim2/dim2.c @@ -717,6 +717,23 @@ static int get_dim2_clk_speed(const char *clock_speed, u8 *val) return -EINVAL; } +static void dim2_release(struct device *d) +{ + struct dim2_hdm *dev = container_of(d, struct dim2_hdm, dev); + unsigned long flags; + + kthread_stop(dev->netinfo_task); + + spin_lock_irqsave(&dim_lock, flags); + dim_shutdown(); + spin_unlock_irqrestore(&dim_lock, flags); + + if (dev->disable_platform) + dev->disable_platform(to_platform_device(d->parent)); + + kfree(dev); +} + /* * dim2_probe - dim2 probe handler * @pdev: platform device structure @@ -738,7 +755,7 @@ static int dim2_probe(struct platform_device *pdev) enum { MLB_INT_IDX, AHB0_INT_IDX }; - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -750,19 +767,21 @@ static int dim2_probe(struct platform_device *pdev) "microchip,clock-speed", &clock_speed); if (ret) { dev_err(&pdev->dev, "missing dt property clock-speed\n"); - return ret; + goto err_free_dev; } ret = get_dim2_clk_speed(clock_speed, &dev->clk_speed); if (ret) { dev_err(&pdev->dev, "bad dt property clock-speed\n"); - return ret; + goto err_free_dev; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->io_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dev->io_base)) - return PTR_ERR(dev->io_base); + if (IS_ERR(dev->io_base)) { + ret = PTR_ERR(dev->io_base); + goto err_free_dev; + } of_id = of_match_node(dim2_of_match, pdev->dev.of_node); pdata = of_id->data; @@ -770,7 +789,7 @@ static int dim2_probe(struct platform_device *pdev) if (pdata->enable) { ret = pdata->enable(pdev); if (ret) - return ret; + goto err_free_dev; } dev->disable_platform = pdata->disable; if (pdata->fcnt) @@ -865,32 +884,34 @@ static int dim2_probe(struct platform_device *pdev) dev->most_iface.request_netinfo = request_netinfo; dev->most_iface.driver_dev = &pdev->dev; dev->most_iface.dev = &dev->dev; - dev->dev.init_name = "dim2_state"; + dev->dev.init_name = dev->name; dev->dev.parent = &pdev->dev; + dev->dev.release = dim2_release; ret = most_register_interface(&dev->most_iface); if (ret) { dev_err(&pdev->dev, "failed to register MOST interface\n"); - goto err_stop_thread; + /* cleanup handled by dim2_release() */ + return ret; } - ret = dim2_sysfs_probe(&dev->dev); + ret = dim2_sysfs_probe(&pdev->dev); if (ret) { dev_err(&pdev->dev, "failed to create sysfs attribute\n"); - goto err_unreg_iface; + most_deregister_interface(&dev->most_iface); + /* cleanup handled by dim2_release() */ + return ret; } return 0; -err_unreg_iface: - most_deregister_interface(&dev->most_iface); -err_stop_thread: - kthread_stop(dev->netinfo_task); err_shutdown_dim: dim_shutdown(); err_disable_platform: if (dev->disable_platform) dev->disable_platform(pdev); +err_free_dev: + kfree(dev); return ret; } @@ -904,18 +925,9 @@ static int dim2_probe(struct platform_device *pdev) static int dim2_remove(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); - unsigned long flags; - dim2_sysfs_destroy(&dev->dev); + dim2_sysfs_destroy(&pdev->dev); most_deregister_interface(&dev->most_iface); - kthread_stop(dev->netinfo_task); - - spin_lock_irqsave(&dim_lock, flags); - dim_shutdown(); - spin_unlock_irqrestore(&dim_lock, flags); - - if (dev->disable_platform) - dev->disable_platform(pdev); return 0; } diff --git a/drivers/staging/most/dim2/sysfs.c b/drivers/staging/most/dim2/sysfs.c index c85b2cdcdca3..22836c8ed554 100644 --- a/drivers/staging/most/dim2/sysfs.c +++ b/drivers/staging/most/dim2/sysfs.c @@ -39,11 +39,10 @@ static const struct attribute_group *dev_attr_groups[] = { int dim2_sysfs_probe(struct device *dev) { - dev->groups = dev_attr_groups; - return device_register(dev); + return sysfs_create_groups(&dev->kobj, dev_attr_groups); } void dim2_sysfs_destroy(struct device *dev) { - device_unregister(dev); + sysfs_remove_groups(&dev->kobj, dev_attr_groups); } -- 2.30.2