All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device
@ 2023-10-17 21:19 Rodrigo Vivi
  2023-10-18 15:56 ` Chanwoo Choi
  2023-11-06  0:22 ` kernel test robot
  0 siblings, 2 replies; 3+ messages in thread
From: Rodrigo Vivi @ 2023-10-17 21:19 UTC (permalink / raw)
  To: linux-pm, linux-kernel, cw00.choi, kyungmin.park, myungjoo.ham,
	digetx, viresh.kumar
  Cc: Rodrigo Vivi

Devfreq provides a very good standard for frequency management of
a device. However it is limited to a single frequency control and
governor per device with a hardcoded 1-1 match since devfreq device
name inherits dev_name of the parent device.

Although it suits well most of PCI devices out there, it currently
limits its adoption on devices with multiple domain frequencies
that could be seen as sub-devices.

This patch introduces the optional string argument 'name'.

When a name is given, the device itself is named with a generic
'df<n>' where 'n' is the global devfreq's device counter.
The given name is only visible at /sys/class/devfreq/df<n>/name.

So, when a name is given, multiple devfreq devices can be created
for a single parent device that is willing to address multiple
frequencies domains or subdevices withing a PCI device for instance.

When no name is given both the device name and the name file uses
the the parent's device dev_name() and it is limited to a
single devfreq device per parent-device, in order to respect the
legacy usage and not break any backwards compatibility.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
---

This is mostly a RFC where the main answer that I'm looking for
is to know if this would be acceptable by devfreq subsystem.

For Intel GPUs we have a concept of a multi-tile and multi-gt.
Each tile can be seen as a duplication of an entire gpu and
contain a GT inside each and each GT has its own independent
frequency management.

Also, some newer platforms, even with single tile, has an exclusive
GT for media, also with independent frequency management.

Currently our sysfs provides a full representation of the hardware
and we could even have something like:
/sys/class/drm/card0/device/tile0/gt0/freq/
/sys/class/drm/card0/device/tile0/gt1/freq/
/sys/class/drm/card0/device/tile1/gt0/freq/
/sys/class/drm/card0/device/tile1/gt1/freq/

We are implementing a new driver for the future platforms, so we
are looking for standardize our interfaces with other drivers
and devfreq seemed to have a bright future.

Unfortunately just this patch by itself wouldn't allow us to use
devfreq directly, because we have underlaying firmware governors.
Other local experiments that seemed to work for me was to convert
the current Tegra's exclusive governor to a generic governor_active.c

On top of that we would need some extra stuff like throttle_reasons,
and some custom arguments, however before taking any further step
toward this direction I'd like to get back to my original question

is this multiple device/domain acceptable here?

Thoughts?

Thanks in advance,
Rodrigo.

 drivers/devfreq/devfreq.c | 31 ++++++++++++++++++++++++++-----
 include/linux/devfreq.h   |  8 ++++++++
 2 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 474d81831ad3..7b4355229d0f 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/idr.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
@@ -57,6 +58,8 @@ static const char timer_name[][DEVFREQ_NAME_LEN] = {
 	[DEVFREQ_TIMER_DELAYED] = { "delayed" },
 };
 
+static DEFINE_IDA(devfreq_ida);
+
 /**
  * find_device_devfreq() - find devfreq struct using device pointer
  * @dev:	device pointer used to lookup device devfreq.
@@ -727,12 +730,15 @@ static int qos_max_notifier_call(struct notifier_block *nb,
 static void devfreq_dev_release(struct device *dev)
 {
 	struct devfreq *devfreq = to_devfreq(dev);
-	int err;
+	int id, err;
 
 	mutex_lock(&devfreq_list_lock);
 	list_del(&devfreq->node);
 	mutex_unlock(&devfreq_list_lock);
 
+	if (sscanf(dev_name(dev), "df%d", &id))
+		ida_free(&devfreq_ida, id);
+
 	err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
 					 DEV_PM_QOS_MAX_FREQUENCY);
 	if (err && err != -ENOENT)
@@ -788,17 +794,26 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	struct devfreq *devfreq;
 	struct devfreq_governor *governor;
 	unsigned long min_freq, max_freq;
-	int err = 0;
+	int id, err = 0;
 
 	if (!dev || !profile || !governor_name) {
 		dev_err(dev, "%s: Invalid parameters.\n", __func__);
 		return ERR_PTR(-EINVAL);
 	}
 
+	id = ida_alloc(&devfreq_ida, GFP_KERNEL);
+	if (id < 0) {
+	        err = -ENOMEM;
+		goto err_ida;
+	}
+
 	mutex_lock(&devfreq_list_lock);
 	devfreq = find_device_devfreq(dev);
 	mutex_unlock(&devfreq_list_lock);
-	if (!IS_ERR(devfreq)) {
+	if (!IS_ERR(devfreq) &&
+	    (!profile->name ||
+	     (profile->name && devfreq->profile->name &&
+	      !strcmp(profile->name, devfreq->profile->name)))) {
 		dev_err(dev, "%s: devfreq device already exists!\n",
 			__func__);
 		err = -EINVAL;
@@ -864,7 +879,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	atomic_set(&devfreq->suspend_count, 0);
 
-	dev_set_name(&devfreq->dev, "%s", dev_name(dev));
+	if (profile->name)
+		dev_set_name(&devfreq->dev, "df%d", id);
+	else
+		dev_set_name(&devfreq->dev, "%s", dev_name(dev));
 	err = device_register(&devfreq->dev);
 	if (err) {
 		mutex_unlock(&devfreq->lock);
@@ -955,6 +973,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	return devfreq;
 
+err_ida:
+	ida_free(&devfreq_ida, id);
 err_init:
 	mutex_unlock(&devfreq_list_lock);
 err_devfreq:
@@ -1394,7 +1414,8 @@ static ssize_t name_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
 	struct devfreq *df = to_devfreq(dev);
-	return sprintf(buf, "%s\n", dev_name(df->dev.parent));
+	return sprintf(buf, "%s\n", df->profile->name ? :
+		       dev_name(df->dev.parent));
 }
 static DEVICE_ATTR_RO(name);
 
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index d312ffbac4dd..0ec43eac647d 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -100,6 +100,13 @@ struct devfreq_dev_status {
  * @freq_table:		Optional list of frequencies to support statistics
  *			and freq_table must be generated in ascending order.
  * @max_state:		The size of freq_table.
+ * @name:		Optional name string. When a name is given, the device
+ *			itself is named with a generic 'df<n>' where 'n' is the
+ *			global devfreq's device counter. The given name is only
+ *			visible at /sys/class/devfreq/df<n>/name. When no name
+ *			is given both the device name and the name file uses the
+ *			the parent's device dev_name() and it is limited to a
+ *			single devfreq device per parent-device.
  *
  * @is_cooling_device: A self-explanatory boolean giving the device a
  *                     cooling effect property.
@@ -117,6 +124,7 @@ struct devfreq_dev_profile {
 
 	unsigned long *freq_table;
 	unsigned int max_state;
+	char *name;
 
 	bool is_cooling_device;
 };
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device
  2023-10-17 21:19 [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device Rodrigo Vivi
@ 2023-10-18 15:56 ` Chanwoo Choi
  2023-11-06  0:22 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: Chanwoo Choi @ 2023-10-18 15:56 UTC (permalink / raw)
  To: Rodrigo Vivi, linux-pm, linux-kernel, cw00.choi, kyungmin.park,
	myungjoo.ham, digetx, viresh.kumar

Hi Rodrigo,

I'm always welcoming to extend the devfreq subsystem
in order to support the new hardware architecture.
Thanks for your suggestion.

On 23. 10. 18. 06:19, Rodrigo Vivi wrote:
> Devfreq provides a very good standard for frequency management of
> a device. However it is limited to a single frequency control and
> governor per device with a hardcoded 1-1 match since devfreq device
> name inherits dev_name of the parent device.
> 
> Although it suits well most of PCI devices out there, it currently
> limits its adoption on devices with multiple domain frequencies
> that could be seen as sub-devices.
> 
> This patch introduces the optional string argument 'name'.
> 
> When a name is given, the device itself is named with a generic
> 'df<n>' where 'n' is the global devfreq's device counter.
> The given name is only visible at /sys/class/devfreq/df<n>/name.
> 
> So, when a name is given, multiple devfreq devices can be created
> for a single parent device that is willing to address multiple
> frequencies domains or subdevices withing a PCI device for instance.
> 
> When no name is given both the device name and the name file uses
> the the parent's device dev_name() and it is limited to a
> single devfreq device per parent-device, in order to respect the
> legacy usage and not break any backwards compatibility.
> 
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> ---
> 
> This is mostly a RFC where the main answer that I'm looking for
> is to know if this would be acceptable by devfreq subsystem.
> 
> For Intel GPUs we have a concept of a multi-tile and multi-gt.
> Each tile can be seen as a duplication of an entire gpu and
> contain a GT inside each and each GT has its own independent
> frequency management.
> 
> Also, some newer platforms, even with single tile, has an exclusive
> GT for media, also with independent frequency management.
> 
> Currently our sysfs provides a full representation of the hardware
> and we could even have something like:
> /sys/class/drm/card0/device/tile0/gt0/freq/
> /sys/class/drm/card0/device/tile0/gt1/freq/
> /sys/class/drm/card0/device/tile1/gt0/freq/
> /sys/class/drm/card0/device/tile1/gt1/freq/
> 
> We are implementing a new driver for the future platforms, so we
> are looking for standardize our interfaces with other drivers
> and devfreq seemed to have a bright future.
> 
> Unfortunately just this patch by itself wouldn't allow us to use
> devfreq directly, because we have underlaying firmware governors.
> Other local experiments that seemed to work for me was to convert
> the current Tegra's exclusive governor to a generic governor_active.c
> 
> On top of that we would need some extra stuff like throttle_reasons,
> and some custom arguments, however before taking any further step
> toward this direction I'd like to get back to my original question
> 
> is this multiple device/domain acceptable here?
> 
> Thoughts?

It is possible to create the multiple devfreq device from one device.
Instead, I think that better to use the following style node name
in order to make the group of same parent device.
- /sys/class/devfreq/devfreq<id>-<id of sub-device>/name.

For example,
/sys/class/devfreq/devfreq0-0/
/sys/class/devfreq/devfreq0-1/
/sys/class/devfreq/devfreq0-2/

/sys/class/devfreq/devfreq1-0/
/sys/class/devfreq/devfreq1-1/
/sys/class/devfreq/devfreq1-2/
/sys/class/devfreq/devfreq1-3/
/sys/class/devfreq/devfreq1-4/

...


> 
> Thanks in advance,
> Rodrigo.
> 
>  drivers/devfreq/devfreq.c | 31 ++++++++++++++++++++++++++-----
>  include/linux/devfreq.h   |  8 ++++++++
>  2 files changed, 34 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 474d81831ad3..7b4355229d0f 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -15,6 +15,7 @@
>  #include <linux/errno.h>
>  #include <linux/err.h>
>  #include <linux/init.h>
> +#include <linux/idr.h>
>  #include <linux/export.h>
>  #include <linux/slab.h>
>  #include <linux/stat.h>
> @@ -57,6 +58,8 @@ static const char timer_name[][DEVFREQ_NAME_LEN] = {
>  	[DEVFREQ_TIMER_DELAYED] = { "delayed" },
>  };
>  
> +static DEFINE_IDA(devfreq_ida);
> +
>  /**
>   * find_device_devfreq() - find devfreq struct using device pointer
>   * @dev:	device pointer used to lookup device devfreq.
> @@ -727,12 +730,15 @@ static int qos_max_notifier_call(struct notifier_block *nb,
>  static void devfreq_dev_release(struct device *dev)
>  {
>  	struct devfreq *devfreq = to_devfreq(dev);
> -	int err;
> +	int id, err;
>  
>  	mutex_lock(&devfreq_list_lock);
>  	list_del(&devfreq->node);
>  	mutex_unlock(&devfreq_list_lock);
>  
> +	if (sscanf(dev_name(dev), "df%d", &id))
> +		ida_free(&devfreq_ida, id);
> +
>  	err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>  					 DEV_PM_QOS_MAX_FREQUENCY);
>  	if (err && err != -ENOENT)
> @@ -788,17 +794,26 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	struct devfreq *devfreq;
>  	struct devfreq_governor *governor;
>  	unsigned long min_freq, max_freq;
> -	int err = 0;
> +	int id, err = 0;
>  
>  	if (!dev || !profile || !governor_name) {
>  		dev_err(dev, "%s: Invalid parameters.\n", __func__);
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> +	id = ida_alloc(&devfreq_ida, GFP_KERNEL);
> +	if (id < 0) {
> +	        err = -ENOMEM;
> +		goto err_ida;
> +	}
> +
>  	mutex_lock(&devfreq_list_lock);
>  	devfreq = find_device_devfreq(dev);
>  	mutex_unlock(&devfreq_list_lock);
> -	if (!IS_ERR(devfreq)) {
> +	if (!IS_ERR(devfreq) &&
> +	    (!profile->name ||
> +	     (profile->name && devfreq->profile->name &&
> +	      !strcmp(profile->name, devfreq->profile->name)))) {
>  		dev_err(dev, "%s: devfreq device already exists!\n",
>  			__func__);
>  		err = -EINVAL;
> @@ -864,7 +879,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  
>  	atomic_set(&devfreq->suspend_count, 0);
>  
> -	dev_set_name(&devfreq->dev, "%s", dev_name(dev));
> +	if (profile->name)
> +		dev_set_name(&devfreq->dev, "df%d", id);
> +	else
> +		dev_set_name(&devfreq->dev, "%s", dev_name(dev));
>  	err = device_register(&devfreq->dev);
>  	if (err) {
>  		mutex_unlock(&devfreq->lock);
> @@ -955,6 +973,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  
>  	return devfreq;
>  
> +err_ida:
> +	ida_free(&devfreq_ida, id);
>  err_init:
>  	mutex_unlock(&devfreq_list_lock);
>  err_devfreq:
> @@ -1394,7 +1414,8 @@ static ssize_t name_show(struct device *dev,
>  			struct device_attribute *attr, char *buf)
>  {
>  	struct devfreq *df = to_devfreq(dev);
> -	return sprintf(buf, "%s\n", dev_name(df->dev.parent));
> +	return sprintf(buf, "%s\n", df->profile->name ? :
> +		       dev_name(df->dev.parent));
>  }
>  static DEVICE_ATTR_RO(name);
>  
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index d312ffbac4dd..0ec43eac647d 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -100,6 +100,13 @@ struct devfreq_dev_status {
>   * @freq_table:		Optional list of frequencies to support statistics
>   *			and freq_table must be generated in ascending order.
>   * @max_state:		The size of freq_table.
> + * @name:		Optional name string. When a name is given, the device
> + *			itself is named with a generic 'df<n>' where 'n' is the
> + *			global devfreq's device counter. The given name is only
> + *			visible at /sys/class/devfreq/df<n>/name. When no name
> + *			is given both the device name and the name file uses the
> + *			the parent's device dev_name() and it is limited to a
> + *			single devfreq device per parent-device.
>   *
>   * @is_cooling_device: A self-explanatory boolean giving the device a
>   *                     cooling effect property.
> @@ -117,6 +124,7 @@ struct devfreq_dev_profile {
>  
>  	unsigned long *freq_table;
>  	unsigned int max_state;
> +	char *name;
>  
>  	bool is_cooling_device;
>  };

-- 
Best Regards,
Samsung Electronics
Chanwoo Choi


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device
  2023-10-17 21:19 [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device Rodrigo Vivi
  2023-10-18 15:56 ` Chanwoo Choi
@ 2023-11-06  0:22 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2023-11-06  0:22 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: llvm, oe-kbuild-all

Hi Rodrigo,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:

[auto build test WARNING on v6.6-rc6]
[also build test WARNING on linus/master next-20231103]
[cannot apply to chanwoo/devfreq-testing]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Rodrigo-Vivi/PM-devfreq-introduce-multiple-devfreq-devices-per-parent-device/20231018-052140
base:   v6.6-rc6
patch link:    https://lore.kernel.org/r/20231017211944.192978-1-rodrigo.vivi%40intel.com
patch subject: [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20231106/202311060707.wCZVoRvK-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231106/202311060707.wCZVoRvK-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311060707.wCZVoRvK-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/devfreq/devfreq.c:805:6: warning: variable 'devfreq' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
           if (id < 0) {
               ^~~~~~
   drivers/devfreq/devfreq.c:981:24: note: uninitialized use occurs here
           devfreq_remove_device(devfreq);
                                 ^~~~~~~
   drivers/devfreq/devfreq.c:805:2: note: remove the 'if' if its condition is always false
           if (id < 0) {
           ^~~~~~~~~~~~~
   drivers/devfreq/devfreq.c:794:25: note: initialize the variable 'devfreq' to silence this warning
           struct devfreq *devfreq;
                                  ^
                                   = NULL
   1 warning generated.


vim +805 drivers/devfreq/devfreq.c

   776	
   777	static void create_sysfs_files(struct devfreq *devfreq,
   778					const struct devfreq_governor *gov);
   779	static void remove_sysfs_files(struct devfreq *devfreq,
   780					const struct devfreq_governor *gov);
   781	
   782	/**
   783	 * devfreq_add_device() - Add devfreq feature to the device
   784	 * @dev:	the device to add devfreq feature.
   785	 * @profile:	device-specific profile to run devfreq.
   786	 * @governor_name:	name of the policy to choose frequency.
   787	 * @data:	devfreq driver pass to governors, governor should not change it.
   788	 */
   789	struct devfreq *devfreq_add_device(struct device *dev,
   790					   struct devfreq_dev_profile *profile,
   791					   const char *governor_name,
   792					   void *data)
   793	{
   794		struct devfreq *devfreq;
   795		struct devfreq_governor *governor;
   796		unsigned long min_freq, max_freq;
   797		int id, err = 0;
   798	
   799		if (!dev || !profile || !governor_name) {
   800			dev_err(dev, "%s: Invalid parameters.\n", __func__);
   801			return ERR_PTR(-EINVAL);
   802		}
   803	
   804		id = ida_alloc(&devfreq_ida, GFP_KERNEL);
 > 805		if (id < 0) {
   806		        err = -ENOMEM;
   807			goto err_ida;
   808		}
   809	
   810		mutex_lock(&devfreq_list_lock);
   811		devfreq = find_device_devfreq(dev);
   812		mutex_unlock(&devfreq_list_lock);
   813		if (!IS_ERR(devfreq) &&
   814		    (!profile->name ||
   815		     (profile->name && devfreq->profile->name &&
   816		      !strcmp(profile->name, devfreq->profile->name)))) {
   817			dev_err(dev, "%s: devfreq device already exists!\n",
   818				__func__);
   819			err = -EINVAL;
   820			goto err_out;
   821		}
   822	
   823		devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
   824		if (!devfreq) {
   825			err = -ENOMEM;
   826			goto err_out;
   827		}
   828	
   829		mutex_init(&devfreq->lock);
   830		mutex_lock(&devfreq->lock);
   831		devfreq->dev.parent = dev;
   832		devfreq->dev.class = devfreq_class;
   833		devfreq->dev.release = devfreq_dev_release;
   834		INIT_LIST_HEAD(&devfreq->node);
   835		devfreq->profile = profile;
   836		devfreq->previous_freq = profile->initial_freq;
   837		devfreq->last_status.current_frequency = profile->initial_freq;
   838		devfreq->data = data;
   839		devfreq->nb.notifier_call = devfreq_notifier_call;
   840	
   841		if (devfreq->profile->timer < 0
   842			|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
   843			mutex_unlock(&devfreq->lock);
   844			err = -EINVAL;
   845			goto err_dev;
   846		}
   847	
   848		if (!devfreq->profile->max_state || !devfreq->profile->freq_table) {
   849			mutex_unlock(&devfreq->lock);
   850			err = set_freq_table(devfreq);
   851			if (err < 0)
   852				goto err_dev;
   853			mutex_lock(&devfreq->lock);
   854		} else {
   855			devfreq->freq_table = devfreq->profile->freq_table;
   856			devfreq->max_state = devfreq->profile->max_state;
   857		}
   858	
   859		devfreq->scaling_min_freq = find_available_min_freq(devfreq);
   860		if (!devfreq->scaling_min_freq) {
   861			mutex_unlock(&devfreq->lock);
   862			err = -EINVAL;
   863			goto err_dev;
   864		}
   865	
   866		devfreq->scaling_max_freq = find_available_max_freq(devfreq);
   867		if (!devfreq->scaling_max_freq) {
   868			mutex_unlock(&devfreq->lock);
   869			err = -EINVAL;
   870			goto err_dev;
   871		}
   872	
   873		devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
   874	
   875		devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
   876		devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
   877		if (IS_ERR(devfreq->opp_table))
   878			devfreq->opp_table = NULL;
   879	
   880		atomic_set(&devfreq->suspend_count, 0);
   881	
   882		if (profile->name)
   883			dev_set_name(&devfreq->dev, "df%d", id);
   884		else
   885			dev_set_name(&devfreq->dev, "%s", dev_name(dev));
   886		err = device_register(&devfreq->dev);
   887		if (err) {
   888			mutex_unlock(&devfreq->lock);
   889			put_device(&devfreq->dev);
   890			goto err_out;
   891		}
   892	
   893		devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
   894				array3_size(sizeof(unsigned int),
   895					    devfreq->max_state,
   896					    devfreq->max_state),
   897				GFP_KERNEL);
   898		if (!devfreq->stats.trans_table) {
   899			mutex_unlock(&devfreq->lock);
   900			err = -ENOMEM;
   901			goto err_devfreq;
   902		}
   903	
   904		devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
   905				devfreq->max_state,
   906				sizeof(*devfreq->stats.time_in_state),
   907				GFP_KERNEL);
   908		if (!devfreq->stats.time_in_state) {
   909			mutex_unlock(&devfreq->lock);
   910			err = -ENOMEM;
   911			goto err_devfreq;
   912		}
   913	
   914		devfreq->stats.total_trans = 0;
   915		devfreq->stats.last_update = get_jiffies_64();
   916	
   917		srcu_init_notifier_head(&devfreq->transition_notifier_list);
   918	
   919		mutex_unlock(&devfreq->lock);
   920	
   921		err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
   922					     DEV_PM_QOS_MIN_FREQUENCY, 0);
   923		if (err < 0)
   924			goto err_devfreq;
   925		err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
   926					     DEV_PM_QOS_MAX_FREQUENCY,
   927					     PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
   928		if (err < 0)
   929			goto err_devfreq;
   930	
   931		devfreq->nb_min.notifier_call = qos_min_notifier_call;
   932		err = dev_pm_qos_add_notifier(dev, &devfreq->nb_min,
   933					      DEV_PM_QOS_MIN_FREQUENCY);
   934		if (err)
   935			goto err_devfreq;
   936	
   937		devfreq->nb_max.notifier_call = qos_max_notifier_call;
   938		err = dev_pm_qos_add_notifier(dev, &devfreq->nb_max,
   939					      DEV_PM_QOS_MAX_FREQUENCY);
   940		if (err)
   941			goto err_devfreq;
   942	
   943		mutex_lock(&devfreq_list_lock);
   944	
   945		governor = try_then_request_governor(governor_name);
   946		if (IS_ERR(governor)) {
   947			dev_err(dev, "%s: Unable to find governor for the device\n",
   948				__func__);
   949			err = PTR_ERR(governor);
   950			goto err_init;
   951		}
   952	
   953		devfreq->governor = governor;
   954		err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
   955							NULL);
   956		if (err) {
   957			dev_err_probe(dev, err,
   958				"%s: Unable to start governor for the device\n",
   959				 __func__);
   960			goto err_init;
   961		}
   962		create_sysfs_files(devfreq, devfreq->governor);
   963	
   964		list_add(&devfreq->node, &devfreq_list);
   965	
   966		mutex_unlock(&devfreq_list_lock);
   967	
   968		if (devfreq->profile->is_cooling_device) {
   969			devfreq->cdev = devfreq_cooling_em_register(devfreq, NULL);
   970			if (IS_ERR(devfreq->cdev))
   971				devfreq->cdev = NULL;
   972		}
   973	
   974		return devfreq;
   975	
   976	err_ida:
   977		ida_free(&devfreq_ida, id);
   978	err_init:
   979		mutex_unlock(&devfreq_list_lock);
   980	err_devfreq:
   981		devfreq_remove_device(devfreq);
   982		devfreq = NULL;
   983	err_dev:
   984		kfree(devfreq);
   985	err_out:
   986		return ERR_PTR(err);
   987	}
   988	EXPORT_SYMBOL(devfreq_add_device);
   989	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-11-06  0:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-17 21:19 [RFC PATCH] PM / devfreq: introduce multiple devfreq devices per parent device Rodrigo Vivi
2023-10-18 15:56 ` Chanwoo Choi
2023-11-06  0:22 ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.