On 25-01-17 14:18:50, Tudor Ambarus wrote: > Callers of of_qcom_ice_get() leak the device reference taken by > of_find_device_by_node(). Introduce devm variant for of_qcom_ice_get(). > Existing consumers need the ICE instance for the entire life of their > device, thus exporting qcom_ice_put() is not required. > > Signed-off-by: Tudor Ambarus <tudor.ambarus@xxxxxxxxxx> Good catch. LGTM. Reviewed-by: Abel Vesa <abel.vesa@xxxxxxxxxx> > --- > drivers/soc/qcom/ice.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ > include/soc/qcom/ice.h | 2 ++ > 2 files changed, 50 insertions(+) > > diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c > index 393d2d1d275f..79e04bff3e33 100644 > --- a/drivers/soc/qcom/ice.c > +++ b/drivers/soc/qcom/ice.c > @@ -11,6 +11,7 @@ > #include <linux/cleanup.h> > #include <linux/clk.h> > #include <linux/delay.h> > +#include <linux/device.h> > #include <linux/iopoll.h> > #include <linux/of.h> > #include <linux/of_platform.h> > @@ -324,6 +325,53 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) > } > EXPORT_SYMBOL_GPL(of_qcom_ice_get); > > +static void qcom_ice_put(const struct qcom_ice *ice) > +{ > + struct platform_device *pdev = to_platform_device(ice->dev); > + > + if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice")) > + platform_device_put(pdev); > +} > + > +static void devm_of_qcom_ice_put(struct device *dev, void *res) > +{ > + qcom_ice_put(*(struct qcom_ice **)res); > +} > + > +/** > + * devm_of_qcom_ice_get() - Devres managed helper to get an ICE instance from > + * a DT node. > + * @dev: device pointer for the consumer device. > + * > + * This function will provide an ICE instance either by creating one for the > + * consumer device if its DT node provides the 'ice' reg range and the 'ice' > + * clock (for legacy DT style). On the other hand, if consumer provides a > + * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already > + * be created and so this function will return that instead. > + * > + * Return: ICE pointer on success, NULL if there is no ICE data provided by the > + * consumer or ERR_PTR() on error. > + */ > +struct qcom_ice *devm_of_qcom_ice_get(struct device *dev) > +{ > + struct qcom_ice *ice, **dr; > + > + dr = devres_alloc(devm_of_qcom_ice_put, sizeof(*dr), GFP_KERNEL); > + if (!dr) > + return ERR_PTR(-ENOMEM); > + > + ice = of_qcom_ice_get(dev); > + if (!IS_ERR_OR_NULL(ice)) { > + *dr = ice; > + devres_add(dev, dr); > + } else { > + devres_free(dr); > + } > + > + return ice; > +} > +EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get); > + > static int qcom_ice_probe(struct platform_device *pdev) > { > struct qcom_ice *engine; > diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h > index 5870a94599a2..d5f6a228df65 100644 > --- a/include/soc/qcom/ice.h > +++ b/include/soc/qcom/ice.h > @@ -34,4 +34,6 @@ int qcom_ice_program_key(struct qcom_ice *ice, > int slot); > int qcom_ice_evict_key(struct qcom_ice *ice, int slot); > struct qcom_ice *of_qcom_ice_get(struct device *dev); > +struct qcom_ice *devm_of_qcom_ice_get(struct device *dev); > + > #endif /* __QCOM_ICE_H__ */ > > -- > 2.48.0.rc2.279.g1de40edade-goog >