aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-10-31 01:42:19 -0400
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2007-11-01 08:15:30 -0400
commitb98ac05d5e460301fbea24cceed0f2a601c82e22 (patch)
tree2e556ad28a007d13339300fbbd4942d0ec9f023c /arch/powerpc
parente701d269aa28996f3502780951fe1b12d5d66b49 (diff)
[POWERPC] 4xx: Deal with 44x virtually tagged icache
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@kernel.crashing.org> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/entry_32.S23
-rw-r--r--arch/powerpc/kernel/misc_32.S9
-rw-r--r--arch/powerpc/mm/44x_mmu.c1
3 files changed, 33 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 21d889e63e87..a7572cf464bd 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -244,6 +244,13 @@ syscall_exit_cont:
244 andis. r10,r0,DBCR0_IC@h 244 andis. r10,r0,DBCR0_IC@h
245 bnel- load_dbcr0 245 bnel- load_dbcr0
246#endif 246#endif
247#ifdef CONFIG_44x
248 lis r4,icache_44x_need_flush@ha
249 lwz r5,icache_44x_need_flush@l(r4)
250 cmplwi cr0,r5,0
251 bne- 2f
2521:
253#endif /* CONFIG_44x */
247 stwcx. r0,0,r1 /* to clear the reservation */ 254 stwcx. r0,0,r1 /* to clear the reservation */
248 lwz r4,_LINK(r1) 255 lwz r4,_LINK(r1)
249 lwz r5,_CCR(r1) 256 lwz r5,_CCR(r1)
@@ -258,6 +265,12 @@ syscall_exit_cont:
258 mtspr SPRN_SRR1,r8 265 mtspr SPRN_SRR1,r8
259 SYNC 266 SYNC
260 RFI 267 RFI
268#ifdef CONFIG_44x
2692: li r7,0
270 iccci r0,r0
271 stw r7,icache_44x_need_flush@l(r4)
272 b 1b
273#endif /* CONFIG_44x */
261 274
26266: li r3,-ENOSYS 27566: li r3,-ENOSYS
263 b ret_from_syscall 276 b ret_from_syscall
@@ -683,6 +696,16 @@ resume_kernel:
683 696
684 /* interrupts are hard-disabled at this point */ 697 /* interrupts are hard-disabled at this point */
685restore: 698restore:
699#ifdef CONFIG_44x
700 lis r4,icache_44x_need_flush@ha
701 lwz r5,icache_44x_need_flush@l(r4)
702 cmplwi cr0,r5,0
703 beq+ 1f
704 li r6,0
705 iccci r0,r0
706 stw r6,icache_44x_need_flush@l(r4)
7071:
708#endif /* CONFIG_44x */
686 lwz r0,GPR0(r1) 709 lwz r0,GPR0(r1)
687 lwz r2,GPR2(r1) 710 lwz r2,GPR2(r1)
688 REST_4GPRS(3, r1) 711 REST_4GPRS(3, r1)
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 0ed2c7eddc9e..8b642ab26d37 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -543,12 +543,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
543 addi r3,r3,L1_CACHE_BYTES 543 addi r3,r3,L1_CACHE_BYTES
544 bdnz 0b 544 bdnz 0b
545 sync 545 sync
546#ifndef CONFIG_44x
547 /* We don't flush the icache on 44x. Those have a virtual icache
548 * and we don't have access to the virtual address here (it's
549 * not the page vaddr but where it's mapped in user space). The
550 * flushing of the icache on these is handled elsewhere, when
551 * a change in the address space occurs, before returning to
552 * user space
553 */
546 mtctr r4 554 mtctr r4
5471: icbi 0,r6 5551: icbi 0,r6
548 addi r6,r6,L1_CACHE_BYTES 556 addi r6,r6,L1_CACHE_BYTES
549 bdnz 1b 557 bdnz 1b
550 sync 558 sync
551 isync 559 isync
560#endif /* CONFIG_44x */
552 blr 561 blr
553 562
554/* 563/*
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index c3df50476539..04dc08798d3d 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -35,6 +35,7 @@
35 */ 35 */
36unsigned int tlb_44x_index; /* = 0 */ 36unsigned int tlb_44x_index; /* = 0 */
37unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS; 37unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS;
38int icache_44x_need_flush;
38 39
39/* 40/*
40 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem 41 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem