[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4 5/7] xen/riscv: introduce and initialize SBI RFENCE extension
On 09.08.2024 18:19, Oleksii Kurochko wrote: > @@ -31,4 +65,34 @@ struct sbiret sbi_ecall(unsigned long ext, unsigned long > fid, > */ > void sbi_console_putchar(int ch); > > +/* > + * Check underlying SBI implementation has RFENCE > + * > + * @return 1 for supported AND 0 for not-supported > + */ > +bool sbi_has_rfence(void); Nit: With bool return type, true and false in the comment? > +/* > + * Instructs the remote harts to execute one or more SFENCE.VMA > + * instructions, covering the range of virtual addresses between > + * start_addr and start_addr + size. It's relatively clear what is meant here, but maybe still better to make things explicit by using a mathematical range: [start_addr, start_addr + size). > + * Returns 0 if IPI was sent to all the targeted harts successfully > + * or negative value if start_addr or size is not valid. > + * > + * @hart_mask a cpu mask containing all the target harts. > + * @param start virtual address start > + * @param size virtual address range size > + */ > +int sbi_remote_sfence_vma(cpumask_t *cpu_mask, pointer-to-const? > --- a/xen/arch/riscv/sbi.c > +++ b/xen/arch/riscv/sbi.c > @@ -7,11 +7,23 @@ > * Modified by Bobby Eshleman (bobby.eshleman@xxxxxxxxx). > * > * Copyright (c) 2019 Western Digital Corporation or its affiliates. > - * Copyright (c) 2021-2023 Vates SAS. > + * Copyright (c) 2021-2024 Vates SAS. > */ > > +#include <xen/compiler.h> > +#include <xen/const.h> > +#include <xen/cpumask.h> > +#include <xen/errno.h> > +#include <xen/init.h> > +#include <xen/lib.h> > +#include <xen/smp.h> > + > +#include <asm/processor.h> > #include <asm/sbi.h> > > +static unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT; > +static unsigned long sbi_fw_id, sbi_fw_version; __ro_after_init for perhaps all three of them? Considering SBI_SPEC_VERSION_{MAJOR,MINOR}_MASK, at least the first of them also doesn't need to be unsigned long, but could be unsigned int? > @@ -38,7 +50,245 @@ struct sbiret sbi_ecall(unsigned long ext, unsigned long > fid, > return ret; > } > > +static int sbi_err_map_xen_errno(int err) > +{ > + switch ( err ) > + { > + case SBI_SUCCESS: > + return 0; > + case SBI_ERR_DENIED: > + return -EACCES; > + case SBI_ERR_INVALID_PARAM: > + return -EINVAL; > + case SBI_ERR_INVALID_ADDRESS: > + return -EFAULT; > + case SBI_ERR_NOT_SUPPORTED: > + return -EOPNOTSUPP; > + case SBI_ERR_FAILURE: > + fallthrough; > + default: > + return -ENOSYS; > + }; > +} > + > void sbi_console_putchar(int ch) > { > sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0); > } > + > +static unsigned long sbi_major_version(void) > +{ > + return (sbi_spec_version >> SBI_SPEC_VERSION_MAJOR_SHIFT) & > + SBI_SPEC_VERSION_MAJOR_MASK; > +} Can you use MASK_EXTR() here, allowing to even drop the separate SBI_SPEC_VERSION_MAJOR_SHIFT? > +static unsigned long sbi_minor_version(void) > +{ > + return sbi_spec_version & SBI_SPEC_VERSION_MINOR_MASK; > +} For consistency here then, too. > +static long sbi_ext_base_func(long fid) > +{ > + struct sbiret ret; > + > + ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0); > + if ( !ret.error ) > + return ret.value; > + else > + return ret.error; With the folding of two distinct values, how is the caller going to tell failure from success? > +} > + > +static int __sbi_rfence_v02_real(unsigned long fid, Are the double leading underscores really necessary here? (Same again further down.) > + unsigned long hmask, unsigned long hbase, > + unsigned long start, unsigned long size, > + unsigned long arg4) > +{ > + struct sbiret ret = {0}; > + int result = 0; > + > + switch ( fid ) > + { > + case SBI_EXT_RFENCE_REMOTE_FENCE_I: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + 0, 0, 0, 0); > + break; > + case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + start, size, 0, 0); > + break; > + case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + start, size, arg4, 0); > + break; > + case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + start, size, 0, 0); > + break; How is e.g. this different from SBI_EXT_RFENCE_REMOTE_SFENCE_VMA handling? To ease recognition, I think you want to fold cases with identical handling. > + case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + start, size, arg4, 0); > + break; > + case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + start, size, 0, 0); > + break; > + case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: > + ret = sbi_ecall(SBI_EXT_RFENCE, fid, hmask, hbase, > + start, size, arg4, 0); > + break; > + > + default: Nit: Just like you have it here, blank lines please between any non- fallthrough case blocks. > + printk("%s: unknown function ID [%lu]\n", > + __func__, fid); > + result = -EINVAL; > + break; > + }; > + > + if ( ret.error ) > + { > + result = sbi_err_map_xen_errno(ret.error); > + printk("%s: hbase=%lu hmask=%#lx failed (error %d)\n", > + __func__, hbase, hmask, result); > + } > + > + return result; > +} > + > +static int __sbi_rfence_v02(unsigned long fid, This has its address taken for storing in a function pointer. I'd like to suggest that from the very beginning you mark such functions cf_check. > + const cpumask_t *cpu_mask, > + unsigned long start, unsigned long size, > + unsigned long arg4, unsigned long arg5) > +{ > + unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0; > + int result; > + > + /* > + * hart_mask_base can be set to -1 to indicate that hart_mask can be > + * ignored and all available harts must be considered. > + */ > + if ( !cpu_mask ) > + return __sbi_rfence_v02_real(fid, 0UL, -1UL, start, size, arg4); > + > + for_each_cpu( cpuid, cpu_mask ) Nit: Either for_each_cpu ( cpuid, cpu_mask ) (if you deem for_each_cpu a pseudo-keyword) or for_each_cpu(cpuid, cpu_mask) (if you don't). > + { > + hartid = cpuid_to_hartid(cpuid); > + if ( hmask ) > + { > + if ( hartid + BITS_PER_LONG <= htop || > + hbase + BITS_PER_LONG <= hartid ) > + { > + result = __sbi_rfence_v02_real(fid, hmask, hbase, > + start, size, arg4); > + if ( result ) > + return result; > + hmask = 0; > + } > + else if ( hartid < hbase ) > + { > + /* shift the mask to fit lower hartid */ > + hmask <<= hbase - hartid; > + hbase = hartid; > + } > + } > + > + if ( !hmask ) > + { > + hbase = hartid; > + htop = hartid; > + } else if ( hartid > htop ) Nit: Closing brace on its own line please. > + htop = hartid; > + > + hmask |= BIT(hartid - hbase, UL); > + } I can see how you will successfully batch for certain configurations this way. When hart ID mapping is something like (0,64,1,65,2,66,...) you won't batch at all though. Which may be fine at least for now, but then I think a comment wants to state what is or is not intended to be covered. It is only this way that people will know that certain shortcomings aren't bugs. > + if ( hmask ) > + { > + result = __sbi_rfence_v02_real(fid, hmask, hbase, > + start, size, arg4); > + if ( result ) > + return result; > + } > + > + return 0; > +} > + > +static int (*__sbi_rfence)(unsigned long fid, > + const cpumask_t *cpu_mask, > + unsigned long start, unsigned long size, > + unsigned long arg4, unsigned long arg5) = NULL; __ro_after_init and no need for an initializer. > +int sbi_remote_sfence_vma(cpumask_t *cpu_mask, > + unsigned long start_addr, > + unsigned long size) > +{ > + return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA, > + cpu_mask, start_addr, size, 0, 0); No check (not even an assertion) here for __sbi_rfence still being NULL? > +int __init sbi_init(void) > +{ > + int ret; > + > + ret = sbi_get_spec_version(); > + if ( ret > 0 ) > + sbi_spec_version = ret; Truncation from long to int is not an issue here? > + printk("SBI specification v%lu.%lu detected\n", > + sbi_major_version(), sbi_minor_version()); > + > + if ( !sbi_spec_is_0_1() ) > + { > + sbi_fw_id = sbi_get_firmware_id(); > + sbi_fw_version = sbi_get_firmware_version(); These cannot return errors? > + printk("SBI implementation ID=%#lx Version=%#lx\n", > + sbi_fw_id, sbi_fw_version); > + > + if ( sbi_probe_extension(SBI_EXT_RFENCE) > 0 ) > + { > + __sbi_rfence = __sbi_rfence_v02; > + printk("SBI v0.2 RFENCE extension detected\n"); > + } > + } else { Nit: Style (and I think I said so before). > + BUG_ON("Ooops. SBI spec veriosn 0.1 detected. Need to add support"); Besides the typo (version) here and ... > + } > + > + if ( !sbi_has_rfence() ) > + { > + BUG_ON("At the moment flush_xen_tlb_range_va() uses SBI rfence to " > + "flush TLB for all CPUS!"); ... here better panic()? A call trace doesn't really add any value for these. Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |