On Wed, 2016-01-27 at 21:13 +1100, David Gibson wrote:
> When HPTEs are removed or modified by hypercalls on spapr, we need to
> invalidate the relevant pages in the qemu TLB.
> 
> Currently we do that by doing some complicated calculations to work out the
> right encoding for the tlbie instruction, then passing that to
> ppc_tlb_invalidate_one()... which totally ignores the argument and flushes
> the whole tlb.
> 
> Avoid that by adding a new flush-by-hpte helper in mmu-hash64.c.

Should we find a better "in between" so long run we implement tlbie
properly ? IE, tlbie will give us the page size using the same encoding
as the HPTE iirc when L=1 ? To be honest the encoding of tlbie in arch
2.07 is so completely insane I have a hard time figuring it out myself
... :-)

Otherwise,

Acked-by: Benjamin Herrenschmidt <b...@kernel.crashing.org>

> Signed-off-by: David Gibson <da...@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c    | 46 ++++-----------------------------------
> -------
>  target-ppc/mmu-hash64.c | 12 ++++++++++++
>  target-ppc/mmu-hash64.h |  3 +++
>  3 files changed, 19 insertions(+), 42 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 4707196..dedc7e0 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -37,42 +37,6 @@ static void set_spr(CPUState *cs, int spr,
> target_ulong value,
>      run_on_cpu(cs, do_spr_sync, &s);
>  }
>  
> -static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
> -                                     target_ulong pte_index)
> -{
> -    target_ulong rb, va_low;
> -
> -    rb = (v & ~0x7fULL) << 16; /* AVA field */
> -    va_low = pte_index >> 3;
> -    if (v & HPTE64_V_SECONDARY) {
> -        va_low = ~va_low;
> -    }
> -    /* xor vsid from AVA */
> -    if (!(v & HPTE64_V_1TB_SEG)) {
> -        va_low ^= v >> 12;
> -    } else {
> -        va_low ^= v >> 24;
> -    }
> -    va_low &= 0x7ff;
> -    if (v & HPTE64_V_LARGE) {
> -        rb |= 1;                         /* L field */
> -#if 0 /* Disable that P7 specific bit for now */
> -        if (r & 0xff000) {
> -            /* non-16MB large page, must be 64k */
> -            /* (masks depend on page size) */
> -            rb |= 0x1000;                /* page encoding in LP
> field */
> -            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field
> */
> -            rb |= (va_low & 0xfe);       /* AVAL field */
> -        }
> -#endif
> -    } else {
> -        /* 4kB page */
> -        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
> -    }
> -    rb |= (v >> 54) & 0x300;            /* B field */
> -    return rb;
> -}
> -
>  static inline bool valid_pte_index(CPUPPCState *env, target_ulong
> pte_index)
>  {
>      /*
> @@ -198,7 +162,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu,
> target_ulong ptex,
>  {
>      CPUPPCState *env = &cpu->env;
>      uint64_t token;
> -    target_ulong v, r, rb;
> +    target_ulong v, r;
>  
>      if (!valid_pte_index(env, ptex)) {
>          return REMOVE_PARM;
> @@ -217,8 +181,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu,
> target_ulong ptex,
>      *vp = v;
>      *rp = r;
>      ppc_hash64_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
> -    rb = compute_tlbie_rb(v, r, ptex);
> -    ppc_tlb_invalidate_one(env, rb);
> +    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
>      return REMOVE_SUCCESS;
>  }
>  
> @@ -322,7 +285,7 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>      target_ulong pte_index = args[1];
>      target_ulong avpn = args[2];
>      uint64_t token;
> -    target_ulong v, r, rb;
> +    target_ulong v, r;
>  
>      if (!valid_pte_index(env, pte_index)) {
>          return H_PARAMETER;
> @@ -343,10 +306,9 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>      r |= (flags << 55) & HPTE64_R_PP0;
>      r |= (flags << 48) & HPTE64_R_KEY_HI;
>      r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
> -    rb = compute_tlbie_rb(v, r, pte_index);
>      ppc_hash64_store_hpte(cpu, pte_index,
>                            (v & ~HPTE64_V_VALID) |
> HPTE64_V_HPTE_DIRTY, 0);
> -    ppc_tlb_invalidate_one(env, rb);
> +    ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r);
>      /* Don't need a memory barrier, due to qemu's global lock */
>      ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY,
> r);
>      return H_SUCCESS;
> diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> index ee1e8bf..3284776 100644
> --- a/target-ppc/mmu-hash64.c
> +++ b/target-ppc/mmu-hash64.c
> @@ -707,3 +707,15 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu,
>                   env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2,
> pte1);
>      }
>  }
> +
> +void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> +                               target_ulong pte_index,
> +                               target_ulong pte0, target_ulong pte1)
> +{
> +    /*
> +     * XXX: given the fact that there are too many segments to
> +     * invalidate, and we still don't have a tlb_flush_mask(env, n,
> +     * mask) in QEMU, we just invalidate all TLBs
> +     */
> +    tlb_flush(CPU(cpu), 1);
> +}
> diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
> index 24fd2c4..293a951 100644
> --- a/target-ppc/mmu-hash64.h
> +++ b/target-ppc/mmu-hash64.h
> @@ -13,6 +13,9 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
> target_ulong address, int rw,
>                                  int mmu_idx);
>  void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
>                             target_ulong pte0, target_ulong pte1);
> +void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> +                               target_ulong pte_index,
> +                               target_ulong pte0, target_ulong
> pte1);
>  #endif
>  
>  /*

Reply via email to