[PATCH] powerpc/powernv: implement NMI IPI with OPAL_SIGNAL_SYSTEM_RESET

Alistair Popple alistair at popple.id.au
Fri Feb 3 17:00:19 AEDT 2017


On Fri, 3 Feb 2017 03:20:48 PM Nicholas Piggin wrote:
> On Fri,  3 Feb 2017 00:25:11 +1000
> Nicholas Piggin <npiggin at gmail.com> wrote:
>
> > This goes with the previous NMI IPI series, and a new version of
> > Alistair's opal API I posted to the skiboot list.
>
> And here is the incremental bit that is required for Alistair's
> hardware implementation to work.
>
> If the opal broacast call fails with OPAL_PARTIAL, then we designate
> a bouncer CPU on another core to send NMI IPIs back to our sibling
> threads.
>
> Probably needs more discussion and testing about how to detect and
> handle failure cases and future compatibility for different types of
> restrictions, but at least it works in mambo.

Looking at the Mambo implementation you recently posted I couldn't see
where OPAL_PARTIAL was returned. So I guess you have other Skiboot
patches to test this path using Mambo? I'm wondering because they
could be useful for testing the skiboot HW side as well...

>
> Of course the other option rather than doing this in Linux is call
> into opal in the system reset handler and have it do the bouncing.
> Something to consider before we finalise the API.

That might not be such a bad idea. OPAL could queue up the threads it
couldn't reset and then wait until opal_sreset_complete() is called
from an eligible thread to reset the ones it couldn't do in the
original call.

I might try prototyping something like this when I get some time. One
issue would be if there is only a single core in the system, but
that's unlikely and I think that's probably something we can't support
in any case as cores can't sreset threads on the same core, at least
on P8.

- Alistair

> Thanks,
> Nick
>
> ---
>  arch/powerpc/platforms/powernv/smp.c | 88 +++++++++++++++++++++++++++++++++---
>  1 file changed, 82 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
> index f90555f75723..4241fda9df9e 100644
> --- a/arch/powerpc/platforms/powernv/smp.c
> +++ b/arch/powerpc/platforms/powernv/smp.c
> @@ -241,8 +241,32 @@ static int pnv_cpu_bootable(unsigned int nr)
>  	return smp_generic_cpu_bootable(nr);
>  }
>
> +static int nmi_ipi_bounce_cpu;
> +static int nmi_ipi_bounce_cpu_done;
> +static int nmi_ipi_bounce_target_core;
> +static int nmi_ipi_bounce_target_exclude;
> +
>  int pnv_system_reset_exception(struct pt_regs *regs)
>  {
> +	smp_rmb();
> +	if (nmi_ipi_bounce_cpu == smp_processor_id()) {
> +		int64_t rc;
> +		int c;
> +
> +		for_each_online_cpu(c) {
> +			if (!cpumask_test_cpu(c, cpu_sibling_mask(nmi_ipi_bounce_target_core)))
> +				continue;
> +			if (c == nmi_ipi_bounce_target_exclude)
> +				continue;
> +			rc = opal_signal_system_reset(c);
> +			if (rc != OPAL_SUCCESS) {
> +				nmi_ipi_bounce_cpu_done = -1;
> +				return 1;
> +			}
> +		}
> +		nmi_ipi_bounce_cpu_done = 1;
> +	}
> +
>  	if (smp_handle_nmi_ipi(regs))
>  		return 1;
>  	return 0;
> @@ -252,13 +276,65 @@ static int pnv_cause_nmi_ipi(int cpu)
>  {
>  	int64_t rc;
>
> -	rc = opal_signal_system_reset(cpu);
> -	if (rc == OPAL_SUCCESS)
> -		return 1;
> +	if (cpu >= 0) {
> +		rc = opal_signal_system_reset(cpu);
> +		if (rc == OPAL_SUCCESS)
> +			return 1;
> +	} else {
> +		/*
> +		 * Test bounce behavior with broadcast IPI.
> +		 */
> +		rc = OPAL_PARTIAL;
> +	}
> +	if (rc == OPAL_PARTIAL) {
> +		int c;
>
> -	/*
> -	 * Don't cope with OPAL_PARTIAL yet (just punt to regular IPI)
> -	 */
> +		/*
> +		 * Some platforms can not send NMI to sibling threads in
> +		 * the same core. We can designate one inter-core target
> +		 * to bounce NMIs back to our sibling threads.
> +		 */
> +
> +		if (cpu >= 0) {
> +			/*
> +			 * Don't support bouncing unicast NMIs yet (because
> +			 * that would have to raise an NMI on an unrelated
> +			 * CPU. Revisit this if callers start using unicast.
> +			 */
> +			return 0;
> +		}
> +
> +		nmi_ipi_bounce_cpu = -1;
> +		nmi_ipi_bounce_cpu_done = 0;
> +		nmi_ipi_bounce_target_core = -1;
> +		nmi_ipi_bounce_target_exclude = -1;
> +		smp_wmb();
> +
> +		for_each_online_cpu(c) {
> +			if (cpumask_test_cpu(c, cpu_sibling_mask(smp_processor_id())))
> +				continue;
> +
> +			if (nmi_ipi_bounce_cpu == -1) {
> +				nmi_ipi_bounce_cpu = c;
> +				nmi_ipi_bounce_target_core = smp_processor_id();
> +				if (cpu == NMI_IPI_ALL_OTHERS)
> +					nmi_ipi_bounce_target_exclude = smp_processor_id();
> +			}
> +
> +			rc = opal_signal_system_reset(c);
> +			if (rc != OPAL_SUCCESS)
> +				return 0;
> +		}
> +
> +		if (nmi_ipi_bounce_cpu == -1)
> +			return 0; /* could not find a bouncer */
> +
> +		while (!nmi_ipi_bounce_cpu_done)
> +			cpu_relax();
> +
> +		if (nmi_ipi_bounce_cpu_done == 1)
> +			return 1; /* bounce worked */
> +	}
>
>  	return 0;
>  }
>



More information about the Linuxppc-dev mailing list