On Thu, Mar 30, 2023, at 22:42, Prabhakar wrote: > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx> > > Currently, selecting which CMOs to use on a given platform is done using > and ALTERNATIVE_X() macro. This was manageable when there were just two > CMO implementations, but now that there are more and more platforms coming > needing custom CMOs, the use of the ALTERNATIVE_X() macro is unmanageable. > > To avoid such issues this patch switches to use of function pointers > instead of ALTERNATIVE_X() macro for cache management (the only drawback > being performance over the previous approach). > > void (*clean_range)(unsigned long addr, unsigned long size); > void (*inv_range)(unsigned long addr, unsigned long size); > void (*flush_range)(unsigned long addr, unsigned long size); > > The above function pointers are provided to be overridden for platforms > needing CMO. > > Convert ZICBOM and T-HEAD CMO to use function pointers. > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx> This is looking pretty good. There are a few things that I still see sticking out, and I think I've mentioned some of them before, but don't remember if there was a reason for doing it like this: > +#ifdef CONFIG_ERRATA_THEAD_CMO I would rename this to not call this an 'ERRATA' but just make it a driver. Not important though, and there was probably a reason you did it like this. > +extern struct riscv_cache_ops noncoherent_cache_ops; > + > +void riscv_noncoherent_register_cache_ops(const struct riscv_cache_ops > *ops); > + > +static inline void riscv_dma_noncoherent_clean(void *vaddr, size_t > size) > +{ > + if (noncoherent_cache_ops.clean_range) { > + unsigned long addr = (unsigned long)vaddr; > + > + noncoherent_cache_ops.clean_range(addr, size); > + } > +} The type case should not be necessary here. Instead I would make the callbacks use 'void *' as well, not 'unsigned long'. It's possible that some future cache controller driver requires passing physical addresses, as is common for last level cache, but as long as all drivers pass virtual addresses, it's easier to do the phys_to_virt() in common code. It also seems wrong to have the fallback be to do nothing when the pointer is NULL, since that cannot actually work when a device is not cache coherent. I would either initialize the function pointer to the zicbom version and remove the NULL check, or keep the pointer NULL and have an explicit 'else zicbom_clean_range()' fallback. > +static void zicbom_register_cmo_ops(void) > +{ > + riscv_noncoherent_register_cache_ops(&zicbom_cmo_ops); > +} > +#else > +static void zicbom_register_cmo_ops(void) {} > +#endif As far as I recall, the #else path here was needed previously to work around a binutils dependency, but with the current code, it should be possible to just always enable CONFIG_RISCV_ISA_ZICBOM when RISCV_DMA_NONCOHERENT is used. Arnd