Message ID | 20200510075510.987823-32-hch@lst.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [01/31] arm: fix the flush_icache_range arguments in set_fiq_handler | expand |
On Sun, May 10, 2020 at 9:57 AM Christoph Hellwig <hch@lst.de> wrote: > > flush_icache_range generally operates on kernel addresses, but for some > reason m68k needed a set_fs override. Move that into the m68k code > insted of keeping it in the module loader. > > Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Gr{oetje,eeting}s, Geert
On Mon, May 11, 2020 at 09:40:39AM +0200, Geert Uytterhoeven wrote: > On Sun, May 10, 2020 at 9:57 AM Christoph Hellwig <hch@lst.de> wrote: > > > > flush_icache_range generally operates on kernel addresses, but for some > > reason m68k needed a set_fs override. Move that into the m68k code > > insted of keeping it in the module loader. > > > > Signed-off-by: Christoph Hellwig <hch@lst.de> > > Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> > Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Btw, do you know what part of flush_icache_range relied on set_fs? Do any of the m68k maintainers have an idea how to handle that in a nicer way when we can split the implementations?
Hi Christoph, On Mon, May 11, 2020 at 5:11 PM Christoph Hellwig <hch@lst.de> wrote: > On Mon, May 11, 2020 at 09:40:39AM +0200, Geert Uytterhoeven wrote: > > On Sun, May 10, 2020 at 9:57 AM Christoph Hellwig <hch@lst.de> wrote: > > > > > > flush_icache_range generally operates on kernel addresses, but for some > > > reason m68k needed a set_fs override. Move that into the m68k code > > > insted of keeping it in the module loader. > > > > > > Signed-off-by: Christoph Hellwig <hch@lst.de> > > > > Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> > > Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> > > Btw, do you know what part of flush_icache_range relied on set_fs? > Do any of the m68k maintainers have an idea how to handle that in > a nicer way when we can split the implementations? arch/m68k/mm/cache.c:virt_to_phys_slow() All instructions that look up addresses in the page tables look at the source/destination function codes (SFC/DFC) to know if they have to use the supervisor or user page tables. So the actual implementation is the same: set_fs() merely configures SFC/DFC, to select the address space to use. Gr{oetje,eeting}s, Geert
On Mon, May 11, 2020 at 05:24:30PM +0200, Geert Uytterhoeven wrote: > > Btw, do you know what part of flush_icache_range relied on set_fs? > > Do any of the m68k maintainers have an idea how to handle that in > > a nicer way when we can split the implementations? > > arch/m68k/mm/cache.c:virt_to_phys_slow() > > All instructions that look up addresses in the page tables look at the > source/destination function codes (SFC/DFC) to know if they have to use > the supervisor or user page tables. > So the actual implementation is the same: set_fs() merely configures > SFC/DFC, to select the address space to use. So instead of the magic instructions could we use the normal kernel virt to phys helpers instead of switching the addresses space? Something like this patch on top of the series: diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c index 5ecb3310e8745..5a861a14c1e69 100644 --- a/arch/m68k/mm/cache.c +++ b/arch/m68k/mm/cache.c @@ -71,47 +71,87 @@ static unsigned long virt_to_phys_slow(unsigned long vaddr) return 0; } -/* Push n pages at kernel virtual address and clear the icache */ -/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */ -void flush_icache_user_range(unsigned long address, unsigned long endaddr) +static inline void coldfire_flush_icache_range(unsigned long start, + unsigned long end) { - if (CPU_IS_COLDFIRE) { - unsigned long start, end; - start = address & ICACHE_SET_MASK; - end = endaddr & ICACHE_SET_MASK; - if (start > end) { - flush_cf_icache(0, end); - end = ICACHE_MAX_ADDR; - } - flush_cf_icache(start, end); - } else if (CPU_IS_040_OR_060) { - address &= PAGE_MASK; - - do { - asm volatile ("nop\n\t" - ".chip 68040\n\t" - "cpushp %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (virt_to_phys_slow(address))); - address += PAGE_SIZE; - } while (address < endaddr); - } else { - unsigned long tmp; - asm volatile ("movec %%cacr,%0\n\t" - "orw %1,%0\n\t" - "movec %0,%%cacr" - : "=&d" (tmp) - : "di" (FLUSH_I)); + start &= ICACHE_SET_MASK; + end &= ICACHE_SET_MASK; + + if (start > end) { + flush_cf_icache(0, end); + end = ICACHE_MAX_ADDR; } + flush_cf_icache(start, end); +} + +static inline void mc68040_flush_icache_user_range(unsigned long start, + unsigned long end) +{ + start &= PAGE_MASK; + + do { + asm volatile ("nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (virt_to_phys_slow(start))); + start += PAGE_SIZE; + } while (start < end); +} + +static inline void mc68020_flush_icache_range(unsigned long start, + unsigned long end) +{ + unsigned long tmp; + + asm volatile ("movec %%cacr,%0\n\t" + "orw %1,%0\n\t" + "movec %0,%%cacr" + : "=&d" (tmp) + : "di" (FLUSH_I)); +} + +void flush_icache_user_range(unsigned long start, unsigned long end) +{ + if (CPU_IS_COLDFIRE) + coldfire_flush_icache_range(start, end); + else if (CPU_IS_040_OR_060) + mc68040_flush_icache_user_range(start, end); + else + mc68020_flush_icache_range(start, end); } -void flush_icache_range(unsigned long address, unsigned long endaddr) +static inline void mc68040_flush_icache_range(unsigned long start, + unsigned long end) { - mm_segment_t old_fs = get_fs(); + start &= PAGE_MASK; + + do { + void *vaddr = (void *)start; + phys_addr_t paddr; + + if (is_vmalloc_addr(vaddr)) + paddr = page_to_phys(vmalloc_to_page(vaddr)); + else + paddr = virt_to_phys(vaddr); + + asm volatile ("nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); + start += PAGE_SIZE; + } while (start < end); +} - set_fs(KERNEL_DS); - flush_icache_user_range(address, endaddr); - set_fs(old_fs); +void flush_icache_range(unsigned long start, unsigned long end) +{ + if (CPU_IS_COLDFIRE) + coldfire_flush_icache_range(start, end); + else if (CPU_IS_040_OR_060) + mc68040_flush_icache_range(start, end); + else + mc68020_flush_icache_range(start, end); } EXPORT_SYMBOL(flush_icache_range);
diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c index 7915be3a09712..5ecb3310e8745 100644 --- a/arch/m68k/mm/cache.c +++ b/arch/m68k/mm/cache.c @@ -107,7 +107,11 @@ void flush_icache_user_range(unsigned long address, unsigned long endaddr) void flush_icache_range(unsigned long address, unsigned long endaddr) { + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); flush_icache_user_range(address, endaddr); + set_fs(old_fs); } EXPORT_SYMBOL(flush_icache_range); diff --git a/kernel/module.c b/kernel/module.c index 646f1e2330d2b..b1673ed49594f 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3312,12 +3312,6 @@ static int check_module_license_and_versions(struct module *mod) static void flush_module_icache(const struct module *mod) { - mm_segment_t old_fs; - - /* flush the icache in correct context */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - /* * Flush the instruction cache, since we've played with text. * Do it before processing of module parameters, so the module @@ -3329,8 +3323,6 @@ static void flush_module_icache(const struct module *mod) + mod->init_layout.size); flush_icache_range((unsigned long)mod->core_layout.base, (unsigned long)mod->core_layout.base + mod->core_layout.size); - - set_fs(old_fs); } int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
flush_icache_range generally operates on kernel addresses, but for some reason m68k needed a set_fs override. Move that into the m68k code insted of keeping it in the module loader. Signed-off-by: Christoph Hellwig <hch@lst.de> --- arch/m68k/mm/cache.c | 4 ++++ kernel/module.c | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-)