Provide devm variants for automatic resource release on device removal.
Makes error-handling in probe() simpler, thus less error-prone.
Once all resources are devmanaged, remove() is no longer needed.
Signed-off-by: Marc Gonzalez <[email protected]>
---
Changes from v2:
x Handle dvb_register_adapter() return code correctly
Changes from v1:
x Simplify devm_dvb_register_adapter() implementation
x Add 3 more devm APIs
x Document them in devres.rst
---
Documentation/driver-model/devres.rst | 6 ++++++
drivers/media/dvb-core/dmxdev.c | 13 +++++++++++++
drivers/media/dvb-core/dvb_demux.c | 13 +++++++++++++
drivers/media/dvb-core/dvb_frontend.c | 13 +++++++++++++
drivers/media/dvb-core/dvbdev.c | 12 ++++++++++++
include/media/dmxdev.h | 3 +++
include/media/dvb_demux.h | 2 ++
include/media/dvb_frontend.h | 3 +++
include/media/dvbdev.h | 3 +++
9 files changed, 68 insertions(+)
diff --git a/Documentation/driver-model/devres.rst b/Documentation/driver-model/devres.rst
index 6af41a6a4bb6..84bdb61f27a3 100644
--- a/Documentation/driver-model/devres.rst
+++ b/Documentation/driver-model/devres.rst
@@ -268,6 +268,12 @@ DMA
DRM
devm_drm_dev_init()
+DVB
+ devm_dvb_dmx_init()
+ devm_dvb_dmxdev_init()
+ devm_dvb_register_adapter()
+ devm_dvb_register_frontend()
+
GPIO
devm_gpiod_get()
devm_gpiod_get_index()
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index f14a872d1268..f38b65d1b430 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -1444,6 +1444,19 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
EXPORT_SYMBOL(dvb_dmxdev_init);
+static void dmxdev_release(void *dmxdev)
+{
+ dvb_dmxdev_release(dmxdev);
+}
+
+int devm_dvb_dmxdev_init(struct device *dev, struct dmxdev *dmxdev,
+ struct dvb_adapter *dvb_adapter)
+{
+ int rc = dvb_dmxdev_init(dmxdev, dvb_adapter);
+ return rc ? : devm_add_action_or_reset(dev, dmxdev_release, dmxdev);
+}
+EXPORT_SYMBOL(devm_dvb_dmxdev_init);
+
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
dmxdev->exit = 1;
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index 39a2c6ccf31d..55b9675b99c5 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -28,6 +28,7 @@
#include <linux/string.h>
#include <linux/crc32.h>
#include <linux/uaccess.h>
+#include <linux/device.h>
#include <asm/div64.h>
#include <media/dvb_demux.h>
@@ -1317,6 +1318,18 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
EXPORT_SYMBOL(dvb_dmx_init);
+static void dmx_release(void *dvbdemux)
+{
+ dvb_dmx_release(dvbdemux);
+}
+
+int devm_dvb_dmx_init(struct device *dev, struct dvb_demux *dvbdemux)
+{
+ int rc = dvb_dmx_init(dvbdemux);
+ return rc ? : devm_add_action_or_reset(dev, dmx_release, dvbdemux);
+}
+EXPORT_SYMBOL(devm_dvb_dmx_init);
+
void dvb_dmx_release(struct dvb_demux *dvbdemux)
{
vfree(dvbdemux->cnt_storage);
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 209186c5cd9b..4a281cd8c064 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -3007,6 +3007,19 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
}
EXPORT_SYMBOL(dvb_register_frontend);
+static void unregister_frontend(void *fe)
+{
+ dvb_unregister_frontend(fe);
+}
+
+int devm_dvb_register_frontend(struct device *dev,
+ struct dvb_adapter *dvb, struct dvb_frontend *fe)
+{
+ int rc = dvb_register_frontend(dvb, fe);
+ return rc ? : devm_add_action_or_reset(dev, unregister_frontend, fe);
+}
+EXPORT_SYMBOL(devm_dvb_register_frontend);
+
int dvb_unregister_frontend(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index a3393cd4e584..0fc8dbf65045 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -885,6 +885,18 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
}
EXPORT_SYMBOL(dvb_register_adapter);
+static void unreg_adapter(void *adap)
+{
+ dvb_unregister_adapter(adap);
+}
+
+int devm_dvb_register_adapter(struct device *dev, struct dvb_adapter *adap,
+ const char *name, struct module *module, short *adapter_nums)
+{
+ int rc = dvb_register_adapter(adap, name, module, dev, adapter_nums);
+ return rc < 0 ? rc : devm_add_action_or_reset(dev, unreg_adapter, adap);
+}
+EXPORT_SYMBOL(devm_dvb_register_adapter);
int dvb_unregister_adapter(struct dvb_adapter *adap)
{
diff --git a/include/media/dmxdev.h b/include/media/dmxdev.h
index baafa3b8aca4..0300d829aeea 100644
--- a/include/media/dmxdev.h
+++ b/include/media/dmxdev.h
@@ -204,6 +204,9 @@ struct dmxdev {
*/
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *adap);
+int devm_dvb_dmxdev_init(struct device *dev, struct dmxdev *dmxdev,
+ struct dvb_adapter *dvb_adapter);
+
/**
* dvb_dmxdev_release - releases a digital TV demux and unregisters it.
*
diff --git a/include/media/dvb_demux.h b/include/media/dvb_demux.h
index 3b6aeca7a49e..95fe901076d7 100644
--- a/include/media/dvb_demux.h
+++ b/include/media/dvb_demux.h
@@ -266,6 +266,8 @@ struct dvb_demux {
*/
int dvb_dmx_init(struct dvb_demux *demux);
+int devm_dvb_dmx_init(struct device *dev, struct dvb_demux *demux);
+
/**
* dvb_dmx_release - releases a digital TV demux internal buffers.
*
diff --git a/include/media/dvb_frontend.h b/include/media/dvb_frontend.h
index f05cd7b94a2c..56dbaf3cc7a9 100644
--- a/include/media/dvb_frontend.h
+++ b/include/media/dvb_frontend.h
@@ -713,6 +713,9 @@ struct dvb_frontend {
int dvb_register_frontend(struct dvb_adapter *dvb,
struct dvb_frontend *fe);
+int devm_dvb_register_frontend(struct device *dev,
+ struct dvb_adapter *dvb, struct dvb_frontend *fe);
+
/**
* dvb_unregister_frontend() - Unregisters a DVB frontend
*
diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
index 551325858de3..32f8d1626319 100644
--- a/include/media/dvbdev.h
+++ b/include/media/dvbdev.h
@@ -202,6 +202,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
struct module *module, struct device *device,
short *adapter_nums);
+int devm_dvb_register_adapter(struct device *dev, struct dvb_adapter *adap,
+ const char *name, struct module *module, short *adapter_nums);
+
/**
* dvb_unregister_adapter - Unregisters a DVB adapter
*
--
2.17.1
Hi Marc,
Thanks for your patch.
On Thu, 2019-07-18 at 15:03 +0200, Marc Gonzalez wrote:
> Provide devm variants for automatic resource release on device removal.
> Makes error-handling in probe() simpler, thus less error-prone.
> Once all resources are devmanaged, remove() is no longer needed.
>
I think it would be better to add this API as part of a series
that also uses it.
Regards,
Eze
On 21/07/2019 17:02, Ezequiel Garcia wrote:
> On Thu, 2019-07-18 at 15:03 +0200, Marc Gonzalez wrote:
>
>> Provide devm variants for automatic resource release on device removal.
>> Makes error-handling in probe() simpler, thus less error-prone.
>> Once all resources are devmanaged, remove() is no longer needed.
>
> I think it would be better to add this API as part of a series
> that also uses it.
I have an outstanding RFC for a new driver:
https://patchwork.kernel.org/patch/11040435/
Locally, I've updated the probe function to use the proposed devm functions.
I was mainly hoping to get initial feedback from the maintainers.
1) See if they're OK with devm APIs
2) See if they're OK with the way I implemented devm APIs
3) See what's missing to get an Ack
static int tsif_probe(struct platform_device *pdev)
{
int err, virq;
struct tsif *tsif;
struct resource *res;
struct dvb_frontend *fe;
struct dvb_adapter *adap;
struct device *dev = &pdev->dev;
short num = DVB_UNSET;
fe = dvb_get_demod_fe(dev->of_node);
if (!fe)
return -ENXIO;
tsif = devm_kzalloc(dev, sizeof(*tsif), GFP_KERNEL);
if (!tsif)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tsif0");
tsif->base = devm_ioremap_resource(dev, res);
if (IS_ERR(tsif->base))
return PTR_ERR(tsif->base);
virq = platform_get_irq_byname(pdev, "tsif0");
err = devm_request_irq(dev, virq, tsif_isr, IRQF_SHARED, "tsif", tsif);
if (err)
return err;
tsif->clk = devm_clk_get(dev, "iface");
if (IS_ERR(tsif->clk))
return PTR_ERR(tsif->clk);
err = devm_clk_prepare_enable(dev, tsif->clk);
if (err)
return err;
adap = &tsif->adapter;
err = devm_dvb_register_adapter(dev, adap, "tsif", THIS_MODULE, &num);
if (err) return err;
/* Not sure the diff between filter and feed? */
tsif->demux.filternum = 16; /*** Dunno what to put here ***/
tsif->demux.feednum = 16; /*** Dunno what to put here ***/
tsif->demux.start_feed = noop;
tsif->demux.stop_feed = noop;
err = devm_dvb_dmx_init(dev, &tsif->demux);
if (err) return err;
/* What relation to dvb_demux.filternum??? */
/* Do I need this object?? */
tsif->dmxdev.filternum = 16;
tsif->dmxdev.demux = &tsif->demux.dmx;
err = devm_dvb_dmxdev_init(dev, &tsif->dmxdev, adap);
if (err) return err;
err = devm_dvb_register_frontend(dev, adap, fe);
if (err) return err;
writel_relaxed(TSIF_START + ENABLE_IRQ, tsif->base + TSIF_STS_CTL);
devm_add_action(dev, stop_tsif, tsif);
INIT_WORK(&tsif->work, handle_pkt);
return 0;
}
On Mon, Jul 22, 2019 at 10:13:56AM +0200, Marc Gonzalez wrote:
> On 21/07/2019 17:02, Ezequiel Garcia wrote:
>
> > On Thu, 2019-07-18 at 15:03 +0200, Marc Gonzalez wrote:
> >
> >> Provide devm variants for automatic resource release on device removal.
> >> Makes error-handling in probe() simpler, thus less error-prone.
> >> Once all resources are devmanaged, remove() is no longer needed.
> >
> > I think it would be better to add this API as part of a series
> > that also uses it.
>
> I have an outstanding RFC for a new driver:
>
> https://patchwork.kernel.org/patch/11040435/
>
> Locally, I've updated the probe function to use the proposed devm functions.
>
> I was mainly hoping to get initial feedback from the maintainers.
> 1) See if they're OK with devm APIs
devm_ has some lifetime issues, wrt to disconnect. However, for a platform
device it is fine.
> 2) See if they're OK with the way I implemented devm APIs
Looks good to me.
> 3) See what's missing to get an Ack
Please submit both this patch and a the driver as a series.
Thanks,
Sean
>
> static int tsif_probe(struct platform_device *pdev)
> {
> int err, virq;
> struct tsif *tsif;
> struct resource *res;
> struct dvb_frontend *fe;
> struct dvb_adapter *adap;
> struct device *dev = &pdev->dev;
> short num = DVB_UNSET;
>
> fe = dvb_get_demod_fe(dev->of_node);
> if (!fe)
> return -ENXIO;
>
> tsif = devm_kzalloc(dev, sizeof(*tsif), GFP_KERNEL);
> if (!tsif)
> return -ENOMEM;
>
> res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tsif0");
> tsif->base = devm_ioremap_resource(dev, res);
> if (IS_ERR(tsif->base))
> return PTR_ERR(tsif->base);
>
> virq = platform_get_irq_byname(pdev, "tsif0");
> err = devm_request_irq(dev, virq, tsif_isr, IRQF_SHARED, "tsif", tsif);
> if (err)
> return err;
>
> tsif->clk = devm_clk_get(dev, "iface");
> if (IS_ERR(tsif->clk))
> return PTR_ERR(tsif->clk);
>
> err = devm_clk_prepare_enable(dev, tsif->clk);
> if (err)
> return err;
>
> adap = &tsif->adapter;
> err = devm_dvb_register_adapter(dev, adap, "tsif", THIS_MODULE, &num);
> if (err) return err;
>
> /* Not sure the diff between filter and feed? */
> tsif->demux.filternum = 16; /*** Dunno what to put here ***/
> tsif->demux.feednum = 16; /*** Dunno what to put here ***/
> tsif->demux.start_feed = noop;
> tsif->demux.stop_feed = noop;
> err = devm_dvb_dmx_init(dev, &tsif->demux);
> if (err) return err;
>
> /* What relation to dvb_demux.filternum??? */
> /* Do I need this object?? */
> tsif->dmxdev.filternum = 16;
> tsif->dmxdev.demux = &tsif->demux.dmx;
> err = devm_dvb_dmxdev_init(dev, &tsif->dmxdev, adap);
> if (err) return err;
>
> err = devm_dvb_register_frontend(dev, adap, fe);
> if (err) return err;
>
> writel_relaxed(TSIF_START + ENABLE_IRQ, tsif->base + TSIF_STS_CTL);
> devm_add_action(dev, stop_tsif, tsif);
> INIT_WORK(&tsif->work, handle_pkt);
>
> return 0;
> }