2019-06-03 07:44:50 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2012-03-05 11:49:30 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
|
|
*/
|
|
|
|
#ifndef __ASM_SMP_H
|
|
|
|
#define __ASM_SMP_H
|
|
|
|
|
2018-12-29 09:43:17 +08:00
|
|
|
#include <linux/const.h>
|
|
|
|
|
2016-02-23 10:31:42 +00:00
|
|
|
/* Values for secondary_data.status */
|
2018-12-10 14:21:13 +00:00
|
|
|
#define CPU_STUCK_REASON_SHIFT (8)
|
2018-12-29 09:43:17 +08:00
|
|
|
#define CPU_BOOT_STATUS_MASK ((UL(1) << CPU_STUCK_REASON_SHIFT) - 1)
|
2016-02-23 10:31:42 +00:00
|
|
|
|
2018-12-10 14:21:13 +00:00
|
|
|
#define CPU_MMU_OFF (-1)
|
|
|
|
#define CPU_BOOT_SUCCESS (0)
|
2016-02-23 10:31:42 +00:00
|
|
|
/* The cpu invoked ops->cpu_die, synchronise it with cpu_kill */
|
2018-12-10 14:21:13 +00:00
|
|
|
#define CPU_KILL_ME (1)
|
2016-02-23 10:31:42 +00:00
|
|
|
/* The cpu couldn't die gracefully and is looping in the kernel */
|
2018-12-10 14:21:13 +00:00
|
|
|
#define CPU_STUCK_IN_KERNEL (2)
|
2016-02-23 10:31:42 +00:00
|
|
|
/* Fatal system error detected by secondary CPU, crash the system */
|
2018-12-10 14:21:13 +00:00
|
|
|
#define CPU_PANIC_KERNEL (3)
|
|
|
|
|
2018-12-29 09:43:17 +08:00
|
|
|
#define CPU_STUCK_REASON_52_BIT_VA (UL(1) << CPU_STUCK_REASON_SHIFT)
|
|
|
|
#define CPU_STUCK_REASON_NO_GRAN (UL(2) << CPU_STUCK_REASON_SHIFT)
|
2016-02-23 10:31:42 +00:00
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
|
2012-03-05 11:49:30 +00:00
|
|
|
#include <linux/threads.h>
|
|
|
|
#include <linux/cpumask.h>
|
|
|
|
#include <linux/thread_info.h>
|
|
|
|
|
arm64: implement raw_smp_processor_id() using thread_info
Historically, arm64 implemented raw_smp_processor_id() as a read of
current_thread_info()->cpu. This changed when arm64 moved thread_info into
task struct, as at the time CONFIG_THREAD_INFO_IN_TASK made core code use
thread_struct::cpu for the cpu number, and due to header dependencies
prevented using this in raw_smp_processor_id(). As a workaround, we moved to
using a percpu variable in commit:
57c82954e77fa12c ("arm64: make cpu number a percpu variable")
Since then, thread_info::cpu was reintroduced, and core code was made to use
this in commits:
001430c1910df65a ("arm64: add CPU field to struct thread_info")
bcf9033e5449bdca ("sched: move CPU field back into thread_info if THREAD_INFO_IN_TASK=y")
Consequently it is possible to use current_thread_info()->cpu again.
This decreases the number of emitted instructions like in the following
example:
Dump of assembler code for function bpf_get_smp_processor_id:
0xffff8000802cd608 <+0>: nop
0xffff8000802cd60c <+4>: nop
0xffff8000802cd610 <+8>: adrp x0, 0xffff800082138000
0xffff8000802cd614 <+12>: mrs x1, tpidr_el1
0xffff8000802cd618 <+16>: add x0, x0, #0x8
0xffff8000802cd61c <+20>: ldrsw x0, [x0, x1]
0xffff8000802cd620 <+24>: ret
After this patch:
Dump of assembler code for function bpf_get_smp_processor_id:
0xffff8000802c9130 <+0>: nop
0xffff8000802c9134 <+4>: nop
0xffff8000802c9138 <+8>: mrs x0, sp_el0
0xffff8000802c913c <+12>: ldr w0, [x0, #24]
0xffff8000802c9140 <+16>: ret
A microbenchmark[1] was built to measure the performance improvement
provided by this change. It calls the following function given number of
times and finds the runtime overhead:
static noinline int get_cpu_id(void)
{
return smp_processor_id();
}
Run the benchmark like:
modprobe smp_processor_id nr_function_calls=1000000000
+--------------------------+------------------------+
| | Number of Calls | Time taken |
+--------+-----------------+------------------------+
| Before | 1000000000 | 1602888401ns |
+--------+-----------------+------------------------+
| After | 1000000000 | 1206212658ns |
+--------+-----------------+------------------------+
| Difference (decrease) | 396675743ns (24.74%) |
+---------------------------------------------------+
Remove the percpu variable cpu_number as it is used only in
set_smp_ipi_range() as a dummy variable to be passed to ipi_handler().
Use irq_stat in place of cpu_number here like arm32.
[1] https://github.com/puranjaymohan/linux/commit/77d3fdd
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/20240503171847.68267-2-puranjay@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2024-05-03 17:18:47 +00:00
|
|
|
#define raw_smp_processor_id() (current_thread_info()->cpu)
|
2012-03-05 11:49:30 +00:00
|
|
|
|
2019-06-03 16:18:29 -07:00
|
|
|
/*
|
|
|
|
* Logical CPU mapping.
|
|
|
|
*/
|
|
|
|
extern u64 __cpu_logical_map[NR_CPUS];
|
2020-12-02 18:41:03 +00:00
|
|
|
extern u64 cpu_logical_map(unsigned int cpu);
|
2020-07-27 23:29:38 +08:00
|
|
|
|
2020-12-02 18:41:03 +00:00
|
|
|
static inline void set_cpu_logical_map(unsigned int cpu, u64 hwid)
|
2020-07-27 23:29:38 +08:00
|
|
|
{
|
|
|
|
__cpu_logical_map[cpu] = hwid;
|
|
|
|
}
|
2019-06-03 16:18:29 -07:00
|
|
|
|
2012-03-05 11:49:30 +00:00
|
|
|
struct seq_file;
|
|
|
|
|
|
|
|
/*
|
2015-03-24 22:02:45 +08:00
|
|
|
* Discover the set of possible CPUs and determine their
|
|
|
|
* SMP operations.
|
2012-03-05 11:49:30 +00:00
|
|
|
*/
|
2015-05-13 14:12:47 +01:00
|
|
|
extern void smp_init_cpus(void);
|
2012-03-05 11:49:30 +00:00
|
|
|
|
2025-07-03 12:25:12 +02:00
|
|
|
enum ipi_msg_type {
|
|
|
|
IPI_RESCHEDULE,
|
|
|
|
IPI_CALL_FUNC,
|
|
|
|
IPI_CPU_STOP,
|
|
|
|
IPI_CPU_STOP_NMI,
|
|
|
|
IPI_TIMER,
|
|
|
|
IPI_IRQ_WORK,
|
|
|
|
NR_IPI,
|
|
|
|
/*
|
|
|
|
* Any enum >= NR_IPI and < MAX_IPI is special and not tracable
|
|
|
|
* with trace_ipi_*
|
|
|
|
*/
|
|
|
|
IPI_CPU_BACKTRACE = NR_IPI,
|
|
|
|
IPI_KGDB_ROUNDUP,
|
|
|
|
MAX_IPI
|
|
|
|
};
|
|
|
|
|
arm64: Allow IPIs to be handled as normal interrupts
In order to deal with IPIs as normal interrupts, let's add
a new way to register them with the architecture code.
set_smp_ipi_range() takes a range of interrupts, and allows
the arch code to request them as if the were normal interrupts.
A standard handler is then called by the core IRQ code to deal
with the IPI.
This means that we don't need to call irq_enter/irq_exit, and
that we don't need to deal with set_irq_regs either. So let's
move the dispatcher into its own function, and leave handle_IPI()
as a compatibility function.
On the sending side, let's make use of ipi_send_mask, which
already exists for this purpose.
One of the major difference is that we end up, in some cases
(such as when performing IRQ time accounting on the scheduler
IPI), end up with nested irq_enter()/irq_exit() pairs.
Other than the (relatively small) overhead, there should be
no consequences to it (these pairs are designed to nest
correctly, and the accounting shouldn't be off).
Reviewed-by: Valentin Schneider <valentin.schneider@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
2020-04-25 15:03:47 +01:00
|
|
|
/*
|
|
|
|
* Register IPI interrupts with the arch SMP code
|
|
|
|
*/
|
2025-07-03 12:25:08 +02:00
|
|
|
extern void set_smp_ipi_range_percpu(int ipi_base, int nr_ipi, int ncpus);
|
|
|
|
|
|
|
|
static inline void set_smp_ipi_range(int ipi_base, int n)
|
|
|
|
{
|
|
|
|
set_smp_ipi_range_percpu(ipi_base, n, 0);
|
|
|
|
}
|
arm64: Allow IPIs to be handled as normal interrupts
In order to deal with IPIs as normal interrupts, let's add
a new way to register them with the architecture code.
set_smp_ipi_range() takes a range of interrupts, and allows
the arch code to request them as if the were normal interrupts.
A standard handler is then called by the core IRQ code to deal
with the IPI.
This means that we don't need to call irq_enter/irq_exit, and
that we don't need to deal with set_irq_regs either. So let's
move the dispatcher into its own function, and leave handle_IPI()
as a compatibility function.
On the sending side, let's make use of ipi_send_mask, which
already exists for this purpose.
One of the major difference is that we end up, in some cases
(such as when performing IRQ time accounting on the scheduler
IPI), end up with nested irq_enter()/irq_exit() pairs.
Other than the (relatively small) overhead, there should be
no consequences to it (these pairs are designed to nest
correctly, and the accounting shouldn't be off).
Reviewed-by: Valentin Schneider <valentin.schneider@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
2020-04-25 15:03:47 +01:00
|
|
|
|
2012-03-05 11:49:30 +00:00
|
|
|
/*
|
|
|
|
* Called from the secondary holding pen, this is the secondary CPU entry point.
|
|
|
|
*/
|
|
|
|
asmlinkage void secondary_start_kernel(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initial data for bringing up a secondary CPU.
|
2016-02-23 10:31:42 +00:00
|
|
|
* @status - Result passed back from the secondary CPU to
|
|
|
|
* indicate failure.
|
2012-03-05 11:49:30 +00:00
|
|
|
*/
|
|
|
|
struct secondary_data {
|
arm64: split thread_info from task stack
This patch moves arm64's struct thread_info from the task stack into
task_struct. This protects thread_info from corruption in the case of
stack overflows, and makes its address harder to determine if stack
addresses are leaked, making a number of attacks more difficult. Precise
detection and handling of overflow is left for subsequent patches.
Largely, this involves changing code to store the task_struct in sp_el0,
and acquire the thread_info from the task struct. Core code now
implements current_thread_info(), and as noted in <linux/sched.h> this
relies on offsetof(task_struct, thread_info) == 0, enforced by core
code.
This change means that the 'tsk' register used in entry.S now points to
a task_struct, rather than a thread_info as it used to. To make this
clear, the TI_* field offsets are renamed to TSK_TI_*, with asm-offsets
appropriately updated to account for the structural change.
Userspace clobbers sp_el0, and we can no longer restore this from the
stack. Instead, the current task is cached in a per-cpu variable that we
can safely access from early assembly as interrupts are disabled (and we
are thus not preemptible).
Both secondary entry and idle are updated to stash the sp and task
pointer separately.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: James Morse <james.morse@arm.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-11-03 20:23:13 +00:00
|
|
|
struct task_struct *task;
|
2016-02-23 10:31:42 +00:00
|
|
|
long status;
|
2012-03-05 11:49:30 +00:00
|
|
|
};
|
2016-02-23 10:31:42 +00:00
|
|
|
|
2012-03-05 11:49:30 +00:00
|
|
|
extern struct secondary_data secondary_data;
|
2016-02-23 10:31:42 +00:00
|
|
|
extern long __early_cpu_boot_status;
|
arm64: factor out spin-table boot method
The arm64 kernel has an internal holding pen, which is necessary for
some systems where we can't bring CPUs online individually and must hold
multiple CPUs in a safe area until the kernel is able to handle them.
The current SMP infrastructure for arm64 is closely coupled to this
holding pen, and alternative boot methods must launch CPUs into the pen,
where they sit before they are launched into the kernel proper.
With PSCI (and possibly other future boot methods), we can bring CPUs
online individually, and need not perform the secondary_holding_pen
dance. Instead, this patch factors the holding pen management code out
to the spin-table boot method code, as it is the only boot method
requiring the pen.
A new entry point for secondaries, secondary_entry is added for other
boot methods to use, which bypasses the holding pen and its associated
overhead when bringing CPUs online. The smp.pen.text section is also
removed, as the pen can live in head.text without problem.
The cpu_operations structure is extended with two new functions,
cpu_boot and cpu_postboot, for bringing a cpu into the kernel and
performing any post-boot cleanup required by a bootmethod (e.g.
resetting the secondary_holding_pen_release to INVALID_HWID).
Documentation is added for cpu_operations.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2013-10-24 20:30:16 +01:00
|
|
|
extern void secondary_entry(void);
|
2012-03-05 11:49:30 +00:00
|
|
|
|
|
|
|
extern void arch_send_call_function_single_ipi(int cpu);
|
|
|
|
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
|
|
|
|
|
2016-01-26 11:10:38 +00:00
|
|
|
#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
|
2023-09-06 09:02:58 -07:00
|
|
|
extern void arch_send_wakeup_ipi(unsigned int cpu);
|
2016-01-26 11:10:38 +00:00
|
|
|
#else
|
2023-09-06 09:02:58 -07:00
|
|
|
static inline void arch_send_wakeup_ipi(unsigned int cpu)
|
2016-01-26 11:10:38 +00:00
|
|
|
{
|
|
|
|
BUILD_BUG();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-10-24 20:30:18 +01:00
|
|
|
extern int __cpu_disable(void);
|
|
|
|
|
2023-05-12 23:07:33 +02:00
|
|
|
static inline void __cpu_die(unsigned int cpu) { }
|
2023-02-16 10:42:01 -08:00
|
|
|
extern void __noreturn cpu_die(void);
|
2023-04-12 16:49:34 -07:00
|
|
|
extern void __noreturn cpu_die_early(void);
|
2013-10-24 20:30:18 +01:00
|
|
|
|
2023-04-12 16:49:34 -07:00
|
|
|
static inline void __noreturn cpu_park_loop(void)
|
2016-02-23 10:31:39 +00:00
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
wfe();
|
|
|
|
wfi();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-23 10:31:42 +00:00
|
|
|
static inline void update_cpu_boot_status(int val)
|
|
|
|
{
|
|
|
|
WRITE_ONCE(secondary_data.status, val);
|
|
|
|
/* Ensure the visibility of the status update */
|
|
|
|
dsb(ishst);
|
|
|
|
}
|
|
|
|
|
2016-04-12 15:46:00 +01:00
|
|
|
/*
|
|
|
|
* The calling secondary CPU has detected serious configuration mismatch,
|
|
|
|
* which calls for a kernel panic. Update the boot status and park the calling
|
|
|
|
* CPU.
|
|
|
|
*/
|
2023-04-12 16:49:34 -07:00
|
|
|
static inline void __noreturn cpu_panic_kernel(void)
|
2016-04-12 15:46:00 +01:00
|
|
|
{
|
|
|
|
update_cpu_boot_status(CPU_PANIC_KERNEL);
|
|
|
|
cpu_park_loop();
|
|
|
|
}
|
|
|
|
|
2016-06-22 10:06:12 +01:00
|
|
|
/*
|
|
|
|
* If a secondary CPU enters the kernel but fails to come online,
|
|
|
|
* (e.g. due to mismatched features), and cannot exit the kernel,
|
|
|
|
* we increment cpus_stuck_in_kernel and leave the CPU in a
|
|
|
|
* quiesecent loop within the kernel text. The memory containing
|
|
|
|
* this loop must not be re-used for anything else as the 'stuck'
|
|
|
|
* core is executing it.
|
|
|
|
*
|
|
|
|
* This function is used to inhibit features like kexec and hibernate.
|
|
|
|
*/
|
|
|
|
bool cpus_are_stuck_in_kernel(void);
|
|
|
|
|
2017-08-17 11:24:27 +09:00
|
|
|
extern void crash_smp_send_stop(void);
|
2017-04-03 11:24:36 +09:00
|
|
|
extern bool smp_crash_stop_failed(void);
|
|
|
|
|
2016-02-23 10:31:42 +00:00
|
|
|
#endif /* ifndef __ASSEMBLY__ */
|
|
|
|
|
2012-03-05 11:49:30 +00:00
|
|
|
#endif /* ifndef __ASM_SMP_H */
|