KVM: PPC: Book3s: PR: Add SPAPR H_BULK_REMOVE support
SPAPR support includes various in-kernel hypercalls, improving performance by cutting out the exit to userspace. H_BULK_REMOVE is implemented in this patch. Signed-off-by: Matt Evans <matt@ozlabs.org> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
03660ba270
commit
3aaefef200
@ -98,6 +98,83 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
|
||||
/* Request defs for kvmppc_h_pr_bulk_remove() */
|
||||
#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL
|
||||
#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL
|
||||
#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL
|
||||
#define H_BULK_REMOVE_END 0xc000000000000000ULL
|
||||
#define H_BULK_REMOVE_CODE 0x3000000000000000ULL
|
||||
#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL
|
||||
#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL
|
||||
#define H_BULK_REMOVE_PARM 0x2000000000000000ULL
|
||||
#define H_BULK_REMOVE_HW 0x3000000000000000ULL
|
||||
#define H_BULK_REMOVE_RC 0x0c00000000000000ULL
|
||||
#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL
|
||||
#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL
|
||||
#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL
|
||||
#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL
|
||||
#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL
|
||||
#define H_BULK_REMOVE_MAX_BATCH 4
|
||||
|
||||
static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int i;
|
||||
int paramnr = 4;
|
||||
int ret = H_SUCCESS;
|
||||
|
||||
for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
|
||||
unsigned long tsh = kvmppc_get_gpr(vcpu, paramnr+(2*i));
|
||||
unsigned long tsl = kvmppc_get_gpr(vcpu, paramnr+(2*i)+1);
|
||||
unsigned long pteg, rb, flags;
|
||||
unsigned long pte[2];
|
||||
unsigned long v = 0;
|
||||
|
||||
if ((tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
|
||||
break; /* Exit success */
|
||||
} else if ((tsh & H_BULK_REMOVE_TYPE) !=
|
||||
H_BULK_REMOVE_REQUEST) {
|
||||
ret = H_PARAMETER;
|
||||
break; /* Exit fail */
|
||||
}
|
||||
|
||||
tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
|
||||
tsh |= H_BULK_REMOVE_RESPONSE;
|
||||
|
||||
if ((tsh & H_BULK_REMOVE_ANDCOND) &&
|
||||
(tsh & H_BULK_REMOVE_AVPN)) {
|
||||
tsh |= H_BULK_REMOVE_PARM;
|
||||
kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
|
||||
ret = H_PARAMETER;
|
||||
break; /* Exit fail */
|
||||
}
|
||||
|
||||
pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
|
||||
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
|
||||
|
||||
/* tsl = AVPN */
|
||||
flags = (tsh & H_BULK_REMOVE_FLAGS) >> 26;
|
||||
|
||||
if ((pte[0] & HPTE_V_VALID) == 0 ||
|
||||
((flags & H_AVPN) && (pte[0] & ~0x7fUL) != tsl) ||
|
||||
((flags & H_ANDCOND) && (pte[0] & tsl) != 0)) {
|
||||
tsh |= H_BULK_REMOVE_NOT_FOUND;
|
||||
} else {
|
||||
/* Splat the pteg in (userland) hpt */
|
||||
copy_to_user((void __user *)pteg, &v, sizeof(v));
|
||||
|
||||
rb = compute_tlbie_rb(pte[0], pte[1],
|
||||
tsh & H_BULK_REMOVE_PTEX);
|
||||
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
|
||||
tsh |= H_BULK_REMOVE_SUCCESS;
|
||||
tsh |= (pte[1] & (HPTE_R_C | HPTE_R_R)) << 43;
|
||||
}
|
||||
kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
|
||||
}
|
||||
kvmppc_set_gpr(vcpu, 3, ret);
|
||||
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
|
||||
static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long flags = kvmppc_get_gpr(vcpu, 4);
|
||||
@ -144,10 +221,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
|
||||
case H_PROTECT:
|
||||
return kvmppc_h_pr_protect(vcpu);
|
||||
case H_BULK_REMOVE:
|
||||
/* We just flush all PTEs, so user space can
|
||||
handle the HPT modifications */
|
||||
kvmppc_mmu_pte_flush(vcpu, 0, 0);
|
||||
break;
|
||||
return kvmppc_h_pr_bulk_remove(vcpu);
|
||||
case H_CEDE:
|
||||
kvm_vcpu_block(vcpu);
|
||||
vcpu->stat.halt_wakeup++;
|
||||
|
Loading…
Reference in New Issue
Block a user