diff options
author | Matt Evans <matt@ozlabs.org> | 2012-01-30 15:25:31 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-04-08 05:55:31 -0400 |
commit | 3aaefef200f618dc455cdf18053a7aeb262b5a11 (patch) | |
tree | 600a14e49230fbb8182325481b6a599864628484 /arch/powerpc | |
parent | 03660ba27020250eae0b5a2722e0c7bec4968c3c (diff) |
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>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kvm/book3s_pr_papr.c | 82 |
1 files changed, 78 insertions, 4 deletions
diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c index b9589324797b..6d1bfe246f0a 100644 --- a/arch/powerpc/kvm/book3s_pr_papr.c +++ b/arch/powerpc/kvm/book3s_pr_papr.c | |||
@@ -98,6 +98,83 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) | |||
98 | return EMULATE_DONE; | 98 | return EMULATE_DONE; |
99 | } | 99 | } |
100 | 100 | ||
101 | /* Request defs for kvmppc_h_pr_bulk_remove() */ | ||
102 | #define H_BULK_REMOVE_TYPE 0xc000000000000000ULL | ||
103 | #define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL | ||
104 | #define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL | ||
105 | #define H_BULK_REMOVE_END 0xc000000000000000ULL | ||
106 | #define H_BULK_REMOVE_CODE 0x3000000000000000ULL | ||
107 | #define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL | ||
108 | #define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL | ||
109 | #define H_BULK_REMOVE_PARM 0x2000000000000000ULL | ||
110 | #define H_BULK_REMOVE_HW 0x3000000000000000ULL | ||
111 | #define H_BULK_REMOVE_RC 0x0c00000000000000ULL | ||
112 | #define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL | ||
113 | #define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL | ||
114 | #define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL | ||
115 | #define H_BULK_REMOVE_AVPN 0x0200000000000000ULL | ||
116 | #define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL | ||
117 | #define H_BULK_REMOVE_MAX_BATCH 4 | ||
118 | |||
119 | static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) | ||
120 | { | ||
121 | int i; | ||
122 | int paramnr = 4; | ||
123 | int ret = H_SUCCESS; | ||
124 | |||
125 | for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { | ||
126 | unsigned long tsh = kvmppc_get_gpr(vcpu, paramnr+(2*i)); | ||
127 | unsigned long tsl = kvmppc_get_gpr(vcpu, paramnr+(2*i)+1); | ||
128 | unsigned long pteg, rb, flags; | ||
129 | unsigned long pte[2]; | ||
130 | unsigned long v = 0; | ||
131 | |||
132 | if ((tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { | ||
133 | break; /* Exit success */ | ||
134 | } else if ((tsh & H_BULK_REMOVE_TYPE) != | ||
135 | H_BULK_REMOVE_REQUEST) { | ||
136 | ret = H_PARAMETER; | ||
137 | break; /* Exit fail */ | ||
138 | } | ||
139 | |||
140 | tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; | ||
141 | tsh |= H_BULK_REMOVE_RESPONSE; | ||
142 | |||
143 | if ((tsh & H_BULK_REMOVE_ANDCOND) && | ||
144 | (tsh & H_BULK_REMOVE_AVPN)) { | ||
145 | tsh |= H_BULK_REMOVE_PARM; | ||
146 | kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh); | ||
147 | ret = H_PARAMETER; | ||
148 | break; /* Exit fail */ | ||
149 | } | ||
150 | |||
151 | pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX); | ||
152 | copy_from_user(pte, (void __user *)pteg, sizeof(pte)); | ||
153 | |||
154 | /* tsl = AVPN */ | ||
155 | flags = (tsh & H_BULK_REMOVE_FLAGS) >> 26; | ||
156 | |||
157 | if ((pte[0] & HPTE_V_VALID) == 0 || | ||
158 | ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != tsl) || | ||
159 | ((flags & H_ANDCOND) && (pte[0] & tsl) != 0)) { | ||
160 | tsh |= H_BULK_REMOVE_NOT_FOUND; | ||
161 | } else { | ||
162 | /* Splat the pteg in (userland) hpt */ | ||
163 | copy_to_user((void __user *)pteg, &v, sizeof(v)); | ||
164 | |||
165 | rb = compute_tlbie_rb(pte[0], pte[1], | ||
166 | tsh & H_BULK_REMOVE_PTEX); | ||
167 | vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); | ||
168 | tsh |= H_BULK_REMOVE_SUCCESS; | ||
169 | tsh |= (pte[1] & (HPTE_R_C | HPTE_R_R)) << 43; | ||
170 | } | ||
171 | kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh); | ||
172 | } | ||
173 | kvmppc_set_gpr(vcpu, 3, ret); | ||
174 | |||
175 | return EMULATE_DONE; | ||
176 | } | ||
177 | |||
101 | static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) | 178 | static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) |
102 | { | 179 | { |
103 | unsigned long flags = kvmppc_get_gpr(vcpu, 4); | 180 | unsigned long flags = kvmppc_get_gpr(vcpu, 4); |
@@ -144,10 +221,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) | |||
144 | case H_PROTECT: | 221 | case H_PROTECT: |
145 | return kvmppc_h_pr_protect(vcpu); | 222 | return kvmppc_h_pr_protect(vcpu); |
146 | case H_BULK_REMOVE: | 223 | case H_BULK_REMOVE: |
147 | /* We just flush all PTEs, so user space can | 224 | return kvmppc_h_pr_bulk_remove(vcpu); |
148 | handle the HPT modifications */ | ||
149 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
150 | break; | ||
151 | case H_CEDE: | 225 | case H_CEDE: |
152 | kvm_vcpu_block(vcpu); | 226 | kvm_vcpu_block(vcpu); |
153 | vcpu->stat.halt_wakeup++; | 227 | vcpu->stat.halt_wakeup++; |