On Sun, Sep 15, 2019 at 11:28:13AM +1000, Nicholas Piggin wrote: > Add support for the scv instruction on POWER9 and later CPUs. > > For now this implements the zeroth scv vector 'scv 0', as identical > to 'sc' system calls, with the exception that lr is not preserved, and > it is 64-bit only. There may yet be changes made to this ABI, so it's > for testing only. > > This also doesn't yet properly handle PR KVM, or the case where a guest > is denied AIL=3 mode. I haven't added real mode entry points, so scv > must not be used when AIL=0, but I haven't cleared the FSCR in this > case. > > This also implements a strange hack to handle the non-implemented > vectors, scheduling a decrementer and expecting it to interrupt and > replay pending soft masked interrupts. This is unlikely to be a good > idea, and needs to actually do a proper handler and replay in case an > interrupt is pending. > > It may also require some errata handling before it can be safely used > on all POWER9 CPUs, I have to look that up. > > rfscv is implemented to return from scv type system calls. It can not > be used to return from sc system calls because those are defined to > preserve lr. > > In a comparison of getpid syscall, the test program had scv taking > about 3 more cycles in user mode (92 vs 89 for sc), due to lr handling. > Total cycles taken for a getpid system call on POWER9 are improved from > 436 to 345 (26.3% faster), mostly due to reducing mtmsr and mtspr. ... > diff --git a/arch/powerpc/kernel/syscall_64.c > b/arch/powerpc/kernel/syscall_64.c > index 034b52d3d78c..3e8aa5ae8ec8 100644 > --- a/arch/powerpc/kernel/syscall_64.c > +++ b/arch/powerpc/kernel/syscall_64.c > @@ -15,6 +15,77 @@ extern void __noreturn tabort_syscall(void); > > typedef long (*syscall_fn)(long, long, long, long, long, long); > > +#ifdef CONFIG_PPC_BOOK3S > +long system_call_vectored_exception(long r3, long r4, long r5, long r6, long > r7, long r8, unsigned long r0, struct pt_regs *regs) > +{ > + unsigned long ti_flags; > + syscall_fn f; > + > + BUG_ON(!(regs->msr & MSR_RI)); > + BUG_ON(!(regs->msr & MSR_PR)); > + BUG_ON(!FULL_REGS(regs)); > + BUG_ON(regs->softe != IRQS_ENABLED); > + > + if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) && > + unlikely(regs->msr & MSR_TS_T)) > + tabort_syscall(); > + > + account_cpu_user_entry(); > + > +#ifdef CONFIG_PPC_SPLPAR > + if (IS_ENABLED(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && > + firmware_has_feature(FW_FEATURE_SPLPAR)) { > + struct lppaca *lp = get_lppaca(); > + > + if (unlikely(local_paca->dtl_ridx != lp->dtl_idx)) This adds another instance of the lack of endian conversion issue. > + accumulate_stolen_time(); > + } > +#endif
Thanks Michal