[RFC PATCH v2 38/45] arm64: smp: Abstract SGI and LPI operations

Jinjie Ruan ruanjinjie at huawei.com
Tue Aug 11 06:22:31 PDT 2026



在 2026/7/28 0:34, 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.

Reviewed-by: Jinjie Ruan <ruanjinjie at huawei.com>

> 
> Signed-off-by: Vladimir Murzin <vladimir.murzin at arm.com>
> ---
>  arch/arm64/kernel/smp.c | 163 +++++++++++++++++++++++++---------------
>  1 file changed, 101 insertions(+), 62 deletions(-)
> 
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 6e5b673613ca..3dd4bc02caed 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -75,11 +75,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);
> @@ -240,7 +247,7 @@ asmlinkage notrace void secondary_start_kernel(void)
>  	 */
>  	notify_cpu_starting(cpu);
>  
> -	ipi_setup(cpu);
> +	ipi_enable(cpu);
>  
>  	numa_add_cpu(cpu);
>  
> @@ -916,13 +923,7 @@ static void __noreturn ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs
>  
>  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)
> @@ -1048,53 +1049,13 @@ static bool ipi_should_be_nmi(enum ipi_msg_type ipi)
>  	}
>  }
>  
> -static void ipi_setup(int cpu)
> -{
> -	int i;
> -
> -	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)));
> -		}
> -	}
> -}
> -
> -#ifdef CONFIG_HOTPLUG_CPU
> -static void ipi_teardown(int cpu)
> +static void ipi_sgi_setup(int ipi, int ncpus)
>  {
> -	int i;
> +	int err, irq, cpu;
>  
> -	if (WARN_ON_ONCE(!ipi_irq_base))
> +	if (WARN_ON_ONCE(ncpus))
>  		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(irq_desc_get_irq(get_ipi_desc(cpu, i)));
> -		}
> -	}
> -}
> -#endif
> -
> -static void ipi_setup_sgi(int ipi)
> -{
> -	int err, irq, cpu;
>  
>  	irq = ipi_irq_base + ipi;
>  
> @@ -1112,7 +1073,50 @@ 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)
> +{
> +	if (ipi_should_be_nmi(ipi)) {
> +		prepare_percpu_nmi(ipi_irq_base + ipi);
> +		enable_percpu_nmi(ipi_irq_base + ipi, 0);
> +	} else {
> +		enable_percpu_irq(ipi_irq_base + ipi, 0);
> +	}
> +}
> +
> +static void ipi_sgi_disable(int cpu, int ipi)
> +{
> +	if (ipi_should_be_nmi(ipi)) {
> +		disable_percpu_nmi(ipi_irq_base + ipi);
> +		teardown_percpu_nmi(ipi_irq_base + ipi);
> +	} else {
> +		disable_percpu_irq(ipi_irq_base + ipi);
> +	}
> +}
> +
> +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 = {
> +	.disable = ipi_sgi_disable,
> +	.enable = ipi_sgi_enable,
> +	.setup = ipi_sgi_setup,
> +	.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(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;
> @@ -1132,6 +1136,44 @@ static void ipi_setup_lpi(int ipi, int ncpus)
>  	}
>  }
>  
> +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 = {
> +	.disable = ipi_lpi_disable,
> +	.enable = ipi_lpi_enable,
> +	.setup = ipi_lpi_setup,
> +	.send = ipi_lpi_send,
> +};
> +
> +static void ipi_enable(int cpu)
> +{
> +	int ipi;
> +
> +	if (WARN_ON_ONCE(!ipi_irq_base))
> +		return;
> +
> +	for (ipi = 0; ipi < nr_ipi; ipi++)
> +		ipi_ops->enable(cpu, ipi);
> +}
> +
> +#ifdef CONFIG_HOTPLUG_CPU
> +static void ipi_teardown(int cpu)
> +{
> +	int ipi;
> +
> +	if (WARN_ON_ONCE(!ipi_irq_base))
> +		return;
> +
> +	for (ipi = 0; ipi < nr_ipi; ipi++)
> +		ipi_ops->disable(cpu, ipi);
> +}
> +#endif
> +
>  void __init set_smp_ipi_range_percpu(int ipi_base, int n, int ncpus)
>  {
>  	int i;
> @@ -1139,18 +1181,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