2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-11-20 01:02:17 +04:00
/*
* linux / arch / arm / mach - vexpress / mcpm_platsmp . c
*
* Created by : Nicolas Pitre , November 2012
* Copyright : ( C ) 2012 - 2013 Linaro Limited
*
* Code to handle secondary CPU bringup and hotplug for the cluster power API .
*/
# include <linux/init.h>
# include <linux/smp.h>
# include <linux/spinlock.h>
# include <asm/mcpm.h>
# include <asm/smp.h>
# include <asm/smp_plat.h>
2013-10-01 22:57:28 +04:00
static void cpu_to_pcpu ( unsigned int cpu ,
unsigned int * pcpu , unsigned int * pcluster )
{
unsigned int mpidr ;
mpidr = cpu_logical_map ( cpu ) ;
* pcpu = MPIDR_AFFINITY_LEVEL ( mpidr , 0 ) ;
* pcluster = MPIDR_AFFINITY_LEVEL ( mpidr , 1 ) ;
}
2013-06-17 23:43:14 +04:00
static int mcpm_boot_secondary ( unsigned int cpu , struct task_struct * idle )
2012-11-20 01:02:17 +04:00
{
2013-10-01 22:57:28 +04:00
unsigned int pcpu , pcluster , ret ;
2012-11-20 01:02:17 +04:00
extern void secondary_startup ( void ) ;
2013-10-01 22:57:28 +04:00
cpu_to_pcpu ( cpu , & pcpu , & pcluster ) ;
2012-11-20 01:02:17 +04:00
pr_debug ( " %s: logical CPU %d is physical CPU %d cluster %d \n " ,
__func__ , cpu , pcpu , pcluster ) ;
mcpm_set_entry_vector ( pcpu , pcluster , NULL ) ;
ret = mcpm_cpu_power_up ( pcpu , pcluster ) ;
if ( ret )
return ret ;
mcpm_set_entry_vector ( pcpu , pcluster , secondary_startup ) ;
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
dsb_sev ( ) ;
return 0 ;
}
2013-06-17 23:43:14 +04:00
static void mcpm_secondary_init ( unsigned int cpu )
2012-11-20 01:02:17 +04:00
{
mcpm_cpu_powered_up ( ) ;
}
# ifdef CONFIG_HOTPLUG_CPU
2013-10-01 22:58:17 +04:00
static int mcpm_cpu_kill ( unsigned int cpu )
{
unsigned int pcpu , pcluster ;
cpu_to_pcpu ( cpu , & pcpu , & pcluster ) ;
2014-04-17 19:58:39 +04:00
return ! mcpm_wait_for_cpu_powerdown ( pcpu , pcluster ) ;
2013-10-01 22:58:17 +04:00
}
2015-07-29 02:34:48 +03:00
static bool mcpm_cpu_can_disable ( unsigned int cpu )
2012-11-20 01:02:17 +04:00
{
2015-07-29 02:34:48 +03:00
/* We assume all CPUs may be shut down. */
return true ;
2012-11-20 01:02:17 +04:00
}
static void mcpm_cpu_die ( unsigned int cpu )
{
unsigned int mpidr , pcpu , pcluster ;
mpidr = read_cpuid_mpidr ( ) ;
pcpu = MPIDR_AFFINITY_LEVEL ( mpidr , 0 ) ;
pcluster = MPIDR_AFFINITY_LEVEL ( mpidr , 1 ) ;
mcpm_set_entry_vector ( pcpu , pcluster , NULL ) ;
mcpm_cpu_power_down ( ) ;
}
# endif
2015-11-15 04:39:53 +03:00
static const struct smp_operations mcpm_smp_ops __initconst = {
2012-11-20 01:02:17 +04:00
. smp_boot_secondary = mcpm_boot_secondary ,
. smp_secondary_init = mcpm_secondary_init ,
# ifdef CONFIG_HOTPLUG_CPU
2013-10-01 22:58:17 +04:00
. cpu_kill = mcpm_cpu_kill ,
2015-07-29 02:34:48 +03:00
. cpu_can_disable = mcpm_cpu_can_disable ,
2012-11-20 01:02:17 +04:00
. cpu_die = mcpm_cpu_die ,
# endif
} ;
2013-04-09 09:29:17 +04:00
void __init mcpm_smp_set_ops ( void )
{
smp_set_ops ( & mcpm_smp_ops ) ;
}