Re: [PATCH 31/31] module: move the set_fs hack for flush_icache_range to m68k

Christoph Hellwig
2020-05-11T16:37:51Z

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);