KVM: PPC: e500: clear up confusion between host and guest entries
authorScott Wood <scottwood@freescale.com>
Thu, 18 Aug 2011 20:25:18 +0000 (15:25 -0500)
committerAvi Kivity <avi@redhat.com>
Mon, 5 Mar 2012 12:52:23 +0000 (14:52 +0200)
Split out the portions of tlbe_priv that should be associated with host
entries into tlbe_ref.  Base victim selection on the number of hardware
entries, not guest entries.

For TLB1, where one guest entry can be mapped by multiple host entries,
we use the host tlbe_ref for tracking page references.  For the guest
TLB0 entries, we still track it with gtlb_priv, to avoid having to
retranslate if the entry is evicted from the host TLB but not the
guest TLB.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/powerpc/include/asm/kvm_e500.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/kvm/e500_tlb.c
arch/powerpc/kvm/e500_tlb.h

index adbfca9dd100f4d2821b30d94ab8e2591da5e059..a5197d816ec786fbf7eb558099e1497e92d4ab52 100644 (file)
@@ -32,13 +32,21 @@ struct tlbe{
 #define E500_TLB_VALID 1
 #define E500_TLB_DIRTY 2
 
-struct tlbe_priv {
+struct tlbe_ref {
        pfn_t pfn;
        unsigned int flags; /* E500_TLB_* */
 };
 
+struct tlbe_priv {
+       struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */
+};
+
 struct vcpu_id_table;
 
+struct kvmppc_e500_tlb_params {
+       int entries, ways, sets;
+};
+
 struct kvmppc_vcpu_e500 {
        /* Unmodified copy of the guest's TLB. */
        struct tlbe *gtlb_arch[E500_TLB_NUM];
@@ -49,6 +57,20 @@ struct kvmppc_vcpu_e500 {
        unsigned int gtlb_size[E500_TLB_NUM];
        unsigned int gtlb_nv[E500_TLB_NUM];
 
+       /*
+        * information associated with each host TLB entry --
+        * TLB1 only for now.  If/when guest TLB1 entries can be
+        * mapped with host TLB0, this will be used for that too.
+        *
+        * We don't want to use this for guest TLB0 because then we'd
+        * have the overhead of doing the translation again even if
+        * the entry is still in the guest TLB (e.g. we swapped out
+        * and back, and our host TLB entries got evicted).
+        */
+       struct tlbe_ref *tlb_refs[E500_TLB_NUM];
+
+       unsigned int host_tlb1_nv;
+
        u32 host_pid[E500_PID_NUM];
        u32 pid[E500_PID_NUM];
        u32 svr;
index f5f89cafebd027c115570651d6bc19f038f29746..a0128232d9cc807a5ae954ab9e41e01d5c7b0cf8 100644 (file)
 #define TLBnCFG_MAXSIZE                0x000f0000      /* Maximum Page Size (v1.0) */
 #define TLBnCFG_MAXSIZE_SHIFT  16
 #define TLBnCFG_ASSOC          0xff000000      /* Associativity */
+#define TLBnCFG_ASSOC_SHIFT    24
 
 /* TLBnPS encoding */
 #define TLBnPS_4K              0x00000004
index b976d8025e58d2ea840178f32da5162b042b7cf6..59221bb1e00e71ac7e900373faec021171b968ec 100644 (file)
@@ -12,6 +12,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -26,7 +27,7 @@
 #include "trace.h"
 #include "timing.h"
 
-#define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1)
+#define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1)
 
 struct id {
        unsigned long val;
@@ -63,7 +64,7 @@ static DEFINE_PER_CPU(struct pcpu_id_table, pcpu_sids);
  * The valid range of shadow ID is [1..255] */
 static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid);
 
-static unsigned int tlb1_entry_num;
+static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM];
 
 /*
  * Allocate a free shadow id and setup a valid sid mapping in given entry.
@@ -237,7 +238,7 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
        }
 }
 
-static inline unsigned int tlb0_get_next_victim(
+static inline unsigned int gtlb0_get_next_victim(
                struct kvmppc_vcpu_e500 *vcpu_e500)
 {
        unsigned int victim;
@@ -252,7 +253,7 @@ static inline unsigned int tlb0_get_next_victim(
 static inline unsigned int tlb1_max_shadow_size(void)
 {
        /* reserve one entry for magic page */
-       return tlb1_entry_num - tlbcam_index - 1;
+       return host_tlb_params[1].entries - tlbcam_index - 1;
 }
 
 static inline int tlbe_is_writable(struct tlbe *tlbe)
@@ -302,13 +303,12 @@ static inline void __write_host_tlbe(struct tlbe *stlbe, uint32_t mas0)
        local_irq_restore(flags);
 }
 
+/* esel is index into set, not whole array */
 static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
                int tlbsel, int esel, struct tlbe *stlbe)
 {
        if (tlbsel == 0) {
-               __write_host_tlbe(stlbe,
-                                 MAS0_TLBSEL(0) |
-                                 MAS0_ESEL(esel & (KVM_E500_TLB0_WAY_NUM - 1)));
+               __write_host_tlbe(stlbe, MAS0_TLBSEL(0) | MAS0_ESEL(esel));
        } else {
                __write_host_tlbe(stlbe,
                                  MAS0_TLBSEL(1) |
@@ -355,8 +355,8 @@ void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu)
 {
 }
 
-static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
-                                        int tlbsel, int esel)
+static void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500,
+                               int tlbsel, int esel)
 {
        struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
        struct vcpu_id_table *idt = vcpu_e500->idt;
@@ -412,18 +412,53 @@ static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
        preempt_enable();
 }
 
+static int tlb0_set_base(gva_t addr, int sets, int ways)
+{
+       int set_base;
+
+       set_base = (addr >> PAGE_SHIFT) & (sets - 1);
+       set_base *= ways;
+
+       return set_base;
+}
+
+static int gtlb0_set_base(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t addr)
+{
+       int sets = KVM_E500_TLB0_SIZE / KVM_E500_TLB0_WAY_NUM;
+
+       return tlb0_set_base(addr, sets, KVM_E500_TLB0_WAY_NUM);
+}
+
+static int htlb0_set_base(gva_t addr)
+{
+       return tlb0_set_base(addr, host_tlb_params[0].sets,
+                            host_tlb_params[0].ways);
+}
+
+static unsigned int get_tlb_esel(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel)
+{
+       unsigned int esel = get_tlb_esel_bit(vcpu_e500);
+
+       if (tlbsel == 0) {
+               esel &= KVM_E500_TLB0_WAY_NUM_MASK;
+               esel += gtlb0_set_base(vcpu_e500, vcpu_e500->mas2);
+       } else {
+               esel &= vcpu_e500->gtlb_size[tlbsel] - 1;
+       }
+
+       return esel;
+}
+
 /* Search the guest TLB for a matching entry. */
 static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
                gva_t eaddr, int tlbsel, unsigned int pid, int as)
 {
        int size = vcpu_e500->gtlb_size[tlbsel];
-       int set_base;
+       unsigned int set_base;
        int i;
 
        if (tlbsel == 0) {
-               int mask = size / KVM_E500_TLB0_WAY_NUM - 1;
-               set_base = (eaddr >> PAGE_SHIFT) & mask;
-               set_base *= KVM_E500_TLB0_WAY_NUM;
+               set_base = gtlb0_set_base(vcpu_e500, eaddr);
                size = KVM_E500_TLB0_WAY_NUM;
        } else {
                set_base = 0;
@@ -455,29 +490,55 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
        return -1;
 }
 
-static inline void kvmppc_e500_priv_setup(struct tlbe_priv *priv,
-                                         struct tlbe *gtlbe,
-                                         pfn_t pfn)
+static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
+                                        struct tlbe *gtlbe,
+                                        pfn_t pfn)
 {
-       priv->pfn = pfn;
-       priv->flags = E500_TLB_VALID;
+       ref->pfn = pfn;
+       ref->flags = E500_TLB_VALID;
 
        if (tlbe_is_writable(gtlbe))
-               priv->flags |= E500_TLB_DIRTY;
+               ref->flags |= E500_TLB_DIRTY;
 }
 
-static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv)
+static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 {
-       if (priv->flags & E500_TLB_VALID) {
-               if (priv->flags & E500_TLB_DIRTY)
-                       kvm_release_pfn_dirty(priv->pfn);
+       if (ref->flags & E500_TLB_VALID) {
+               if (ref->flags & E500_TLB_DIRTY)
+                       kvm_release_pfn_dirty(ref->pfn);
                else
-                       kvm_release_pfn_clean(priv->pfn);
+                       kvm_release_pfn_clean(ref->pfn);
+
+               ref->flags = 0;
+       }
+}
+
+static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+       int tlbsel = 0;
+       int i;
 
-               priv->flags = 0;
+       for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) {
+               struct tlbe_ref *ref =
+                       &vcpu_e500->gtlb_priv[tlbsel][i].ref;
+               kvmppc_e500_ref_release(ref);
        }
 }
 
+static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+       int stlbsel = 1;
+       int i;
+
+       for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
+               struct tlbe_ref *ref =
+                       &vcpu_e500->tlb_refs[stlbsel][i];
+               kvmppc_e500_ref_release(ref);
+       }
+
+       clear_tlb_privs(vcpu_e500);
+}
+
 static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
                unsigned int eaddr, int as)
 {
@@ -487,7 +548,7 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
 
        /* since we only have two TLBs, only lower bit is used. */
        tlbsel = (vcpu_e500->mas4 >> 28) & 0x1;
-       victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
+       victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
        pidsel = (vcpu_e500->mas4 >> 16) & 0xf;
        tsized = (vcpu_e500->mas4 >> 7) & 0x1f;
 
@@ -508,10 +569,12 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
 /* TID must be supplied by the caller */
 static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
                                           struct tlbe *gtlbe, int tsize,
-                                          struct tlbe_priv *priv,
+                                          struct tlbe_ref *ref,
                                           u64 gvaddr, struct tlbe *stlbe)
 {
-       pfn_t pfn = priv->pfn;
+       pfn_t pfn = ref->pfn;
+
+       BUG_ON(!(ref->flags & E500_TLB_VALID));
 
        /* Force TS=1 IPROT=0 for all guest mappings. */
        stlbe->mas1 = MAS1_TSIZE(tsize) | MAS1_TS | MAS1_VALID;
@@ -524,16 +587,15 @@ static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
        stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN;
 }
 
-
+/* sesel is an index into the entire array, not just the set */
 static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-       u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel,
-       struct tlbe *stlbe)
+       u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int sesel,
+       struct tlbe *stlbe, struct tlbe_ref *ref)
 {
        struct kvm_memory_slot *slot;
        unsigned long pfn, hva;
        int pfnmap = 0;
        int tsize = BOOK3E_PAGESZ_4K;
-       struct tlbe_priv *priv;
 
        /*
         * Translate guest physical to true physical, acquiring
@@ -629,12 +691,11 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                }
        }
 
-       /* Drop old priv and setup new one. */
-       priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
-       kvmppc_e500_priv_release(priv);
-       kvmppc_e500_priv_setup(priv, gtlbe, pfn);
+       /* Drop old ref and setup new one. */
+       kvmppc_e500_ref_release(ref);
+       kvmppc_e500_ref_setup(ref, gtlbe, pfn);
 
-       kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, priv, gvaddr, stlbe);
+       kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, ref, gvaddr, stlbe);
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
@@ -642,14 +703,22 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                                int esel, struct tlbe *stlbe)
 {
        struct tlbe *gtlbe;
+       struct tlbe_ref *ref;
+       int sesel = esel & (host_tlb_params[0].ways - 1);
+       int sesel_base;
+       gva_t ea;
 
        gtlbe = &vcpu_e500->gtlb_arch[0][esel];
+       ref = &vcpu_e500->gtlb_priv[0][esel].ref;
+
+       ea = get_tlb_eaddr(gtlbe);
+       sesel_base = htlb0_set_base(ea);
 
        kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe),
                        get_tlb_raddr(gtlbe) >> PAGE_SHIFT,
-                       gtlbe, 0, esel, stlbe);
+                       gtlbe, 0, sesel_base + sesel, stlbe, ref);
 
-       return esel;
+       return sesel;
 }
 
 /* Caller must ensure that the specified guest TLB entry is safe to insert into
@@ -658,14 +727,17 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe)
 {
+       struct tlbe_ref *ref;
        unsigned int victim;
 
-       victim = vcpu_e500->gtlb_nv[1]++;
+       victim = vcpu_e500->host_tlb1_nv++;
 
-       if (unlikely(vcpu_e500->gtlb_nv[1] >= tlb1_max_shadow_size()))
-               vcpu_e500->gtlb_nv[1] = 0;
+       if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
+               vcpu_e500->host_tlb1_nv = 0;
 
-       kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim, stlbe);
+       ref = &vcpu_e500->tlb_refs[1][victim];
+       kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1,
+                              victim, stlbe, ref);
 
        return victim;
 }
@@ -792,7 +864,7 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
 
                /* since we only have two TLBs, only lower bit is used. */
                tlbsel = vcpu_e500->mas4 >> 28 & 0x1;
-               victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
+               victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
 
                vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
                        | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
@@ -839,7 +911,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
        gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
 
        if (get_tlb_v(gtlbe))
-               kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel);
+               inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
 
        gtlbe->mas1 = vcpu_e500->mas1;
        gtlbe->mas2 = vcpu_e500->mas2;
@@ -950,11 +1022,11 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
        switch (tlbsel) {
        case 0:
                stlbsel = 0;
-               sesel = esel;
-               priv = &vcpu_e500->gtlb_priv[stlbsel][sesel];
+               sesel = esel & (host_tlb_params[0].ways - 1);
+               priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
 
                kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K,
-                                       priv, eaddr, &stlbe);
+                                       &priv->ref, eaddr, &stlbe);
                break;
 
        case 1: {
@@ -1020,32 +1092,76 @@ void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500)
 
 int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-       tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF;
+       host_tlb_params[0].entries = mfspr(SPRN_TLB0CFG) & TLBnCFG_N_ENTRY;
+       host_tlb_params[1].entries = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+
+       /*
+        * This should never happen on real e500 hardware, but is
+        * architecturally possible -- e.g. in some weird nested
+        * virtualization case.
+        */
+       if (host_tlb_params[0].entries == 0 ||
+           host_tlb_params[1].entries == 0) {
+               pr_err("%s: need to know host tlb size\n", __func__);
+               return -ENODEV;
+       }
+
+       host_tlb_params[0].ways = (mfspr(SPRN_TLB0CFG) & TLBnCFG_ASSOC) >>
+                                 TLBnCFG_ASSOC_SHIFT;
+       host_tlb_params[1].ways = host_tlb_params[1].entries;
+
+       if (!is_power_of_2(host_tlb_params[0].entries) ||
+           !is_power_of_2(host_tlb_params[0].ways) ||
+           host_tlb_params[0].entries < host_tlb_params[0].ways ||
+           host_tlb_params[0].ways == 0) {
+               pr_err("%s: bad tlb0 host config: %u entries %u ways\n",
+                      __func__, host_tlb_params[0].entries,
+                      host_tlb_params[0].ways);
+               return -ENODEV;
+       }
+
+       host_tlb_params[0].sets =
+               host_tlb_params[0].entries / host_tlb_params[0].ways;
+       host_tlb_params[1].sets = 1;
 
        vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE;
        vcpu_e500->gtlb_arch[0] =
                kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL);
        if (vcpu_e500->gtlb_arch[0] == NULL)
-               goto err_out;
+               goto err;
 
        vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE;
        vcpu_e500->gtlb_arch[1] =
                kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL);
        if (vcpu_e500->gtlb_arch[1] == NULL)
-               goto err_out_guest0;
-
-       vcpu_e500->gtlb_priv[0] = (struct tlbe_priv *)
-               kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB0_SIZE, GFP_KERNEL);
-       if (vcpu_e500->gtlb_priv[0] == NULL)
-               goto err_out_guest1;
-       vcpu_e500->gtlb_priv[1] = (struct tlbe_priv *)
-               kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB1_SIZE, GFP_KERNEL);
-
-       if (vcpu_e500->gtlb_priv[1] == NULL)
-               goto err_out_priv0;
+               goto err;
+
+       vcpu_e500->tlb_refs[0] =
+               kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
+                       GFP_KERNEL);
+       if (!vcpu_e500->tlb_refs[0])
+               goto err;
+
+       vcpu_e500->tlb_refs[1] =
+               kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
+                       GFP_KERNEL);
+       if (!vcpu_e500->tlb_refs[1])
+               goto err;
+
+       vcpu_e500->gtlb_priv[0] =
+               kzalloc(sizeof(struct tlbe_ref) * vcpu_e500->gtlb_size[0],
+                       GFP_KERNEL);
+       if (!vcpu_e500->gtlb_priv[0])
+               goto err;
+
+       vcpu_e500->gtlb_priv[1] =
+               kzalloc(sizeof(struct tlbe_ref) * vcpu_e500->gtlb_size[1],
+                       GFP_KERNEL);
+       if (!vcpu_e500->gtlb_priv[1])
+               goto err;
 
        if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL)
-               goto err_out_priv1;
+               goto err;
 
        /* Init TLB configuration register */
        vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL;
@@ -1055,31 +1171,26 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
 
        return 0;
 
-err_out_priv1:
-       kfree(vcpu_e500->gtlb_priv[1]);
-err_out_priv0:
+err:
+       kfree(vcpu_e500->tlb_refs[0]);
+       kfree(vcpu_e500->tlb_refs[1]);
        kfree(vcpu_e500->gtlb_priv[0]);
-err_out_guest1:
-       kfree(vcpu_e500->gtlb_arch[1]);
-err_out_guest0:
+       kfree(vcpu_e500->gtlb_priv[1]);
        kfree(vcpu_e500->gtlb_arch[0]);
-err_out:
+       kfree(vcpu_e500->gtlb_arch[1]);
        return -1;
 }
 
 void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-       int stlbsel, i;
-
-       /* release all privs */
-       for (stlbsel = 0; stlbsel < 2; stlbsel++)
-               for (i = 0; i < vcpu_e500->gtlb_size[stlbsel]; i++) {
-                       struct tlbe_priv *priv =
-                               &vcpu_e500->gtlb_priv[stlbsel][i];
-                       kvmppc_e500_priv_release(priv);
-               }
+       clear_tlb_refs(vcpu_e500);
 
        kvmppc_e500_id_table_free(vcpu_e500);
+
+       kfree(vcpu_e500->tlb_refs[0]);
+       kfree(vcpu_e500->tlb_refs[1]);
+       kfree(vcpu_e500->gtlb_priv[0]);
+       kfree(vcpu_e500->gtlb_priv[1]);
        kfree(vcpu_e500->gtlb_arch[1]);
        kfree(vcpu_e500->gtlb_arch[0]);
 }
index 59b88e99a235612126a4781671edaccf6e1f0c14..b587f691459a22994824009862b42af5379edc70 100644 (file)
@@ -155,23 +155,6 @@ static inline unsigned int get_tlb_esel_bit(
        return (vcpu_e500->mas0 >> 16) & 0xfff;
 }
 
-static inline unsigned int get_tlb_esel(
-               const struct kvmppc_vcpu_e500 *vcpu_e500,
-               int tlbsel)
-{
-       unsigned int esel = get_tlb_esel_bit(vcpu_e500);
-
-       if (tlbsel == 0) {
-               esel &= KVM_E500_TLB0_WAY_NUM_MASK;
-               esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK)
-                               << KVM_E500_TLB0_WAY_NUM_BIT;
-       } else {
-               esel &= KVM_E500_TLB1_SIZE - 1;
-       }
-
-       return esel;
-}
-
 static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
                        const struct tlbe *tlbe)
 {