2020-03-17 18:11:40 -07:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( c ) 2020 Western Digital Corporation or its affiliates .
*/
# include <linux/errno.h>
# include <linux/of.h>
# include <linux/string.h>
2022-01-20 01:09:15 -08:00
# include <linux/sched/task_stack.h>
2020-03-17 18:11:40 -07:00
# include <asm/cpu_ops.h>
# include <asm/sbi.h>
# include <asm/smp.h>
2022-07-13 22:53:06 +01:00
# include "head.h"
2020-03-17 18:11:40 -07:00
const struct cpu_operations cpu_ops_spinwait ;
2022-01-20 01:09:15 -08:00
void * __cpu_spinwait_stack_pointer [ NR_CPUS ] __section ( " .data " ) ;
void * __cpu_spinwait_task_pointer [ NR_CPUS ] __section ( " .data " ) ;
static void cpu_update_secondary_bootdata ( unsigned int cpuid ,
struct task_struct * tidle )
{
2022-05-27 10:47:40 +05:30
unsigned long hartid = cpuid_to_hartid_map ( cpuid ) ;
2022-01-20 01:09:15 -08:00
/*
* The hartid must be less than NR_CPUS to avoid out - of - bound access
* errors for __cpu_spinwait_stack / task_pointer . That is not always possible
* for platforms with discontiguous hartid numbering scheme . That ' s why
* spinwait booting is not the recommended approach for any platforms
* booting Linux in S - mode and can be disabled in the future .
*/
2022-05-27 10:47:40 +05:30
if ( hartid = = INVALID_HARTID | | hartid > = ( unsigned long ) NR_CPUS )
2022-01-20 01:09:15 -08:00
return ;
/* Make sure tidle is updated */
smp_mb ( ) ;
WRITE_ONCE ( __cpu_spinwait_stack_pointer [ hartid ] ,
task_stack_page ( tidle ) + THREAD_SIZE ) ;
WRITE_ONCE ( __cpu_spinwait_task_pointer [ hartid ] , tidle ) ;
}
2020-03-17 18:11:40 -07:00
static int spinwait_cpu_prepare ( unsigned int cpuid )
{
if ( ! cpu_ops_spinwait . cpu_start ) {
pr_err ( " cpu start method not defined for CPU [%d] \n " , cpuid ) ;
return - ENODEV ;
}
return 0 ;
}
static int spinwait_cpu_start ( unsigned int cpuid , struct task_struct * tidle )
{
/*
* In this protocol , all cpus boot on their own accord . _start
* selects the first cpu to boot the kernel and causes the remainder
* of the cpus to spin in a loop waiting for their stack pointer to be
* setup by that main cpu . Writing to bootdata
2022-01-20 01:09:15 -08:00
* ( i . e __cpu_spinwait_stack_pointer ) signals to the spinning cpus that they
2020-03-17 18:11:40 -07:00
* can continue the boot process .
*/
cpu_update_secondary_bootdata ( cpuid , tidle ) ;
return 0 ;
}
const struct cpu_operations cpu_ops_spinwait = {
. name = " spinwait " ,
. cpu_prepare = spinwait_cpu_prepare ,
. cpu_start = spinwait_cpu_start ,
} ;