Contributors: 14
| Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
| Tiwei Bie |
701 |
82.67% |
1 |
3.23% |
| Jeff Dike |
77 |
9.08% |
11 |
35.48% |
| Al Viro |
25 |
2.95% |
6 |
19.35% |
| Benjamin Berg |
18 |
2.12% |
1 |
3.23% |
| Paolo 'Blaisorblade' Giarrusso |
7 |
0.83% |
2 |
6.45% |
| Ingo Molnar |
6 |
0.71% |
2 |
6.45% |
| Thomas Gleixner |
3 |
0.35% |
1 |
3.23% |
| Andy Shevchenko |
2 |
0.24% |
1 |
3.23% |
| Ingo van Lil |
2 |
0.24% |
1 |
3.23% |
| Alexey Dobriyan |
2 |
0.24% |
1 |
3.23% |
| Gennady Sharapov |
2 |
0.24% |
1 |
3.23% |
| Chris Wedgwood |
1 |
0.12% |
1 |
3.23% |
| Eric W. Biedermann |
1 |
0.12% |
1 |
3.23% |
| Alex Dewar |
1 |
0.12% |
1 |
3.23% |
| Total |
848 |
|
31 |
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2025 Ant Group
* Author: Tiwei Bie <tiwei.btw@antgroup.com>
*
* Based on the previous implementation in TT mode
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
#include <linux/sched.h>
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/module.h>
#include <linux/processor.h>
#include <linux/threads.h>
#include <linux/cpu.h>
#include <linux/hardirq.h>
#include <linux/smp.h>
#include <linux/smp-internal.h>
#include <init.h>
#include <kern.h>
#include <os.h>
#include <smp.h>
enum {
UML_IPI_RES = 0,
UML_IPI_CALL_SINGLE,
UML_IPI_CALL,
UML_IPI_STOP,
};
void arch_smp_send_reschedule(int cpu)
{
os_send_ipi(cpu, UML_IPI_RES);
}
void arch_send_call_function_single_ipi(int cpu)
{
os_send_ipi(cpu, UML_IPI_CALL_SINGLE);
}
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
int cpu;
for_each_cpu(cpu, mask)
os_send_ipi(cpu, UML_IPI_CALL);
}
void smp_send_stop(void)
{
int cpu, me = smp_processor_id();
for_each_online_cpu(cpu) {
if (cpu == me)
continue;
os_send_ipi(cpu, UML_IPI_STOP);
}
}
static void ipi_handler(int vector, struct uml_pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
int cpu = raw_smp_processor_id();
irq_enter();
if (current->mm)
os_alarm_process(current->mm->context.id.pid);
switch (vector) {
case UML_IPI_RES:
inc_irq_stat(irq_resched_count);
scheduler_ipi();
break;
case UML_IPI_CALL_SINGLE:
inc_irq_stat(irq_call_count);
generic_smp_call_function_single_interrupt();
break;
case UML_IPI_CALL:
inc_irq_stat(irq_call_count);
generic_smp_call_function_interrupt();
break;
case UML_IPI_STOP:
set_cpu_online(cpu, false);
while (1)
pause();
break;
default:
pr_err("CPU#%d received unknown IPI (vector=%d)!\n", cpu, vector);
break;
}
irq_exit();
set_irq_regs(old_regs);
}
void uml_ipi_handler(int vector)
{
struct uml_pt_regs r = { .is_user = 0 };
preempt_disable();
ipi_handler(vector, &r);
preempt_enable();
}
/* AP states used only during CPU startup */
enum {
UML_CPU_PAUSED = 0,
UML_CPU_RUNNING,
};
static int cpu_states[NR_CPUS];
static int start_secondary(void *unused)
{
int err, cpu = raw_smp_processor_id();
notify_cpu_starting(cpu);
set_cpu_online(cpu, true);
err = um_setup_timer();
if (err)
panic("CPU#%d failed to setup timer, err = %d", cpu, err);
local_irq_enable();
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
return 0;
}
void uml_start_secondary(void *opaque)
{
int cpu = raw_smp_processor_id();
struct mm_struct *mm = &init_mm;
struct task_struct *idle;
stack_protections((unsigned long) &cpu_irqstacks[cpu]);
set_sigstack(&cpu_irqstacks[cpu], THREAD_SIZE);
set_cpu_present(cpu, true);
os_futex_wait(&cpu_states[cpu], UML_CPU_PAUSED);
smp_rmb(); /* paired with smp_wmb() in __cpu_up() */
idle = cpu_tasks[cpu];
idle->thread_info.cpu = cpu;
mmgrab(mm);
idle->active_mm = mm;
idle->thread.request.thread.proc = start_secondary;
idle->thread.request.thread.arg = NULL;
new_thread(task_stack_page(idle), &idle->thread.switch_buf,
new_thread_handler);
os_start_secondary(opaque, &idle->thread.switch_buf);
}
void __init smp_prepare_cpus(unsigned int max_cpus)
{
int err, cpu, me = smp_processor_id();
unsigned long deadline;
os_init_smp();
for_each_possible_cpu(cpu) {
if (cpu == me)
continue;
pr_debug("Booting processor %d...\n", cpu);
err = os_start_cpu_thread(cpu);
if (err) {
pr_crit("CPU#%d failed to start cpu thread, err = %d",
cpu, err);
continue;
}
deadline = jiffies + msecs_to_jiffies(1000);
spin_until_cond(cpu_present(cpu) ||
time_is_before_jiffies(deadline));
if (!cpu_present(cpu))
pr_crit("CPU#%d failed to boot\n", cpu);
}
}
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
cpu_tasks[cpu] = tidle;
smp_wmb(); /* paired with smp_rmb() in uml_start_secondary() */
cpu_states[cpu] = UML_CPU_RUNNING;
os_futex_wake(&cpu_states[cpu]);
spin_until_cond(cpu_online(cpu));
return 0;
}
void __init smp_cpus_done(unsigned int max_cpus)
{
}
/* Set in uml_ncpus_setup */
int uml_ncpus = 1;
void __init prefill_possible_map(void)
{
int cpu;
for (cpu = 0; cpu < uml_ncpus; cpu++)
set_cpu_possible(cpu, true);
for (; cpu < NR_CPUS; cpu++)
set_cpu_possible(cpu, false);
}
static int __init uml_ncpus_setup(char *line, int *add)
{
*add = 0;
if (kstrtoint(line, 10, ¨_ncpus)) {
os_warn("%s: Couldn't parse '%s'\n", __func__, line);
return -1;
}
uml_ncpus = clamp(uml_ncpus, 1, NR_CPUS);
return 0;
}
__uml_setup("ncpus=", uml_ncpus_setup,
"ncpus=<# of desired CPUs>\n"
" This tells UML how many virtual processors to start. The maximum\n"
" number of supported virtual processors can be obtained by querying\n"
" the CONFIG_NR_CPUS option using --showconfig.\n\n"
);
EXPORT_SYMBOL(uml_curr_cpu);