[RFC/PATCH] powerpc: Deal with 44x virtually tagged icache
Josh Boyer
jwboyer at linux.vnet.ibm.com
Tue Oct 30 23:23:10 EST 2007
On Tue, 30 Oct 2007 16:16:54 +1100
Benjamin Herrenschmidt <benh at kernel.crashing.org> wrote:
> The 44x family has an interesting "feature" which is a virtually
> tagged instruction cache (yuck !). So far, we haven't dealt with
> it properly, which means we've been mostly lucky or people didn't
> report the problems, unless people have been running custom patches
> in their distro...
>
> This is an attempt at fixing it properly. I chose to do it by
> setting a global flag whenever we change a PTE that was previously
> marked executable, and flush the entire instruction cache upon
> return to user space when that happens.
>
> This is a bit heavy handed, but it's hard to do more fine grained
> flushes as the icbi instruction, on those processor, for some very
> strange reasons (since the cache is virtually mapped) still requires
> a valid TLB entry for reading in the target address space, which
> isn't something I want to deal with.
>
> Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
> ---
>
> Fortunately, we don't support SMP on these or this solution wouldn't
> work.
We should mark 44x BROKEN on SMP in Kconfig.
>
> It does mean we do a bit of over-flushing on swap but on the
> other hand, the code is simple. Another option would have been
> to do the iccci after any syscall that potentially unmaps or
> changes a mapping, like sys_munmap, sys_mremap, sys_sbrk, but
> also the shmem stuff etc... I decided there was just too many
> and was worried I would miss one.
>
> This not very tested as I don't have a test case at hand showing the
> problem and didn't feel like writing one today :-) It boots though.
>
> Careful eyes will notice I didn't do the flush on fast_exception_return,
> which shouldn't be necessary.
>
> arch/powerpc/kernel/entry_32.S | 25 +++++++++++++++++++++++++
> arch/powerpc/kernel/misc_32.S | 9 +++++++++
> arch/powerpc/mm/44x_mmu.c | 1 +
> include/asm-powerpc/pgtable-ppc32.h | 13 +++++++++++++
> 4 files changed, 48 insertions(+)
No arch/ppc fix? I know we all want it to die as soon as possible, but
still... :)
> Index: linux-work/arch/powerpc/kernel/entry_32.S
> ===================================================================
> --- linux-work.orig/arch/powerpc/kernel/entry_32.S 2007-10-15 11:19:35.000000000 +1000
> +++ linux-work/arch/powerpc/kernel/entry_32.S 2007-10-30 16:09:51.000000000 +1100
> @@ -244,6 +244,13 @@ syscall_exit_cont:
> andis. r10,r0,DBCR0_IC at h
> bnel- load_dbcr0
> #endif
> +#ifdef CONFIG_44x
> + lis r4,icache_44x_need_flush at ha
> + lwz r5,icache_44x_need_flush at l(r4)
> + cmplwi cr0,r5,0
> + bne- 2f
> +1:
> +#endif /* CONFIG_44x */
> stwcx. r0,0,r1 /* to clear the reservation */
> lwz r4,_LINK(r1)
> lwz r5,_CCR(r1)
> @@ -259,6 +266,13 @@ syscall_exit_cont:
> SYNC
> RFI
>
> +#ifdef CONFIG_44x
> +2: li r7,0
> + iccci r0,r0
> + stw r7,icache_44x_need_flush at l(r4)
> + b 1b
> +#endif /* CONFIG_44x */
> +
> 66: li r3,-ENOSYS
> b ret_from_syscall
>
> @@ -683,6 +697,17 @@ resume_kernel:
>
> /* interrupts are hard-disabled at this point */
> restore:
> +#ifdef CONFIG_44x
> + lis r4,icache_44x_need_flush at ha
> + lwz r5,icache_44x_need_flush at l(r4)
> + cmplwi cr0,r5,0
> + beq+ 1f
> + iccci r0,r0
> + li r6,0
> + iccci r0,r0
> + stw r6,icache_44x_need_flush at l(r4)
> +1:
Why two iccci's here?
> +#endif /* CONFIG_44x */
> lwz r0,GPR0(r1)
> lwz r2,GPR2(r1)
> REST_4GPRS(3, r1)
> Index: linux-work/arch/powerpc/mm/44x_mmu.c
> ===================================================================
> --- linux-work.orig/arch/powerpc/mm/44x_mmu.c 2007-09-28 11:42:05.000000000 +1000
> +++ linux-work/arch/powerpc/mm/44x_mmu.c 2007-10-30 15:30:50.000000000 +1100
> @@ -35,6 +35,7 @@
> */
> unsigned int tlb_44x_index; /* = 0 */
> unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS;
> +int icache_44x_need_flush;
>
> /*
> * "Pins" a 256MB TLB entry in AS0 for kernel lowmem
> Index: linux-work/include/asm-powerpc/pgtable-ppc32.h
> ===================================================================
> --- linux-work.orig/include/asm-powerpc/pgtable-ppc32.h 2007-09-28 11:42:10.000000000 +1000
> +++ linux-work/include/asm-powerpc/pgtable-ppc32.h 2007-10-30 15:30:50.000000000 +1100
> @@ -11,6 +11,11 @@
> extern unsigned long va_to_phys(unsigned long address);
> extern pte_t *va_to_pte(unsigned long address);
> extern unsigned long ioremap_bot, ioremap_base;
> +
> +#ifdef CONFIG_44x
> +extern int icache_44x_need_flush;
> +#endif
> +
> #endif /* __ASSEMBLY__ */
>
> /*
> @@ -562,6 +567,10 @@ static inline unsigned long pte_update(p
> : "=&r" (old), "=&r" (tmp), "=m" (*p)
> : "r" (p), "r" (clr), "r" (set), "m" (*p)
> : "cc" );
> +#ifdef CONFIG_44x
> + if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC))
> + icache_44x_need_flush = 1;
> +#endif
> return old;
> }
> #else
> @@ -582,6 +591,10 @@ static inline unsigned long long pte_upd
> : "=&r" (old), "=&r" (tmp), "=m" (*p)
> : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p)
> : "cc" );
> +#ifdef CONFIG_44x
> + if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC))
> + icache_44x_need_flush = 1;
> +#endif
> return old;
> }
> #endif
> Index: linux-work/arch/powerpc/kernel/misc_32.S
> ===================================================================
> --- linux-work.orig/arch/powerpc/kernel/misc_32.S 2007-10-30 15:15:03.000000000 +1100
> +++ linux-work/arch/powerpc/kernel/misc_32.S 2007-10-30 15:30:50.000000000 +1100
> @@ -543,12 +543,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_I
> addi r3,r3,L1_CACHE_BYTES
> bdnz 0b
> sync
> +#ifndef CONFIG_44x
> + /* We don't flush the icache on 44x. Those have a virtual icache
> + * and we don't have access to the virtual address here (it's
> + * not the page vaddr but where it's mapped in user space). The
> + * flushing of the icache on these is handled elsewhere, when
> + * a change in the address space occurs, before returning to
> + * user space
> + */
> mtctr r4
> 1: icbi 0,r6
> addi r6,r6,L1_CACHE_BYTES
> bdnz 1b
> sync
> isync
> +#endif /* CONFIG_44x */
> blr
>
> /*
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list