3838
3939static struct class * devfreq_class ;
4040static struct dentry * devfreq_debugfs ;
41+ static const struct attribute_group gov_attr_group ;
4142
4243/*
4344 * devfreq core provides delayed work based load monitoring helper
@@ -146,10 +147,9 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
146147 DEV_PM_QOS_MIN_FREQUENCY );
147148 qos_max_freq = dev_pm_qos_read_value (devfreq -> dev .parent ,
148149 DEV_PM_QOS_MAX_FREQUENCY );
149- * min_freq = max (* min_freq , ( unsigned long ) HZ_PER_KHZ * qos_min_freq );
150+ * min_freq = max (* min_freq , HZ_PER_KHZ * qos_min_freq );
150151 if (qos_max_freq != PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE )
151- * max_freq = min (* max_freq ,
152- (unsigned long )HZ_PER_KHZ * qos_max_freq );
152+ * max_freq = min (* max_freq , HZ_PER_KHZ * qos_max_freq );
153153
154154 /* Apply constraints from OPP interface */
155155 * max_freq = clamp (* max_freq , devfreq -> scaling_min_freq , devfreq -> scaling_max_freq );
@@ -785,11 +785,6 @@ static void devfreq_dev_release(struct device *dev)
785785 kfree (devfreq );
786786}
787787
788- static void create_sysfs_files (struct devfreq * devfreq ,
789- const struct devfreq_governor * gov );
790- static void remove_sysfs_files (struct devfreq * devfreq ,
791- const struct devfreq_governor * gov );
792-
793788/**
794789 * devfreq_add_device() - Add devfreq feature to the device
795790 * @dev: the device to add devfreq feature.
@@ -956,7 +951,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
956951 __func__ );
957952 goto err_init ;
958953 }
959- create_sysfs_files (devfreq , devfreq -> governor );
954+
955+ err = sysfs_update_group (& devfreq -> dev .kobj , & gov_attr_group );
956+ if (err )
957+ goto err_init ;
960958
961959 list_add (& devfreq -> node , & devfreq_list );
962960
@@ -995,12 +993,9 @@ int devfreq_remove_device(struct devfreq *devfreq)
995993
996994 devfreq_cooling_unregister (devfreq -> cdev );
997995
998- if (devfreq -> governor ) {
996+ if (devfreq -> governor )
999997 devfreq -> governor -> event_handler (devfreq ,
1000998 DEVFREQ_GOV_STOP , NULL );
1001- remove_sysfs_files (devfreq , devfreq -> governor );
1002- }
1003-
1004999 device_unregister (& devfreq -> dev );
10051000
10061001 return 0 ;
@@ -1460,7 +1455,6 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
14601455 __func__ , df -> governor -> name , ret );
14611456 goto out ;
14621457 }
1463- remove_sysfs_files (df , df -> governor );
14641458
14651459 /*
14661460 * Start the new governor and create the specific sysfs files
@@ -1489,7 +1483,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
14891483 * Create the sysfs files for the new governor. But if failed to start
14901484 * the new governor, restore the sysfs files of previous governor.
14911485 */
1492- create_sysfs_files ( df , df -> governor );
1486+ ret = sysfs_update_group ( & df -> dev . kobj , & gov_attr_group );
14931487
14941488out :
14951489 mutex_unlock (& devfreq_list_lock );
@@ -1807,14 +1801,17 @@ static struct attribute *devfreq_attrs[] = {
18071801 & dev_attr_trans_stat .attr ,
18081802 NULL ,
18091803};
1810- ATTRIBUTE_GROUPS (devfreq );
18111804
18121805static ssize_t polling_interval_show (struct device * dev ,
18131806 struct device_attribute * attr , char * buf )
18141807{
18151808 struct devfreq * df = to_devfreq (dev );
18161809
1817- if (!df -> profile )
1810+ /* Protect against race between sysfs attrs update and read/write */
1811+ guard (mutex )(& devfreq_list_lock );
1812+
1813+ if (!df -> profile || !df -> governor ||
1814+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , POLLING_INTERVAL ))
18181815 return - EINVAL ;
18191816
18201817 return sprintf (buf , "%d\n" , df -> profile -> polling_ms );
@@ -1828,7 +1825,10 @@ static ssize_t polling_interval_store(struct device *dev,
18281825 unsigned int value ;
18291826 int ret ;
18301827
1831- if (!df -> governor )
1828+ guard (mutex )(& devfreq_list_lock );
1829+
1830+ if (!df -> governor ||
1831+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , POLLING_INTERVAL ))
18321832 return - EINVAL ;
18331833
18341834 ret = sscanf (buf , "%u" , & value );
@@ -1847,7 +1847,10 @@ static ssize_t timer_show(struct device *dev,
18471847{
18481848 struct devfreq * df = to_devfreq (dev );
18491849
1850- if (!df -> profile )
1850+ guard (mutex )(& devfreq_list_lock );
1851+
1852+ if (!df -> profile || !df -> governor ||
1853+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , TIMER ))
18511854 return - EINVAL ;
18521855
18531856 return sprintf (buf , "%s\n" , timer_name [df -> profile -> timer ]);
@@ -1861,7 +1864,10 @@ static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
18611864 int timer = -1 ;
18621865 int ret = 0 , i ;
18631866
1864- if (!df -> governor || !df -> profile )
1867+ guard (mutex )(& devfreq_list_lock );
1868+
1869+ if (!df -> governor || !df -> profile ||
1870+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , TIMER ))
18651871 return - EINVAL ;
18661872
18671873 ret = sscanf (buf , "%16s" , str_timer );
@@ -1905,37 +1911,47 @@ static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
19051911}
19061912static DEVICE_ATTR_RW (timer );
19071913
1908- #define CREATE_SYSFS_FILE (df , name ) \
1909- { \
1910- int ret; \
1911- ret = sysfs_create_file(&df->dev.kobj, &dev_attr_##name.attr); \
1912- if (ret < 0) { \
1913- dev_warn(&df->dev, \
1914- "Unable to create attr(%s)\n", "##name"); \
1915- } \
1916- } \
1914+ static struct attribute * governor_attrs [] = {
1915+ & dev_attr_polling_interval .attr ,
1916+ & dev_attr_timer .attr ,
1917+ NULL
1918+ };
19171919
1918- /* Create the specific sysfs files which depend on each governor. */
1919- static void create_sysfs_files (struct devfreq * devfreq ,
1920- const struct devfreq_governor * gov )
1920+ static umode_t gov_attr_visible (struct kobject * kobj ,
1921+ struct attribute * attr , int n )
19211922{
1922- if (IS_SUPPORTED_ATTR (gov -> attrs , POLLING_INTERVAL ))
1923- CREATE_SYSFS_FILE (devfreq , polling_interval );
1924- if (IS_SUPPORTED_ATTR (gov -> attrs , TIMER ))
1925- CREATE_SYSFS_FILE (devfreq , timer );
1926- }
1923+ struct device * dev = kobj_to_dev (kobj );
1924+ struct devfreq * df = to_devfreq (dev );
19271925
1928- /* Remove the specific sysfs files which depend on each governor. */
1929- static void remove_sysfs_files (struct devfreq * devfreq ,
1930- const struct devfreq_governor * gov )
1931- {
1932- if (IS_SUPPORTED_ATTR (gov -> attrs , POLLING_INTERVAL ))
1933- sysfs_remove_file (& devfreq -> dev .kobj ,
1934- & dev_attr_polling_interval .attr );
1935- if (IS_SUPPORTED_ATTR (gov -> attrs , TIMER ))
1936- sysfs_remove_file (& devfreq -> dev .kobj , & dev_attr_timer .attr );
1926+ if (!df -> governor || !df -> governor -> attrs )
1927+ return 0 ;
1928+
1929+ if (attr == & dev_attr_polling_interval .attr &&
1930+ IS_SUPPORTED_ATTR (df -> governor -> attrs , POLLING_INTERVAL ))
1931+ return attr -> mode ;
1932+
1933+ if (attr == & dev_attr_timer .attr &&
1934+ IS_SUPPORTED_ATTR (df -> governor -> attrs , TIMER ))
1935+ return attr -> mode ;
1936+
1937+ return 0 ;
19371938}
19381939
1940+ static const struct attribute_group devfreq_group = {
1941+ .attrs = devfreq_attrs ,
1942+ };
1943+
1944+ static const struct attribute_group gov_attr_group = {
1945+ .attrs = governor_attrs ,
1946+ .is_visible = gov_attr_visible ,
1947+ };
1948+
1949+ static const struct attribute_group * devfreq_groups [] = {
1950+ & devfreq_group ,
1951+ & gov_attr_group ,
1952+ NULL
1953+ };
1954+
19391955/**
19401956 * devfreq_summary_show() - Show the summary of the devfreq devices
19411957 * @s: seq_file instance to show the summary of devfreq devices
0 commit comments