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 <asm/cpu_ops.h>
14 extern char secondary_start_sbi
[];
15 const struct cpu_operations cpu_ops_sbi
;
17 static int sbi_hsm_hart_start(unsigned long hartid
, unsigned long saddr
,
22 ret
= sbi_ecall(SBI_EXT_HSM
, SBI_EXT_HSM_HART_START
,
23 hartid
, saddr
, priv
, 0, 0, 0);
25 return sbi_err_map_linux_errno(ret
.error
);
30 #ifdef CONFIG_HOTPLUG_CPU
31 static int sbi_hsm_hart_stop(void)
35 ret
= sbi_ecall(SBI_EXT_HSM
, SBI_EXT_HSM_HART_STOP
, 0, 0, 0, 0, 0, 0);
38 return sbi_err_map_linux_errno(ret
.error
);
43 static int sbi_hsm_hart_get_status(unsigned long hartid
)
47 ret
= sbi_ecall(SBI_EXT_HSM
, SBI_EXT_HSM_HART_STATUS
,
48 hartid
, 0, 0, 0, 0, 0);
50 return sbi_err_map_linux_errno(ret
.error
);
56 static int sbi_cpu_start(unsigned int cpuid
, struct task_struct
*tidle
)
59 unsigned long boot_addr
= __pa_symbol(secondary_start_sbi
);
60 int hartid
= cpuid_to_hartid_map(cpuid
);
62 cpu_update_secondary_bootdata(cpuid
, tidle
);
63 rc
= sbi_hsm_hart_start(hartid
, boot_addr
, 0);
68 static int sbi_cpu_prepare(unsigned int cpuid
)
70 if (!cpu_ops_sbi
.cpu_start
) {
71 pr_err("cpu start method not defined for CPU [%d]\n", cpuid
);
77 #ifdef CONFIG_HOTPLUG_CPU
78 static int sbi_cpu_disable(unsigned int cpuid
)
80 if (!cpu_ops_sbi
.cpu_stop
)
85 static void sbi_cpu_stop(void)
89 ret
= sbi_hsm_hart_stop();
90 pr_crit("Unable to stop the cpu %u (%d)\n", smp_processor_id(), ret
);
93 static int sbi_cpu_is_stopped(unsigned int cpuid
)
96 int hartid
= cpuid_to_hartid_map(cpuid
);
98 rc
= sbi_hsm_hart_get_status(hartid
);
100 if (rc
== SBI_HSM_HART_STATUS_STOPPED
)
106 const struct cpu_operations cpu_ops_sbi
= {
108 .cpu_prepare
= sbi_cpu_prepare
,
109 .cpu_start
= sbi_cpu_start
,
110 #ifdef CONFIG_HOTPLUG_CPU
111 .cpu_disable
= sbi_cpu_disable
,
112 .cpu_stop
= sbi_cpu_stop
,
113 .cpu_is_stopped
= sbi_cpu_is_stopped
,