2019-05-27 09:55:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-07-20 23:39:22 +04:00
/*
* pmi backend for the cbe_cpufreq driver
*
* ( C ) Copyright IBM Deutschland Entwicklung GmbH 2005 - 2007
*
* Author : Christian Krafft < krafft @ de . ibm . com >
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/timer.h>
2016-03-28 01:08:17 +03:00
# include <linux/init.h>
2007-11-13 20:10:58 +03:00
# include <linux/of_platform.h>
2019-07-05 13:19:48 +03:00
# include <linux/pm_qos.h>
2007-11-13 20:10:58 +03:00
2007-07-20 23:39:22 +04:00
# include <asm/processor.h>
# include <asm/prom.h>
# include <asm/pmi.h>
2007-10-04 09:40:42 +04:00
# include <asm/cell-regs.h>
2007-07-20 23:39:22 +04:00
# ifdef DEBUG
# include <asm/time.h>
# endif
2013-03-25 09:50:23 +04:00
# include "ppc_cbe_cpufreq.h"
2007-07-20 23:39:22 +04:00
bool cbe_cpufreq_has_pmi = false ;
EXPORT_SYMBOL_GPL ( cbe_cpufreq_has_pmi ) ;
/*
* hardware specific functions
*/
int cbe_cpufreq_set_pmode_pmi ( int cpu , unsigned int pmode )
{
int ret ;
pmi_message_t pmi_msg ;
# ifdef DEBUG
long time ;
# endif
pmi_msg . type = PMI_TYPE_FREQ_CHANGE ;
pmi_msg . data1 = cbe_cpu_to_node ( cpu ) ;
pmi_msg . data2 = pmode ;
# ifdef DEBUG
time = jiffies ;
# endif
pmi_send_message ( pmi_msg ) ;
# ifdef DEBUG
time = jiffies - time ;
time = jiffies_to_msecs ( time ) ;
pr_debug ( " had to wait %lu ms for a transition using " \
" PMI \n " , time ) ;
# endif
ret = pmi_msg . data2 ;
pr_debug ( " PMI returned slow mode %d \n " , ret ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( cbe_cpufreq_set_pmode_pmi ) ;
static void cbe_cpufreq_handle_pmi ( pmi_message_t pmi_msg )
{
2019-07-05 13:19:48 +03:00
struct cpufreq_policy * policy ;
struct dev_pm_qos_request * req ;
2007-07-20 23:39:22 +04:00
u8 node , slow_mode ;
2019-07-05 13:19:48 +03:00
int cpu , ret ;
2007-07-20 23:39:22 +04:00
BUG_ON ( pmi_msg . type ! = PMI_TYPE_FREQ_CHANGE ) ;
node = pmi_msg . data1 ;
slow_mode = pmi_msg . data2 ;
2019-07-05 13:19:48 +03:00
cpu = cbe_node_to_cpu ( node ) ;
2007-07-20 23:39:22 +04:00
pr_debug ( " cbe_handle_pmi: node: %d max_freq: %d \n " , node , slow_mode ) ;
2019-07-05 13:19:48 +03:00
policy = cpufreq_cpu_get ( cpu ) ;
if ( ! policy ) {
pr_warn ( " cpufreq policy not found cpu%d \n " , cpu ) ;
return ;
}
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
req = policy - > driver_data ;
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
ret = dev_pm_qos_update_request ( req ,
policy - > freq_table [ slow_mode ] . frequency ) ;
if ( ret < 0 )
pr_warn ( " Failed to update freq constraint: %d \n " , ret ) ;
else
pr_debug ( " limiting node %d to slow mode %d \n " , node , slow_mode ) ;
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
cpufreq_cpu_put ( policy ) ;
2007-07-20 23:39:22 +04:00
}
static struct pmi_handler cbe_pmi_handler = {
. type = PMI_TYPE_FREQ_CHANGE ,
. handle_pmi_message = cbe_cpufreq_handle_pmi ,
} ;
2019-07-05 13:19:48 +03:00
void cbe_cpufreq_pmi_policy_init ( struct cpufreq_policy * policy )
{
struct dev_pm_qos_request * req ;
int ret ;
if ( ! cbe_cpufreq_has_pmi )
return ;
req = kzalloc ( sizeof ( * req ) , GFP_KERNEL ) ;
if ( ! req )
return ;
ret = dev_pm_qos_add_request ( get_cpu_device ( policy - > cpu ) , req ,
DEV_PM_QOS_MAX_FREQUENCY ,
policy - > freq_table [ 0 ] . frequency ) ;
if ( ret < 0 ) {
pr_err ( " Failed to add freq constraint (%d) \n " , ret ) ;
kfree ( req ) ;
return ;
}
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
policy - > driver_data = req ;
}
EXPORT_SYMBOL_GPL ( cbe_cpufreq_pmi_policy_init ) ;
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
void cbe_cpufreq_pmi_policy_exit ( struct cpufreq_policy * policy )
2007-07-20 23:39:22 +04:00
{
2019-07-05 13:19:48 +03:00
struct dev_pm_qos_request * req = policy - > driver_data ;
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
if ( cbe_cpufreq_has_pmi ) {
dev_pm_qos_remove_request ( req ) ;
kfree ( req ) ;
}
}
EXPORT_SYMBOL_GPL ( cbe_cpufreq_pmi_policy_exit ) ;
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
void cbe_cpufreq_pmi_init ( void )
{
if ( ! pmi_register_handler ( & cbe_pmi_handler ) )
cbe_cpufreq_has_pmi = true ;
}
EXPORT_SYMBOL_GPL ( cbe_cpufreq_pmi_init ) ;
2007-07-20 23:39:22 +04:00
2019-07-05 13:19:48 +03:00
void cbe_cpufreq_pmi_exit ( void )
{
pmi_unregister_handler ( & cbe_pmi_handler ) ;
cbe_cpufreq_has_pmi = false ;
2007-07-20 23:39:22 +04:00
}
2019-07-05 13:19:48 +03:00
EXPORT_SYMBOL_GPL ( cbe_cpufreq_pmi_exit ) ;