On 06/12/2018 06:18 PM, Jeff Melvile wrote: > Dmitriy (and Philippe), > > Thanks for looking into this. I'm working with Raman. > > On Tue, 22 May 2018, Dmitriy Cherkasov wrote: > >> On 05/20/2018 08:07 AM, Philippe Gerum wrote: >>> On 05/18/2018 06:24 PM, Singh, Raman wrote: >>>> Environment: ARM Cortex-A53 quad-core processor (ARM 64-bit) on a >>>> Zynq Ultrascale+ ZCU102 dev board, Xenomai 3 next branch from May >>>> 14, 2018 (SHA1: 410a4cc1109ba4e0d05b7ece7b4a5210287e1183 ), >>>> Cobalt configuration with POSIX skin, Linux Kernel version 4.9.24 >>>> >>>> I've been having issues with semaphore latency when threads access >>>> semaphores while executing on different cores. When both threads accessing >>>> a semaphore execute on the same processor core, the latency between >>>> one thread posting a semaphore and another waking up after waiting on it >>>> is fairly small. However, as soon as one of the threads is moved to a >>>> different core, the latency between a semaphore post from one thread to a >>>> waiting thread waking up in response starts to become large enough to >>>> affect real time performance. The latencies I've been seeing are on the >>>> order >>>> of 100's of milliseconds. >>>> >>> >>> Reproduced on hikey here: the rescheduling IPIs Xenomai is sending for >>> waking up threads on remote CPUs don't flow to the other end properly >>> (ipipe_send_ipi()), which explains the behavior you have been seeing. >>> >>> @Dmitriy: this may be an issue with the range of SGIs available to the >>> kernel when a secure firmware is enabled, which may be restricted to >>> SGI[0-7]. >>> >>> For the rescheduling IPI on ARM64, the interrupt pipeline attempts to >>> trigger SGI8 which may be reserved by the ATF in secure mode, therefore >>> may never be received on the remote end. >>> >>> Fixing this will require some work in the interrupt pipeline, typically >>> for multiplexing our IPIs on a single SGI below SGI8. As a matter of >>> fact, the same issue exists on the ARM side, but since running a secure >>> firmware there is uncommon for Xenomai users, this went unnoticed (at >>> least not reported yet AFAIR). We need to sync up on this not to >>> duplicate work. >>> >> >> I see this on Hikey with the latest ipipe-arm64 tree as well. I can confirm >> the >> reschedule IPI isn't being received although it is sent. Rearranging the IPIs >> to move reschedule up a few spots resolves the issue, so I think this >> confirms >> the root cause. > > Short term - what is the consequence of naively rearranging the IPIs? What > else breaks? FWIW secure firmware is not in use. Is your test patch > something we can apply to be able to test the multi-core aspects of our > software? > > Let me know if there is anything either of us can do to help. We have > kernel development experience but admittedly not quite at this level. >
This issue may affect the ARM port in some cases as well, so I took a stab at it for ARM64 since the related code is very similar. Could you test that patch? TIA, commit 765aa7853642b46e1c13fd1f21dfcb9d049f5bfa (HEAD -> wip/arm64-ipi-4.9) Author: Philippe Gerum <r...@xenomai.org> Date: Wed Jun 13 19:16:27 2018 +0200 arm64/ipipe: multiplex IPIs SGI8-15 can be reserved for the exclusive use of the firmware. The ARM64 kernel currently uses six of them (NR_IPI), and the pipeline needs to define three more for conveying out-of-band events (i.e. reschedule, hrtimer and critical IPIs). Therefore we have to multiplex nine inter-processor events over eight SGIs (SGI0-7). This patch changes the IPI management in order to multiplex all regular (in-band) IPIs over SGI0, reserving SGI1-3 for out-of-band events. diff --git a/arch/arm64/include/asm/ipipe.h b/arch/arm64/include/asm/ipipe.h index b16f03b508d6..8e756be01906 100644 --- a/arch/arm64/include/asm/ipipe.h +++ b/arch/arm64/include/asm/ipipe.h @@ -32,6 +32,7 @@ #include <linux/jump_label.h> #include <linux/ipipe_trace.h> #include <linux/ipipe_debug.h> +#include <asm/hardirq.h> #define IPIPE_CORE_RELEASE 4 @@ -165,7 +166,7 @@ static inline void ipipe_unmute_pic(void) void __ipipe_early_core_setup(void); void __ipipe_hook_critical_ipi(struct ipipe_domain *ipd); void __ipipe_root_localtimer(unsigned int irq, void *cookie); -void __ipipe_grab_ipi(unsigned svc, struct pt_regs *regs); +void __ipipe_grab_ipi(unsigned int sgi, struct pt_regs *regs); void __ipipe_ipis_alloc(void); void __ipipe_ipis_request(void); diff --git a/arch/arm64/include/asm/ipipe_base.h b/arch/arm64/include/asm/ipipe_base.h index 867474e1b075..4d8beb560a2f 100644 --- a/arch/arm64/include/asm/ipipe_base.h +++ b/arch/arm64/include/asm/ipipe_base.h @@ -31,13 +31,15 @@ #ifdef CONFIG_SMP -extern unsigned __ipipe_first_ipi; - -#define IPIPE_CRITICAL_IPI __ipipe_first_ipi -#define IPIPE_HRTIMER_IPI (IPIPE_CRITICAL_IPI + 1) -#define IPIPE_RESCHEDULE_IPI (IPIPE_CRITICAL_IPI + 2) - -#define IPIPE_LAST_IPI IPIPE_RESCHEDULE_IPI +/* + * Out-of-band IPIs are directly mapped to SGI1-3, instead of + * multiplexed over SGI0 like regular in-band messages. + */ +#define IPIPE_IPI_BASE IPIPE_VIRQ_BASE +#define IPIPE_OOB_IPI_NR 3 +#define IPIPE_CRITICAL_IPI (IPIPE_IPI_BASE + NR_IPI) +#define IPIPE_HRTIMER_IPI (IPIPE_IPI_BASE + NR_IPI + 1) +#define IPIPE_RESCHEDULE_IPI (IPIPE_IPI_BASE + NR_IPI + 2) #ifdef CONFIG_IPIPE_LEGACY #define hard_smp_processor_id() \ diff --git a/arch/arm64/kernel/ipipe.c b/arch/arm64/kernel/ipipe.c index ae1d0f542a3e..57f4e951648e 100644 --- a/arch/arm64/kernel/ipipe.c +++ b/arch/arm64/kernel/ipipe.c @@ -219,7 +219,6 @@ void __ipipe_enable_pipeline(void) irq, (ipipe_irq_handler_t)__ipipe_do_IRQ, NULL, NULL); - #ifdef CONFIG_SMP __ipipe_ipis_request(); #endif /* CONFIG_SMP */ diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index dbb00c13eb6f..3fe20f7b7f36 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -75,23 +75,8 @@ enum ipi_msg_type { IPI_TIMER, IPI_IRQ_WORK, IPI_WAKEUP, -#ifdef CONFIG_IPIPE - IPI_IPIPE_FIRST, -#endif /* CONFIG_IPIPE */ }; -#ifdef CONFIG_IPIPE -#define noipipe_irq_enter() \ - do { \ - } while(0) -#define noipipe_irq_exit() \ - do { \ - } while(0) -#else /* !CONFIG_IPIPE */ -#define noipipe_irq_enter() irq_enter() -#define noipipe_irq_exit() irq_exit() -#endif /* !CONFIG_IPIPE */ - #ifdef CONFIG_ARM64_VHE /* Whether the boot CPU is running in HYP mode or not*/ @@ -766,12 +751,6 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { S(IPI_WAKEUP, "CPU wake-up interrupts"), }; -static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) -{ - trace_ipi_raise(target, ipi_types[ipinr]); - __smp_cross_call(target, ipinr); -} - void show_ipi_list(struct seq_file *p, int prec) { unsigned int cpu, i; @@ -798,60 +777,123 @@ u64 smp_irq_stat_cpu(unsigned int cpu) } #ifdef CONFIG_IPIPE -#define IPIPE_IPI_BASE IPIPE_VIRQ_BASE -unsigned __ipipe_first_ipi; -EXPORT_SYMBOL_GPL(__ipipe_first_ipi); +static DEFINE_PER_CPU(unsigned long, ipi_messages); + +#define noipipe_irq_enter() \ + do { \ + } while(0) +#define noipipe_irq_exit() \ + do { \ + } while(0) -static void __ipipe_do_IPI(unsigned virq, void *cookie) +static void __ipipe_do_IPI(unsigned int virq, void *cookie) { - enum ipi_msg_type msg = virq - IPIPE_IPI_BASE; - handle_IPI(msg, raw_cpu_ptr(&ipipe_percpu.tick_regs)); + unsigned int ipinr = virq - IPIPE_IPI_BASE; + + handle_IPI(ipinr, raw_cpu_ptr(&ipipe_percpu.tick_regs)); } void __ipipe_ipis_alloc(void) { - unsigned int virq, ipi, last_ipi; + unsigned int virq, ipi; + static bool done; /* May be called multiple times via init_stage() */ - if (__ipipe_first_ipi) + if (done) return; - last_ipi = NR_IPI + IPIPE_LAST_IPI; - for (ipi = 0; ipi <= last_ipi; ipi++) { + /* + * We have to get virtual IRQs in the range + * [ IPIPE_IPI_BASE..IPIPE_IPI_BASE + NR_IPI + IPIPE_OOB_IPI_NR - 1 ], + * otherwise something is wrong (likely someone would have + * allocated virqs before we do, and this would break our + * fixed numbering scheme for IPIs). + */ + for (ipi = 0; ipi < NR_IPI + IPIPE_OOB_IPI_NR; ipi++) { virq = ipipe_alloc_virq(); - if (ipi == IPI_IPIPE_FIRST) - __ipipe_first_ipi = virq; + WARN_ON_ONCE(virq != IPIPE_IPI_BASE + ipi); } + + done = true; } void __ipipe_ipis_request(void) { - unsigned virq; + unsigned int virq; - for (virq = IPIPE_IPI_BASE; virq < __ipipe_first_ipi; virq++) + /* + * Attach a handler to each VIRQ mapping an IPI which might be + * posted by __ipipe_grab_ipi(). This handler will invoke + * handle_IPI() from the root stage in turn, passing it the + * corresponding IPI message number. + */ + for (virq = IPIPE_IPI_BASE; + virq < IPIPE_IPI_BASE + NR_IPI + IPIPE_OOB_IPI_NR; virq++) ipipe_request_irq(ipipe_root_domain, virq, (ipipe_irq_handler_t)__ipipe_do_IPI, NULL, NULL); } -void ipipe_send_ipi(unsigned ipi, cpumask_t cpumask) + +static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) +{ + unsigned int cpu, sgi; + + if (ipinr < NR_IPI) { + /* regular in-band IPI (multiplexed over SGI0). */ + trace_ipi_raise_rcuidle(target, ipi_types[ipinr]); + for_each_cpu(cpu, target) + set_bit(ipinr, &per_cpu(ipi_messages, cpu)); + smp_mb(); + sgi = 0; + } else /* out-of-band IPI (SGI1-3). */ + sgi = ipinr - NR_IPI + 1; + + __smp_cross_call(target, sgi); +} + +void ipipe_send_ipi(unsigned int ipi, cpumask_t cpumask) { - enum ipi_msg_type msg = ipi - IPIPE_IPI_BASE; - smp_cross_call(&cpumask, msg); + unsigned int ipinr = ipi - IPIPE_IPI_BASE; + smp_cross_call(&cpumask, ipinr); } EXPORT_SYMBOL_GPL(ipipe_send_ipi); /* hw IRQs off */ -asmlinkage void __exception __ipipe_grab_ipi(unsigned svc, struct pt_regs *regs) +asmlinkage void __ipipe_grab_ipi(unsigned int sgi, struct pt_regs *regs) { - int virq = IPIPE_IPI_BASE + svc; + unsigned int ipinr, irq; + unsigned long *pmsg; - __ipipe_dispatch_irq(virq, IPIPE_IRQF_NOACK); + if (sgi) { /* SGI1-3, OOB messages. */ + irq = sgi + NR_IPI - 1 + IPIPE_IPI_BASE; + __ipipe_dispatch_irq(irq, IPIPE_IRQF_NOACK); + } else { + /* In-band IPI (0..NR_IPI-1) multiplexed over SGI0. */ + pmsg = raw_cpu_ptr(&ipi_messages); + while (*pmsg) { + ipinr = ffs(*pmsg) - 1; + clear_bit(ipinr, pmsg); + irq = IPIPE_IPI_BASE + ipinr; + __ipipe_dispatch_irq(irq, IPIPE_IRQF_NOACK); + } + } __ipipe_exit_irq(regs); } +#else + +#define noipipe_irq_enter() irq_enter() +#define noipipe_irq_exit() irq_exit() + +static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) +{ + trace_ipi_raise(target, ipi_types[ipinr]); + __smp_cross_call(target, ipinr); +} + #endif /* CONFIG_IPIPE */ void arch_send_call_function_ipi_mask(const struct cpumask *mask) -- Philippe. _______________________________________________ Xenomai mailing list Xenomai@xenomai.org https://xenomai.org/mailman/listinfo/xenomai