Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  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 <linux/sched/task_stack.h>
 11#include <asm/cpu_ops.h>
 12#include <asm/cpu_ops_sbi.h>
 13#include <asm/sbi.h>
 14#include <asm/smp.h>
 15
 16extern char secondary_start_sbi[];
 17const struct cpu_operations cpu_ops_sbi;
 18
 19/*
 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
 22 * to handle that.
 23 */
 24static DEFINE_PER_CPU(struct sbi_hart_boot_data, boot_data);
 25
 26static int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
 27			      unsigned long priv)
 28{
 29	struct sbiret ret;
 30
 31	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START,
 32			hartid, saddr, priv, 0, 0, 0);
 33	if (ret.error)
 34		return sbi_err_map_linux_errno(ret.error);
 35	else
 36		return 0;
 37}
 38
 39#ifdef CONFIG_HOTPLUG_CPU
 40static int sbi_hsm_hart_stop(void)
 41{
 42	struct sbiret ret;
 43
 44	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
 45
 46	if (ret.error)
 47		return sbi_err_map_linux_errno(ret.error);
 48	else
 49		return 0;
 50}
 51
 52static int sbi_hsm_hart_get_status(unsigned long hartid)
 53{
 54	struct sbiret ret;
 55
 56	ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS,
 57			hartid, 0, 0, 0, 0, 0);
 58	if (ret.error)
 59		return sbi_err_map_linux_errno(ret.error);
 60	else
 61		return ret.value;
 62}
 63#endif
 64
 65static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
 66{
 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);
 71
 72	/* Make sure tidle is updated */
 73	smp_mb();
 74	bdata->task_ptr = tidle;
 75	bdata->stack_ptr = task_stack_page(tidle) + THREAD_SIZE;
 76	/* Make sure boot data is updated */
 77	smp_mb();
 78	hsm_data = __pa(bdata);
 79	return sbi_hsm_hart_start(hartid, boot_addr, hsm_data);
 80}
 81
 82#ifdef CONFIG_HOTPLUG_CPU
 83static void sbi_cpu_stop(void)
 84{
 85	int ret;
 86
 87	ret = sbi_hsm_hart_stop();
 88	pr_crit("Unable to stop the cpu %u (%d)\n", smp_processor_id(), ret);
 89}
 90
 91static int sbi_cpu_is_stopped(unsigned int cpuid)
 92{
 93	int rc;
 94	unsigned long hartid = cpuid_to_hartid_map(cpuid);
 95
 96	rc = sbi_hsm_hart_get_status(hartid);
 97
 98	if (rc == SBI_HSM_STATE_STOPPED)
 99		return 0;
100	return rc;
101}
102#endif
103
104const 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,
109#endif
110};