Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * HSM extension and cpu_ops implementation.
  4 *
  5 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  6 */
  7
  8#include <linux/init.h>
  9#include <linux/mm.h>
 10#include <asm/cpu_ops.h>
 11#include <asm/sbi.h>
 12#include <asm/smp.h>
 13
 14extern char secondary_start_sbi[];
 15const struct cpu_operations cpu_ops_sbi;
 16
 17static int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
 18			      unsigned long priv)
 19{
 20	struct sbiret ret;
 21
 22	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START,
 23			hartid, saddr, priv, 0, 0, 0);
 24	if (ret.error)
 25		return sbi_err_map_linux_errno(ret.error);
 26	else
 27		return 0;
 28}
 29
 30#ifdef CONFIG_HOTPLUG_CPU
 31static int sbi_hsm_hart_stop(void)
 32{
 33	struct sbiret ret;
 34
 35	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
 36
 37	if (ret.error)
 38		return sbi_err_map_linux_errno(ret.error);
 39	else
 40		return 0;
 41}
 42
 43static int sbi_hsm_hart_get_status(unsigned long hartid)
 44{
 45	struct sbiret ret;
 46
 47	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS,
 48			hartid, 0, 0, 0, 0, 0);
 49	if (ret.error)
 50		return sbi_err_map_linux_errno(ret.error);
 51	else
 52		return ret.value;
 53}
 54#endif
 55
 56static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
 57{
 58	int rc;
 59	unsigned long boot_addr = __pa_symbol(secondary_start_sbi);
 60	int hartid = cpuid_to_hartid_map(cpuid);
 61
 62	cpu_update_secondary_bootdata(cpuid, tidle);
 63	rc = sbi_hsm_hart_start(hartid, boot_addr, 0);
 64
 65	return rc;
 66}
 67
 68static int sbi_cpu_prepare(unsigned int cpuid)
 69{
 70	if (!cpu_ops_sbi.cpu_start) {
 71		pr_err("cpu start method not defined for CPU [%d]\n", cpuid);
 72		return -ENODEV;
 73	}
 74	return 0;
 75}
 76
 77#ifdef CONFIG_HOTPLUG_CPU
 78static int sbi_cpu_disable(unsigned int cpuid)
 79{
 80	if (!cpu_ops_sbi.cpu_stop)
 81		return -EOPNOTSUPP;
 82	return 0;
 83}
 84
 85static void sbi_cpu_stop(void)
 86{
 87	int ret;
 88
 89	ret = sbi_hsm_hart_stop();
 90	pr_crit("Unable to stop the cpu %u (%d)\n", smp_processor_id(), ret);
 91}
 92
 93static int sbi_cpu_is_stopped(unsigned int cpuid)
 94{
 95	int rc;
 96	int hartid = cpuid_to_hartid_map(cpuid);
 97
 98	rc = sbi_hsm_hart_get_status(hartid);
 99
100	if (rc == SBI_HSM_HART_STATUS_STOPPED)
101		return 0;
102	return rc;
103}
104#endif
105
106const struct cpu_operations cpu_ops_sbi = {
107	.name		= "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,
114#endif
115};