Re: [PATCH v2 3/5] thermal: devfreq_cooling: add new registration functions with Energy Model

From: Ionela Voinescu
Date: Wed Dec 02 2020 - 05:25:28 EST


Hi Lukasz,

On Wednesday 18 Nov 2020 at 12:03:56 (+0000), Lukasz Luba wrote:
> + * Register a devfreq cooling device and attempt to register Energy Model. The
> + * available OPPs must be registered for the device.
> + *
> + * If @dfc_power is provided, the cooling device is registered with the
> + * power extensions. If @em_cb is provided it will be called for each OPP to
> + * calculate power value and cost. If @em_cb is not provided then simple Energy
> + * Model is going to be used, which requires "dynamic-power-coefficient" a
> + * devicetree property.
> + */
> +struct thermal_cooling_device *
> +devfreq_cooling_em_register_power(struct devfreq *df,
> + struct devfreq_cooling_power *dfc_power,
> + struct em_data_callback *em_cb)
> +{
> + struct thermal_cooling_device *cdev;
> + struct devfreq_cooling_device *dfc;
> + struct device_node *np = NULL;
> + struct device *dev;
> + int nr_opp, ret;
> +
> + if (IS_ERR_OR_NULL(df))
> + return ERR_PTR(-EINVAL);
> +
> + dev = df->dev.parent;
> +
> + if (em_cb) {
> + nr_opp = dev_pm_opp_get_opp_count(dev);
> + if (nr_opp <= 0) {
> + dev_err(dev, "No valid OPPs found\n");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + ret = em_dev_register_perf_domain(dev, nr_opp, em_cb, NULL, false);
> + } else {
> + ret = dev_pm_opp_of_register_em(dev, NULL);
> + }
> +
> + if (ret)
> + dev_warn(dev, "Unable to register EM for devfreq cooling device (%d)\n",
> + ret);
> +
> + if (dev->of_node)
> + np = of_node_get(dev->of_node);
> +

Should np be checked before use? I'm not sure if it's better to do the
assign first and then the check on np before use. It depends on the
consequences of passing a NULL node pointer later on.

> + cdev = of_devfreq_cooling_register_power(np, df, dfc_power);
> +
> + if (np)
> + of_node_put(np);
> +
> + if (IS_ERR_OR_NULL(cdev)) {
> + if (!ret)
> + em_dev_unregister_perf_domain(dev);
> + } else {
> + dfc = cdev->devdata;
> + dfc->em_registered = !ret;
> + }
> +
> + return cdev;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_cooling_em_register_power);
> +
> +/**
> + * devfreq_cooling_em_register() - Register devfreq cooling device together
> + * with Energy Model.
> + * @df: Pointer to devfreq device.
> + * @em_cb: Callback functions providing the data of the Energy Model
> + *
> + * This function attempts to register Energy Model for devfreq device and then
> + * register the devfreq cooling device.
> + */
> +struct thermal_cooling_device *
> +devfreq_cooling_em_register(struct devfreq *df, struct em_data_callback *em_cb)
> +{
> + return devfreq_cooling_em_register_power(df, NULL, em_cb);
> +}
> +EXPORT_SYMBOL_GPL(devfreq_cooling_em_register);
> +
> /**
> * devfreq_cooling_unregister() - Unregister devfreq cooling device.
> * @cdev: Pointer to devfreq cooling device to unregister.
> + *
> + * Unregisters devfreq cooling device and related Energy Model if it was
> + * present.
> */
> void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
> {
> struct devfreq_cooling_device *dfc;
> + struct device *dev;
>
> - if (!cdev)
> + if (IS_ERR_OR_NULL(cdev))
> return;
>
> dfc = cdev->devdata;
> + dev = dfc->devfreq->dev.parent;
>
> thermal_cooling_device_unregister(dfc->cdev);
> ida_simple_remove(&devfreq_ida, dfc->id);
> dev_pm_qos_remove_request(&dfc->req_max_freq);
> +
> + if (dfc->em_registered)
> + em_dev_unregister_perf_domain(dev);
> +
> kfree(dfc->power_table);
> kfree(dfc->freq_table);
>
> diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h
> index 9df2dfca68dd..19868fb922f1 100644
> --- a/include/linux/devfreq_cooling.h
> +++ b/include/linux/devfreq_cooling.h
> @@ -11,6 +11,7 @@
> #define __DEVFREQ_COOLING_H__
>
> #include <linux/devfreq.h>
> +#include <linux/energy_model.h>
> #include <linux/thermal.h>
>
>
> @@ -65,6 +66,13 @@ struct thermal_cooling_device *
> of_devfreq_cooling_register(struct device_node *np, struct devfreq *df);
> struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df);
> void devfreq_cooling_unregister(struct thermal_cooling_device *dfc);
> +struct thermal_cooling_device *
> +devfreq_cooling_em_register_power(struct devfreq *df,
> + struct devfreq_cooling_power *dfc_power,
> + struct em_data_callback *em_cb);
> +struct thermal_cooling_device *
> +devfreq_cooling_em_register(struct devfreq *df,
> + struct em_data_callback *em_cb);
>
> #else /* !CONFIG_DEVFREQ_THERMAL */
>
> @@ -87,6 +95,20 @@ devfreq_cooling_register(struct devfreq *df)
> return ERR_PTR(-EINVAL);
> }
>
> +static inline struct thermal_cooling_device *
> +devfreq_cooling_em_register_power(struct devfreq *df,
> + struct devfreq_cooling_power *dfc_power,
> + struct em_data_callback *em_cb)
> +{
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static inline struct thermal_cooling_device *
> +devfreq_cooling_em_register(struct devfreq *df, struct em_data_callback *em_cb)
> +{
> + return ERR_PTR(-EINVAL);
> +}
> +
> static inline void
> devfreq_cooling_unregister(struct thermal_cooling_device *dfc)
> {
> --
> 2.17.1
>

Otherwise it looks good to me:

Reviewed-by: Ionela Voinescu <ionela.voinescu@xxxxxxx>

Ionela.