mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
KVM: PPC: Add book3s_32 tlbie flush acceleration
On Book3s_32 the tlbie instruction flushed effective addresses by the mask 0x0ffff000. This is pretty hard to reflect with a hash that hashes ~0xfff, so to speed up that target we should also keep a special hash around for it. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
49451389ec
commit
2d27fc5eac
2 changed files with 39 additions and 5 deletions
|
@ -42,9 +42,11 @@
|
|||
|
||||
#define HPTEG_CACHE_NUM (1 << 15)
|
||||
#define HPTEG_HASH_BITS_PTE 13
|
||||
#define HPTEG_HASH_BITS_PTE_LONG 12
|
||||
#define HPTEG_HASH_BITS_VPTE 13
|
||||
#define HPTEG_HASH_BITS_VPTE_LONG 5
|
||||
#define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE)
|
||||
#define HPTEG_HASH_NUM_PTE_LONG (1 << HPTEG_HASH_BITS_PTE_LONG)
|
||||
#define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE)
|
||||
#define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG)
|
||||
|
||||
|
@ -163,6 +165,7 @@ struct kvmppc_mmu {
|
|||
|
||||
struct hpte_cache {
|
||||
struct hlist_node list_pte;
|
||||
struct hlist_node list_pte_long;
|
||||
struct hlist_node list_vpte;
|
||||
struct hlist_node list_vpte_long;
|
||||
struct rcu_head rcu_head;
|
||||
|
@ -293,6 +296,7 @@ struct kvm_vcpu_arch {
|
|||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
|
||||
struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
|
||||
struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
|
||||
struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
|
||||
int hpte_cache_count;
|
||||
|
|
|
@ -45,6 +45,12 @@ static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
|
|||
return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
|
||||
}
|
||||
|
||||
static inline u64 kvmppc_mmu_hash_pte_long(u64 eaddr)
|
||||
{
|
||||
return hash_64((eaddr & 0x0ffff000) >> PTE_SIZE,
|
||||
HPTEG_HASH_BITS_PTE_LONG);
|
||||
}
|
||||
|
||||
static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
|
||||
{
|
||||
return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
|
||||
|
@ -66,6 +72,11 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
|||
index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
|
||||
hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
|
||||
|
||||
/* Add to ePTE_long list */
|
||||
index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
|
||||
hlist_add_head_rcu(&pte->list_pte_long,
|
||||
&vcpu->arch.hpte_hash_pte_long[index]);
|
||||
|
||||
/* Add to vPTE list */
|
||||
index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
|
||||
hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
|
||||
|
@ -99,6 +110,7 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
|||
spin_lock(&vcpu->arch.mmu_lock);
|
||||
|
||||
hlist_del_init_rcu(&pte->list_pte);
|
||||
hlist_del_init_rcu(&pte->list_pte_long);
|
||||
hlist_del_init_rcu(&pte->list_vpte);
|
||||
hlist_del_init_rcu(&pte->list_vpte_long);
|
||||
|
||||
|
@ -150,10 +162,28 @@ static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea)
|
||||
{
|
||||
struct hlist_head *list;
|
||||
struct hlist_node *node;
|
||||
struct hpte_cache *pte;
|
||||
|
||||
/* Find the list of entries in the map */
|
||||
list = &vcpu->arch.hpte_hash_pte_long[
|
||||
kvmppc_mmu_hash_pte_long(guest_ea)];
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Check the list for matching entries and invalidate */
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_pte_long)
|
||||
if ((pte->pte.eaddr & 0x0ffff000UL) == guest_ea)
|
||||
invalidate_pte(vcpu, pte);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
|
||||
{
|
||||
u64 i;
|
||||
|
||||
dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
|
||||
vcpu->arch.hpte_cache_count, guest_ea, ea_mask);
|
||||
|
||||
|
@ -164,9 +194,7 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
|
|||
kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
|
||||
break;
|
||||
case 0x0ffff000:
|
||||
/* 32-bit flush w/o segment, go through all possible segments */
|
||||
for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
|
||||
kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
|
||||
kvmppc_mmu_pte_flush_long(vcpu, guest_ea);
|
||||
break;
|
||||
case 0:
|
||||
/* Doing a complete flush -> start from scratch */
|
||||
|
@ -292,6 +320,8 @@ int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
|
|||
/* init hpte lookup hashes */
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long));
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
|
||||
|
|
Loading…
Reference in a new issue