1 // SPDX-License-Identifier: GPL-2.0-only
3 * HSM extension and cpu_ops implementation.
5 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
8 #include <linux/init.h>
10 #include <linux/sched/task_stack.h>
11 #include <asm/cpu_ops.h>
12 #include <asm/cpu_ops_sbi.h>
16 extern char secondary_start_sbi
[];
17 const struct cpu_operations cpu_ops_sbi
;
20 * Ordered booting via HSM brings one cpu at a time. However, cpu hotplug can
21 * be invoked from multiple threads in parallel. Define a per cpu data
24 static DEFINE_PER_CPU(struct sbi_hart_boot_data
, boot_data
);
26 static int sbi_hsm_hart_start(unsigned long hartid
, unsigned long saddr
,
31 ret
= sbi_ecall(SBI_EXT_HSM
, SBI_EXT_HSM_HART_START
,
32 hartid
, saddr
, priv
, 0, 0, 0);
34 return sbi_err_map_linux_errno(ret
.error
);
39 #ifdef CONFIG_HOTPLUG_CPU
40 static int sbi_hsm_hart_stop(void)
44 ret
= sbi_ecall(SBI_EXT_HSM
, SBI_EXT_HSM_HART_STOP
, 0, 0, 0, 0, 0, 0);
47 return sbi_err_map_linux_errno(ret
.error
);
52 static int sbi_hsm_hart_get_status(unsigned long hartid
)
56 ret
= sbi_ecall(SBI_EXT_HSM
, SBI_EXT_HSM_HART_STATUS
,
57 hartid
, 0, 0, 0, 0, 0);
59 return sbi_err_map_linux_errno(ret
.error
);
65 static int sbi_cpu_start(unsigned int cpuid
, struct task_struct
*tidle
)
67 unsigned long boot_addr
= __pa_symbol(secondary_start_sbi
);
68 unsigned long hartid
= cpuid_to_hartid_map(cpuid
);
69 unsigned long hsm_data
;
70 struct sbi_hart_boot_data
*bdata
= &per_cpu(boot_data
, cpuid
);
72 /* Make sure tidle is updated */
74 bdata
->task_ptr
= tidle
;
75 bdata
->stack_ptr
= task_pt_regs(tidle
);
76 /* Make sure boot data is updated */
78 hsm_data
= __pa(bdata
);
79 return sbi_hsm_hart_start(hartid
, boot_addr
, hsm_data
);
82 #ifdef CONFIG_HOTPLUG_CPU
83 static void sbi_cpu_stop(void)
87 ret
= sbi_hsm_hart_stop();
88 pr_crit("Unable to stop the cpu %u (%d)\n", smp_processor_id(), ret
);
91 static int sbi_cpu_is_stopped(unsigned int cpuid
)
94 unsigned long hartid
= cpuid_to_hartid_map(cpuid
);
96 rc
= sbi_hsm_hart_get_status(hartid
);
98 if (rc
== SBI_HSM_STATE_STOPPED
)
104 const struct cpu_operations cpu_ops_sbi
= {
105 .cpu_start
= sbi_cpu_start
,
106 #ifdef CONFIG_HOTPLUG_CPU
107 .cpu_stop
= sbi_cpu_stop
,
108 .cpu_is_stopped
= sbi_cpu_is_stopped
,