Commit d1de1576 authored by Marc Zyngier's avatar Marc Zyngier Committed by Oliver Upton

KVM: arm64: nv: Handle FEAT_TTL hinted TLB operations

Support guest-provided information information to size the range of
required invalidation. This helps with reducing over-invalidation,
provided that the guest actually provides accurate information.
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240614144552.2773592-12-maz@kernel.orgSigned-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 70109bcd
......@@ -124,6 +124,8 @@ extern void kvm_nested_s2_wp(struct kvm *kvm);
extern void kvm_nested_s2_unmap(struct kvm *kvm);
extern void kvm_nested_s2_flush(struct kvm *kvm);
unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val);
static inline bool kvm_supported_tlbi_s1e1_op(struct kvm_vcpu *vpcu, u32 instr)
{
struct kvm *kvm = vpcu->kvm;
......
......@@ -364,6 +364,95 @@ int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
return ret;
}
static unsigned int ttl_to_size(u8 ttl)
{
int level = ttl & 3;
int gran = (ttl >> 2) & 3;
unsigned int max_size = 0;
switch (gran) {
case TLBI_TTL_TG_4K:
switch (level) {
case 0:
break;
case 1:
max_size = SZ_1G;
break;
case 2:
max_size = SZ_2M;
break;
case 3:
max_size = SZ_4K;
break;
}
break;
case TLBI_TTL_TG_16K:
switch (level) {
case 0:
case 1:
break;
case 2:
max_size = SZ_32M;
break;
case 3:
max_size = SZ_16K;
break;
}
break;
case TLBI_TTL_TG_64K:
switch (level) {
case 0:
case 1:
/* No 52bit IPA support */
break;
case 2:
max_size = SZ_512M;
break;
case 3:
max_size = SZ_64K;
break;
}
break;
default: /* No size information */
break;
}
return max_size;
}
unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val)
{
unsigned long max_size;
u8 ttl;
ttl = FIELD_GET(GENMASK_ULL(47, 44), val);
max_size = ttl_to_size(ttl);
if (!max_size) {
/* Compute the maximum extent of the invalidation */
switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) {
case VTCR_EL2_TG0_4K:
max_size = SZ_1G;
break;
case VTCR_EL2_TG0_16K:
max_size = SZ_32M;
break;
case VTCR_EL2_TG0_64K:
default: /* IMPDEF: treat any other value as 64k */
/*
* No, we do not support 52bit IPA in nested yet. Once
* we do, this should be 4TB.
*/
max_size = SZ_512M;
break;
}
}
WARN_ON(!max_size);
return max_size;
}
/*
* We can have multiple *different* MMU contexts with the same VMID:
*
......
......@@ -2865,34 +2865,12 @@ static void s2_mmu_unmap_ipa(struct kvm_s2_mmu *mmu,
*
* - NS bit: we're non-secure only.
*
* - TTL field: We already have the granule size from the
* VTCR_EL2.TG0 field, and the level is only relevant to the
* guest's S2PT.
*
* - IPA[51:48]: We don't support 52bit IPA just yet...
*
* And of course, adjust the IPA to be on an actual address.
*/
base_addr = (info->ipa.addr & GENMASK_ULL(35, 0)) << 12;
/* Compute the maximum extent of the invalidation */
switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) {
case VTCR_EL2_TG0_4K:
max_size = SZ_1G;
break;
case VTCR_EL2_TG0_16K:
max_size = SZ_32M;
break;
case VTCR_EL2_TG0_64K:
default: /* IMPDEF: treat any other value as 64k */
/*
* No, we do not support 52bit IPA in nested yet. Once
* we do, this should be 4TB.
*/
max_size = SZ_512M;
break;
}
max_size = compute_tlb_inval_range(mmu, info->ipa.addr);
base_addr &= ~(max_size - 1);
kvm_stage2_unmap_range(mmu, base_addr, max_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment