[PATCH] staging: most: dim2: fix device registration
From: Nikita Yushchenko
Date: Wed Sep 29 2021 - 16:59:08 EST
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