At the moment there are two TLBs. The OpenRISC TLB followed
by the QEMU's own TLB.
At the end of the TLB miss handler a tlb_flush of QEMUs TLB
is executed which is exactly what we want to avoid.
As long as there is no context switch we don't have to flush the TLB.

There are two options:
1. If l.rfe is executed and the MMU is off we don't flush the buffer.
This would work under Linux

2. We flush the TLB only if the correct DTLB and ITLB registers are
cleared. Unfortunately the OpenRISC TLB is smaller and there is no
register which commands to flush the whole buffer.
In this case we have to reckognize when the whole TLB is flushed.
This would have the benefit that syscalls which do not change
the context would not flush the TLB.

Both solutions would break weakly the specification but the speed benefit
is more than a factor of two for memory intense programs.
In this patch, I choose solution no. 2.
If the first TLB register is cleared the whole TLB is cleared.

Signed-off-by: Sebastian Macke <sebast...@macke.de>
---
 target-openrisc/cpu.h              | 2 +-
 target-openrisc/interrupt_helper.c | 8 --------
 target-openrisc/sys_helper.c       | 4 ++++
 3 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 057821d..bac61e5 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -412,7 +412,7 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState 
*env,
     *pc = env->pc;
     *cs_base = 0;
     /* D_FLAG -- branch instruction exception */
-    *flags = (env->flags & D_FLAG) | (env->sr & SR_SM);
+    *flags = (env->flags & D_FLAG) | (env->sr & (SR_SM | SR_DME | SR_IME));
 }
 
 static inline int cpu_mmu_index(CPUOpenRISCState *env)
diff --git a/target-openrisc/interrupt_helper.c 
b/target-openrisc/interrupt_helper.c
index ae187f5..1ad3a78 100644
--- a/target-openrisc/interrupt_helper.c
+++ b/target-openrisc/interrupt_helper.c
@@ -25,10 +25,6 @@ void HELPER(rfe)(CPUOpenRISCState *env)
 {
     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
-#ifndef CONFIG_USER_ONLY
-    int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^
-                         (cpu->env.esr & (SR_SM | SR_IME | SR_DME));
-#endif
     cpu->env.pc = cpu->env.epcr;
     ENV_SET_SR(&(cpu->env), cpu->env.esr);
 
@@ -48,10 +44,6 @@ void HELPER(rfe)(CPUOpenRISCState *env)
         cpu->env.tlb->cpu_openrisc_map_address_code =
             &cpu_openrisc_get_phys_nommu;
     }
-
-    if (need_flush_tlb) {
-        tlb_flush(&cpu->env, 1);
-    }
 #endif
     cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
index 3eda0e1..b7c987d 100644
--- a/target-openrisc/sys_helper.c
+++ b/target-openrisc/sys_helper.c
@@ -77,6 +77,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
         idx = spr - TO_SPR(1, 512);
         if (!(rb & 1)) {
             tlb_flush_page(env, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK);
+            if (idx == 0) {
+                /* Assume that the whole tlb buffer must be flushed */
+                tlb_flush(&cpu->env, 1);
+            }
         }
         env->tlb->dtlb[0][idx].mr = rb;
         break;
-- 
1.8.4.1


Reply via email to