[PATCH 30/38] arm64: smp: Abstract SGI and LPI operations
Jinjie Ruan
ruanjinjie at huawei.com
Wed Sep 16 02:01:37 PDT 2026
在 2026/9/14 18:20, Vladimir Murzin 写道:
> SGI and LPI backed IPIs require different setup, enable, disable and
> send operations. These differences are currently handled by repeatedly
> checking percpu_ipi_descs. As the implementation specific logic grows,
> these checks make the common IPI code increasingly difficult to
> follow.
>
> Introduce an operations structure for each implementation to
> encapsulate the specific of SGI and LPI handling, leaving the common
> IPI paths generic.
>
> Signed-off-by: Vladimir Murzin <vladimir.murzin at arm.com>
> Reviewed-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
> arch/arm64/kernel/smp.c | 135 ++++++++++++++++++++++++++--------------
> 1 file changed, 88 insertions(+), 47 deletions(-)
>
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 3d7060aedd66..46cdcc114997 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -77,11 +77,18 @@ static DEFINE_PER_CPU_READ_MOSTLY(struct ipi_descs, pcpu_ipi_desc);
>
> #define get_ipi_desc(__cpu, __ipi) (per_cpu_ptr(&pcpu_ipi_desc, __cpu)->descs[__ipi])
>
> -static bool percpu_ipi_descs __ro_after_init;
> +struct ipi_irq_ops {
> + void (*setup)(int ipi, int ncpus);
> + void (*disable)(int cpu, int ipi);
> + void (*enable)(int cpu, int ipi);
> + void (*send)(const cpumask_t *mask, unsigned int nr);
> +};
> +
> +static const struct ipi_irq_ops *ipi_ops __ro_after_init;
>
> static bool crash_stop;
>
> -static void ipi_setup(int cpu);
> +static void ipi_enable(int cpu);
>
> #ifdef CONFIG_HOTPLUG_CPU
> static void ipi_teardown(int cpu);
> @@ -242,7 +249,7 @@ asmlinkage notrace void secondary_start_kernel(void)
> */
> notify_cpu_starting(cpu);
>
> - ipi_setup(cpu);
> + ipi_enable(cpu);
>
> numa_add_cpu(cpu);
>
> @@ -937,13 +944,7 @@ void __noreturn panic_smp_self_stop(void)
>
> static void arm64_send_ipi(const cpumask_t *mask, unsigned int nr)
> {
> - unsigned int cpu;
> -
> - if (!percpu_ipi_descs)
> - __ipi_send_mask(get_ipi_desc(0, nr), mask);
> - else
> - for_each_cpu(cpu, mask)
> - __ipi_send_single(get_ipi_desc(cpu, nr), cpu);
> + ipi_ops->send(mask, nr);
> }
>
> static void arm64_backtrace_ipi(cpumask_t *mask)
> @@ -1074,54 +1075,37 @@ static bool ipi_should_be_nmi(enum ipi_msg_type ipi)
> }
> }
>
> -static void ipi_setup(int cpu)
> +static void ipi_enable(int cpu)
> {
> - int i;
> + int ipi;
>
> if (WARN_ON_ONCE(!ipi_irq_base))
> return;
>
> - for (i = 0; i < nr_ipi; i++) {
> - if (!percpu_ipi_descs) {
> - if (ipi_should_be_nmi(i)) {
> - prepare_percpu_nmi(ipi_irq_base + i);
> - enable_percpu_nmi(ipi_irq_base + i, 0);
> - } else {
> - enable_percpu_irq(ipi_irq_base + i, 0);
> - }
> - } else {
> - enable_irq(irq_desc_get_irq(get_ipi_desc(cpu, i)));
> - }
> - }
> + for (ipi = 0; ipi < nr_ipi; ipi++)
> + ipi_ops->enable(cpu, ipi);
> }
>
> #ifdef CONFIG_HOTPLUG_CPU
> static void ipi_teardown(int cpu)
> {
> - int i;
> + int ipi;
>
> if (WARN_ON_ONCE(!ipi_irq_base))
> return;
>
> - for (i = 0; i < nr_ipi; i++) {
> - if (!percpu_ipi_descs) {
> - if (ipi_should_be_nmi(i)) {
> - disable_percpu_nmi(ipi_irq_base + i);
> - teardown_percpu_nmi(ipi_irq_base + i);
> - } else {
> - disable_percpu_irq(ipi_irq_base + i);
> - }
> - } else {
> - disable_irq_nosync(irq_desc_get_irq(get_ipi_desc(cpu, i)));
> - }
> - }
> + for (ipi = 0; ipi < nr_ipi; ipi++)
> + ipi_ops->disable(cpu, ipi);
> }
> #endif
>
> -static void ipi_setup_sgi(int ipi)
> +static void ipi_sgi_setup(int ipi, int ncpus)
> {
> int err, irq, cpu;
>
> + if (WARN_ON_ONCE(ncpus))
> + return;
> +
> irq = ipi_irq_base + ipi;
>
> if (ipi_should_be_nmi(ipi)) {
> @@ -1138,7 +1122,53 @@ static void ipi_setup_sgi(int ipi)
> irq_set_status_flags(irq, IRQ_HIDDEN);
> }
>
> -static void ipi_setup_lpi(int ipi, int ncpus)
> +static void ipi_sgi_enable(int cpu, int ipi)
> +{
> + int irq = ipi_irq_base + ipi;
> +
> + if (ipi_should_be_nmi(ipi)) {
> + prepare_percpu_nmi(irq);
> + enable_percpu_nmi(irq, 0);
> + } else {
> + enable_percpu_irq(irq, 0);
> + }
> +}
> +
> +static void ipi_sgi_disable(int cpu, int ipi)
> +{
> + int irq = ipi_irq_base + ipi;
> +
> + if (ipi_should_be_nmi(ipi)) {
> + disable_percpu_nmi(irq);
> + teardown_percpu_nmi(irq);
> + } else {
> + disable_percpu_irq(irq);
> + }
> +}
> +
> +static void ipi_sgi_send(const cpumask_t *mask, unsigned int nr)
> +{
> + __ipi_send_mask(get_ipi_desc(0, nr), mask);
> +}
> +
> +static const struct ipi_irq_ops ipi_sgi_ops = {
> + .setup = ipi_sgi_setup,
> + .disable = ipi_sgi_disable,
> + .enable = ipi_sgi_enable,
> + .send = ipi_sgi_send,
> +};
> +
> +static void ipi_lpi_enable(int cpu, int ipi)
> +{
> + enable_irq(irq_desc_get_irq(get_ipi_desc(cpu, ipi)));
> +}
> +
> +static void ipi_lpi_disable(int cpu, int ipi)
> +{
> + disable_irq_nosync(irq_desc_get_irq(get_ipi_desc(cpu, ipi)));
> +}
> +
> +static void ipi_lpi_setup(int ipi, int ncpus)
> {
> for (int cpu = 0; cpu < ncpus; cpu++) {
> int err, irq;
> @@ -1158,6 +1188,20 @@ static void ipi_setup_lpi(int ipi, int ncpus)
> }
> }
>
> +static void ipi_lpi_send(const cpumask_t *mask, unsigned int nr) {
Sashiko pointed out a typo in the formatting.
static void ipi_lpi_send(const cpumask_t *mask, unsigned int nr)
{
> + int cpu;
> +
> + for_each_cpu(cpu, mask)
> + __ipi_send_single(get_ipi_desc(cpu, nr), cpu);
> +}
> +
> +static const struct ipi_irq_ops ipi_lpi_ops = {
> + .setup = ipi_lpi_setup,
> + .disable = ipi_lpi_disable,
> + .enable = ipi_lpi_enable,
> + .send = ipi_lpi_send,
> +};
> +
> void __init set_smp_ipi_range_percpu(int ipi_base, int n, int ncpus)
> {
> int i;
> @@ -1165,18 +1209,15 @@ void __init set_smp_ipi_range_percpu(int ipi_base, int n, int ncpus)
> WARN_ON(n < MAX_IPI);
> nr_ipi = min(n, MAX_IPI);
>
> - percpu_ipi_descs = !!ncpus;
> ipi_irq_base = ipi_base;
>
> - for (i = 0; i < nr_ipi; i++) {
> - if (!percpu_ipi_descs)
> - ipi_setup_sgi(i);
> - else
> - ipi_setup_lpi(i, ncpus);
> - }
> + ipi_ops = ncpus ? &ipi_lpi_ops : &ipi_sgi_ops;
> +
> + for (i = 0; i < nr_ipi; i++)
> + ipi_ops->setup(i, ncpus);
>
> /* Setup the boot CPU immediately */
> - ipi_setup(smp_processor_id());
> + ipi_enable(smp_processor_id());
> }
>
> void arch_smp_send_reschedule(int cpu)
More information about the linux-arm-kernel
mailing list