Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * SMP initialisation and IPI support
  4 * Based on arch/arm64/kernel/smp.c
  5 *
  6 * Copyright (C) 2012 ARM Ltd.
  7 * Copyright (C) 2015 Regents of the University of California
  8 * Copyright (C) 2017 SiFive
  9 */
 10
 11#include <linux/arch_topology.h>
 12#include <linux/module.h>
 13#include <linux/init.h>
 14#include <linux/kernel.h>
 15#include <linux/mm.h>
 16#include <linux/sched.h>
 17#include <linux/kernel_stat.h>
 18#include <linux/notifier.h>
 19#include <linux/cpu.h>
 20#include <linux/percpu.h>
 21#include <linux/delay.h>
 22#include <linux/err.h>
 23#include <linux/irq.h>
 24#include <linux/of.h>
 25#include <linux/sched/task_stack.h>
 26#include <linux/sched/mm.h>
 27#include <asm/cpu_ops.h>
 28#include <asm/irq.h>
 29#include <asm/mmu_context.h>
 30#include <asm/numa.h>
 31#include <asm/tlbflush.h>
 32#include <asm/sections.h>
 33#include <asm/sbi.h>
 34#include <asm/smp.h>
 35
 36#include "head.h"
 37
 
 
 38static DECLARE_COMPLETION(cpu_running);
 39
 40void __init smp_prepare_boot_cpu(void)
 41{
 
 42}
 43
 44void __init smp_prepare_cpus(unsigned int max_cpus)
 45{
 46	int cpuid;
 47	int ret;
 48	unsigned int curr_cpuid;
 49
 50	init_cpu_topology();
 51
 52	curr_cpuid = smp_processor_id();
 53	store_cpu_topology(curr_cpuid);
 54	numa_store_cpu_info(curr_cpuid);
 55	numa_add_cpu(curr_cpuid);
 56
 57	/* This covers non-smp usecase mandated by "nosmp" option */
 58	if (max_cpus == 0)
 59		return;
 60
 61	for_each_possible_cpu(cpuid) {
 62		if (cpuid == curr_cpuid)
 63			continue;
 64		if (cpu_ops[cpuid]->cpu_prepare) {
 65			ret = cpu_ops[cpuid]->cpu_prepare(cpuid);
 66			if (ret)
 67				continue;
 68		}
 69		set_cpu_present(cpuid, true);
 70		numa_store_cpu_info(cpuid);
 71	}
 72}
 73
 74void __init setup_smp(void)
 75{
 76	struct device_node *dn;
 77	unsigned long hart;
 78	bool found_boot_cpu = false;
 79	int cpuid = 1;
 80	int rc;
 81
 82	cpu_set_ops(0);
 83
 84	for_each_of_cpu_node(dn) {
 85		rc = riscv_of_processor_hartid(dn, &hart);
 86		if (rc < 0)
 87			continue;
 88
 89		if (hart == cpuid_to_hartid_map(0)) {
 90			BUG_ON(found_boot_cpu);
 91			found_boot_cpu = 1;
 92			early_map_cpu_to_node(0, of_node_to_nid(dn));
 93			continue;
 94		}
 95		if (cpuid >= NR_CPUS) {
 96			pr_warn("Invalid cpuid [%d] for hartid [%lu]\n",
 97				cpuid, hart);
 98			continue;
 99		}
100
101		cpuid_to_hartid_map(cpuid) = hart;
102		early_map_cpu_to_node(cpuid, of_node_to_nid(dn));
103		cpuid++;
104	}
105
106	BUG_ON(!found_boot_cpu);
107
108	if (cpuid > nr_cpu_ids)
109		pr_warn("Total number of cpus [%d] is greater than nr_cpus option value [%d]\n",
110			cpuid, nr_cpu_ids);
111
112	for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) {
113		if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) {
114			cpu_set_ops(cpuid);
115			set_cpu_possible(cpuid, true);
116		}
117	}
118}
119
120static int start_secondary_cpu(int cpu, struct task_struct *tidle)
121{
122	if (cpu_ops[cpu]->cpu_start)
123		return cpu_ops[cpu]->cpu_start(cpu, tidle);
124
125	return -EOPNOTSUPP;
126}
127
128int __cpu_up(unsigned int cpu, struct task_struct *tidle)
129{
130	int ret = 0;
 
131	tidle->thread_info.cpu = cpu;
132
133	ret = start_secondary_cpu(cpu, tidle);
134	if (!ret) {
135		wait_for_completion_timeout(&cpu_running,
 
 
 
 
 
 
 
 
 
 
 
136					    msecs_to_jiffies(1000));
137
138		if (!cpu_online(cpu)) {
139			pr_crit("CPU%u: failed to come online\n", cpu);
140			ret = -EIO;
141		}
142	} else {
143		pr_crit("CPU%u: failed to start\n", cpu);
144	}
145
146	return ret;
147}
148
149void __init smp_cpus_done(unsigned int max_cpus)
150{
151}
152
153/*
154 * C entry point for a secondary processor.
155 */
156asmlinkage __visible void smp_callin(void)
157{
158	struct mm_struct *mm = &init_mm;
159	unsigned int curr_cpuid = smp_processor_id();
160
161	riscv_clear_ipi();
162
163	/* All kernel threads share the same mm context.  */
164	mmgrab(mm);
165	current->active_mm = mm;
166
167	store_cpu_topology(curr_cpuid);
168	notify_cpu_starting(curr_cpuid);
169	numa_add_cpu(curr_cpuid);
170	set_cpu_online(curr_cpuid, 1);
171
172	/*
173	 * Remote TLB flushes are ignored while the CPU is offline, so emit
174	 * a local TLB flush right now just in case.
175	 */
176	local_flush_tlb_all();
177	complete(&cpu_running);
178	/*
179	 * Disable preemption before enabling interrupts, so we don't try to
180	 * schedule a CPU that hasn't actually started yet.
181	 */
 
182	local_irq_enable();
183	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
184}
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * SMP initialisation and IPI support
  4 * Based on arch/arm64/kernel/smp.c
  5 *
  6 * Copyright (C) 2012 ARM Ltd.
  7 * Copyright (C) 2015 Regents of the University of California
  8 * Copyright (C) 2017 SiFive
  9 */
 10
 11#include <linux/arch_topology.h>
 12#include <linux/module.h>
 13#include <linux/init.h>
 14#include <linux/kernel.h>
 15#include <linux/mm.h>
 16#include <linux/sched.h>
 17#include <linux/kernel_stat.h>
 18#include <linux/notifier.h>
 19#include <linux/cpu.h>
 20#include <linux/percpu.h>
 21#include <linux/delay.h>
 22#include <linux/err.h>
 23#include <linux/irq.h>
 24#include <linux/of.h>
 25#include <linux/sched/task_stack.h>
 26#include <linux/sched/mm.h>
 
 27#include <asm/irq.h>
 28#include <asm/mmu_context.h>
 
 29#include <asm/tlbflush.h>
 30#include <asm/sections.h>
 31#include <asm/sbi.h>
 32#include <asm/smp.h>
 33
 34#include "head.h"
 35
 36void *__cpu_up_stack_pointer[NR_CPUS];
 37void *__cpu_up_task_pointer[NR_CPUS];
 38static DECLARE_COMPLETION(cpu_running);
 39
 40void __init smp_prepare_boot_cpu(void)
 41{
 42	init_cpu_topology();
 43}
 44
 45void __init smp_prepare_cpus(unsigned int max_cpus)
 46{
 47	int cpuid;
 
 
 
 
 
 
 
 
 
 48
 49	/* This covers non-smp usecase mandated by "nosmp" option */
 50	if (max_cpus == 0)
 51		return;
 52
 53	for_each_possible_cpu(cpuid) {
 54		if (cpuid == smp_processor_id())
 55			continue;
 
 
 
 
 
 56		set_cpu_present(cpuid, true);
 
 57	}
 58}
 59
 60void __init setup_smp(void)
 61{
 62	struct device_node *dn;
 63	int hart;
 64	bool found_boot_cpu = false;
 65	int cpuid = 1;
 
 
 
 66
 67	for_each_of_cpu_node(dn) {
 68		hart = riscv_of_processor_hartid(dn);
 69		if (hart < 0)
 70			continue;
 71
 72		if (hart == cpuid_to_hartid_map(0)) {
 73			BUG_ON(found_boot_cpu);
 74			found_boot_cpu = 1;
 
 75			continue;
 76		}
 77		if (cpuid >= NR_CPUS) {
 78			pr_warn("Invalid cpuid [%d] for hartid [%d]\n",
 79				cpuid, hart);
 80			break;
 81		}
 82
 83		cpuid_to_hartid_map(cpuid) = hart;
 
 84		cpuid++;
 85	}
 86
 87	BUG_ON(!found_boot_cpu);
 88
 89	if (cpuid > nr_cpu_ids)
 90		pr_warn("Total number of cpus [%d] is greater than nr_cpus option value [%d]\n",
 91			cpuid, nr_cpu_ids);
 92
 93	for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) {
 94		if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID)
 
 95			set_cpu_possible(cpuid, true);
 
 96	}
 97}
 98
 
 
 
 
 
 
 
 
 99int __cpu_up(unsigned int cpu, struct task_struct *tidle)
100{
101	int ret = 0;
102	int hartid = cpuid_to_hartid_map(cpu);
103	tidle->thread_info.cpu = cpu;
104
105	/*
106	 * On RISC-V systems, all harts boot on their own accord.  Our _start
107	 * selects the first hart to boot the kernel and causes the remainder
108	 * of the harts to spin in a loop waiting for their stack pointer to be
109	 * setup by that main hart.  Writing __cpu_up_stack_pointer signals to
110	 * the spinning harts that they can continue the boot process.
111	 */
112	smp_mb();
113	WRITE_ONCE(__cpu_up_stack_pointer[hartid],
114		  task_stack_page(tidle) + THREAD_SIZE);
115	WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle);
116
117	lockdep_assert_held(&cpu_running);
118	wait_for_completion_timeout(&cpu_running,
119					    msecs_to_jiffies(1000));
120
121	if (!cpu_online(cpu)) {
122		pr_crit("CPU%u: failed to come online\n", cpu);
123		ret = -EIO;
 
 
 
124	}
125
126	return ret;
127}
128
129void __init smp_cpus_done(unsigned int max_cpus)
130{
131}
132
133/*
134 * C entry point for a secondary processor.
135 */
136asmlinkage __visible void __init smp_callin(void)
137{
138	struct mm_struct *mm = &init_mm;
 
 
 
139
140	/* All kernel threads share the same mm context.  */
141	mmgrab(mm);
142	current->active_mm = mm;
143
144	trap_init();
145	notify_cpu_starting(smp_processor_id());
146	update_siblings_masks(smp_processor_id());
147	set_cpu_online(smp_processor_id(), 1);
 
148	/*
149	 * Remote TLB flushes are ignored while the CPU is offline, so emit
150	 * a local TLB flush right now just in case.
151	 */
152	local_flush_tlb_all();
153	complete(&cpu_running);
154	/*
155	 * Disable preemption before enabling interrupts, so we don't try to
156	 * schedule a CPU that hasn't actually started yet.
157	 */
158	preempt_disable();
159	local_irq_enable();
160	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
161}