@ -40,6 +40,8 @@ do { \
" opp_table_lock protection " ) ; \
} while ( 0 )
static void dev_pm_opp_get ( struct dev_pm_opp * opp ) ;
static struct opp_device * _find_opp_dev ( const struct device * dev ,
struct opp_table * opp_table )
{
@ -94,21 +96,13 @@ struct opp_table *_find_opp_table(struct device *dev)
* return 0
*
* This is useful only for devices with single power supply .
*
* Locking : This function must be called under rcu_read_lock ( ) . opp is a rcu
* protected pointer . This means that opp which could have been fetched by
* opp_find_freq_ { exact , ceil , floor } functions is valid as long as we are
* under RCU lock . The pointer returned by the opp_find_freq family must be
* used in the same section as the usage of this function with the pointer
* prior to unlocking with rcu_read_unlock ( ) to maintain the integrity of the
* pointer .
*/
unsigned long dev_pm_opp_get_voltage ( struct dev_pm_opp * opp )
{
struct dev_pm_opp * tmp_opp ;
unsigned long v = 0 ;
opp_ rcu_lockdep_assert ( ) ;
rcu_read_lock ( ) ;
tmp_opp = rcu_dereference ( opp ) ;
if ( IS_ERR_OR_NULL ( tmp_opp ) )
@ -116,6 +110,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
else
v = tmp_opp - > supplies [ 0 ] . u_volt ;
rcu_read_unlock ( ) ;
return v ;
}
EXPORT_SYMBOL_GPL ( dev_pm_opp_get_voltage ) ;
@ -126,21 +121,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
*
* Return : frequency in hertz corresponding to the opp , else
* return 0
*
* Locking : This function must be called under rcu_read_lock ( ) . opp is a rcu
* protected pointer . This means that opp which could have been fetched by
* opp_find_freq_ { exact , ceil , floor } functions is valid as long as we are
* under RCU lock . The pointer returned by the opp_find_freq family must be
* used in the same section as the usage of this function with the pointer
* prior to unlocking with rcu_read_unlock ( ) to maintain the integrity of the
* pointer .
*/
unsigned long dev_pm_opp_get_freq ( struct dev_pm_opp * opp )
{
struct dev_pm_opp * tmp_opp ;
unsigned long f = 0 ;
opp_ rcu_lockdep_assert ( ) ;
rcu_read_lock ( ) ;
tmp_opp = rcu_dereference ( opp ) ;
if ( IS_ERR_OR_NULL ( tmp_opp ) | | ! tmp_opp - > available )
@ -148,6 +135,7 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
else
f = tmp_opp - > rate ;
rcu_read_unlock ( ) ;
return f ;
}
EXPORT_SYMBOL_GPL ( dev_pm_opp_get_freq ) ;
@ -161,20 +149,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
* quickly . Running on them for longer times may overheat the chip .
*
* Return : true if opp is turbo opp , else false .
*
* Locking : This function must be called under rcu_read_lock ( ) . opp is a rcu
* protected pointer . This means that opp which could have been fetched by
* opp_find_freq_ { exact , ceil , floor } functions is valid as long as we are
* under RCU lock . The pointer returned by the opp_find_freq family must be
* used in the same section as the usage of this function with the pointer
* prior to unlocking with rcu_read_unlock ( ) to maintain the integrity of the
* pointer .
*/
bool dev_pm_opp_is_turbo ( struct dev_pm_opp * opp )
{
struct dev_pm_opp * tmp_opp ;
bool turbo ;
opp_ rcu_lockdep_assert ( ) ;
rcu_read_lock ( ) ;
tmp_opp = rcu_dereference ( opp ) ;
if ( IS_ERR_OR_NULL ( tmp_opp ) | | ! tmp_opp - > available ) {
@ -182,7 +163,10 @@ bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp)
return false ;
}
return tmp_opp - > turbo ;
turbo = tmp_opp - > turbo ;
rcu_read_unlock ( ) ;
return turbo ;
}
EXPORT_SYMBOL_GPL ( dev_pm_opp_is_turbo ) ;
@ -410,11 +394,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
* This provides a mechanism to enable an opp which is not available currently
* or the opposite as well .
*
* Locking : This function must be called under rcu_read_lock ( ) . opp is a rcu
* protected pointer . The reason for the same is that the opp pointer which is
* returned will remain valid for use with opp_get_ { voltage , freq } only while
* under the locked area . The pointer returned must be used prior to unlocking
* with rcu_read_unlock ( ) to maintain the integrity of the pointer .
* The callers are required to call dev_pm_opp_put ( ) for the returned OPP after
* use .
*/
struct dev_pm_opp * dev_pm_opp_find_freq_exact ( struct device * dev ,
unsigned long freq ,
@ -423,13 +404,14 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
struct opp_table * opp_table ;
struct dev_pm_opp * temp_opp , * opp = ERR_PTR ( - ERANGE ) ;
opp_ rcu_lockdep_assert ( ) ;
rcu_read_ lock ( ) ;
opp_table = _find_opp_table ( dev ) ;
if ( IS_ERR ( opp_table ) ) {
int r = PTR_ERR ( opp_table ) ;
dev_err ( dev , " %s: OPP table not found (%d) \n " , __func__ , r ) ;
rcu_read_unlock ( ) ;
return ERR_PTR ( r ) ;
}
@ -437,10 +419,15 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
if ( temp_opp - > available = = available & &
temp_opp - > rate = = freq ) {
opp = temp_opp ;
/* Increment the reference count of OPP */
dev_pm_opp_get ( opp ) ;
break ;
}
}
rcu_read_unlock ( ) ;
return opp ;
}
EXPORT_SYMBOL_GPL ( dev_pm_opp_find_freq_exact ) ;
@ -454,6 +441,9 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
if ( temp_opp - > available & & temp_opp - > rate > = * freq ) {
opp = temp_opp ;
* freq = opp - > rate ;
/* Increment the reference count of OPP */
dev_pm_opp_get ( opp ) ;
break ;
}
}
@ -476,29 +466,33 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
* ERANGE : no match found for search
* ENODEV : if device not found in list of registered devices
*
* Locking : This function must be called under rcu_read_lock ( ) . opp is a rcu
* protected pointer . The reason for the same is that the opp pointer which is
* returned will remain valid for use with opp_get_ { voltage , freq } only while
* under the locked area . The pointer returned must be used prior to unlocking
* with rcu_read_unlock ( ) to maintain the integrity of the pointer .
* The callers are required to call dev_pm_opp_put ( ) for the returned OPP after
* use .
*/
struct dev_pm_opp * dev_pm_opp_find_freq_ceil ( struct device * dev ,
unsigned long * freq )
{
struct opp_table * opp_table ;
opp_rcu_lockdep_assert ( ) ;
struct dev_pm_opp * opp ;
if ( ! dev | | ! freq ) {
dev_err ( dev , " %s: Invalid argument freq=%p \n " , __func__ , freq ) ;
return ERR_PTR ( - EINVAL ) ;
}
rcu_read_lock ( ) ;
opp_table = _find_opp_table ( dev ) ;
if ( IS_ERR ( opp_table ) )
if ( IS_ERR ( opp_table ) ) {
rcu_read_unlock ( ) ;
return ERR_CAST ( opp_table ) ;
}
opp = _find_freq_ceil ( opp_table , freq ) ;
return _find_freq_ceil ( opp_table , freq ) ;
rcu_read_unlock ( ) ;
return opp ;
}
EXPORT_SYMBOL_GPL ( dev_pm_opp_find_freq_ceil ) ;
@ -517,11 +511,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
* ERANGE : no match found for search
* ENODEV : if device not found in list of registered devices
*
* Locking : This function must be called under rcu_read_lock ( ) . opp is a rcu
* protected pointer . The reason for the same is that the opp pointer which is
* returned will remain valid for use with opp_get_ { voltage , freq } only while
* under the locked area . The pointer returned must be used prior to unlocking
* with rcu_read_unlock ( ) to maintain the integrity of the pointer .
* The callers are required to call dev_pm_opp_put ( ) for the returned OPP after
* use .
*/
struct dev_pm_opp * dev_pm_opp_find_freq_floor ( struct device * dev ,
unsigned long * freq )
@ -529,16 +520,18 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
struct opp_table * opp_table ;
struct dev_pm_opp * temp_opp , * opp = ERR_PTR ( - ERANGE ) ;
opp_rcu_lockdep_assert ( ) ;
if ( ! dev | | ! freq ) {
dev_err ( dev , " %s: Invalid argument freq=%p \n " , __func__ , freq ) ;
return ERR_PTR ( - EINVAL ) ;
}
rcu_read_lock ( ) ;
opp_table = _find_opp_table ( dev ) ;
if ( IS_ERR ( opp_table ) )
if ( IS_ERR ( opp_table ) ) {
rcu_read_unlock ( ) ;
return ERR_CAST ( opp_table ) ;
}
list_for_each_entry_rcu ( temp_opp , & opp_table - > opp_list , node ) {
if ( temp_opp - > available ) {
@ -549,6 +542,12 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
opp = temp_opp ;
}
}
/* Increment the reference count of OPP */
if ( ! IS_ERR ( opp ) )
dev_pm_opp_get ( opp ) ;
rcu_read_unlock ( ) ;
if ( ! IS_ERR ( opp ) )
* freq = opp - > rate ;
@ -736,6 +735,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
ret = PTR_ERR ( opp ) ;
dev_err ( dev , " %s: failed to find OPP for freq %lu (%d) \n " ,
__func__ , freq , ret ) ;
if ( ! IS_ERR ( old_opp ) )
dev_pm_opp_put ( old_opp ) ;
rcu_read_unlock ( ) ;
return ret ;
}
@ -747,6 +748,9 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
/* Only frequency scaling */
if ( ! regulators ) {
dev_pm_opp_put ( opp ) ;
if ( ! IS_ERR ( old_opp ) )
dev_pm_opp_put ( old_opp ) ;
rcu_read_unlock ( ) ;
return _generic_set_opp_clk_only ( dev , clk , old_freq , freq ) ;
}
@ -772,6 +776,9 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
data - > new_opp . rate = freq ;
memcpy ( data - > new_opp . supplies , opp - > supplies , size ) ;
dev_pm_opp_put ( opp ) ;
if ( ! IS_ERR ( old_opp ) )
dev_pm_opp_put ( old_opp ) ;
rcu_read_unlock ( ) ;
return set_opp ( data ) ;
@ -967,6 +974,11 @@ static void _opp_kref_release(struct kref *kref)
dev_pm_opp_put_opp_table ( opp_table ) ;
}
static void dev_pm_opp_get ( struct dev_pm_opp * opp )
{
kref_get ( & opp - > kref ) ;
}
void dev_pm_opp_put ( struct dev_pm_opp * opp )
{
kref_put_mutex ( & opp - > kref , _opp_kref_release , & opp - > opp_table - > lock ) ;