diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv_rm_xics.c')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rm_xics.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index 3ee38e6e884f..7b066f6b02ad 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c | |||
@@ -183,8 +183,10 @@ static void icp_rm_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp, | |||
183 | * state update in HW (ie bus transactions) so we can handle them | 183 | * state update in HW (ie bus transactions) so we can handle them |
184 | * separately here as well. | 184 | * separately here as well. |
185 | */ | 185 | */ |
186 | if (resend) | 186 | if (resend) { |
187 | icp->rm_action |= XICS_RM_CHECK_RESEND; | 187 | icp->rm_action |= XICS_RM_CHECK_RESEND; |
188 | icp->rm_resend_icp = icp; | ||
189 | } | ||
188 | } | 190 | } |
189 | 191 | ||
190 | 192 | ||
@@ -254,10 +256,25 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, | |||
254 | * nothing needs to be done as there can be no XISR to | 256 | * nothing needs to be done as there can be no XISR to |
255 | * reject. | 257 | * reject. |
256 | * | 258 | * |
259 | * ICP state: Check_IPI | ||
260 | * | ||
257 | * If the CPPR is less favored, then we might be replacing | 261 | * If the CPPR is less favored, then we might be replacing |
258 | * an interrupt, and thus need to possibly reject it as in | 262 | * an interrupt, and thus need to possibly reject it. |
259 | * | 263 | * |
260 | * ICP state: Check_IPI | 264 | * ICP State: IPI |
265 | * | ||
266 | * Besides rejecting any pending interrupts, we also | ||
267 | * update XISR and pending_pri to mark IPI as pending. | ||
268 | * | ||
269 | * PAPR does not describe this state, but if the MFRR is being | ||
270 | * made less favored than its earlier value, there might be | ||
271 | * a previously-rejected interrupt needing to be resent. | ||
272 | * Ideally, we would want to resend only if | ||
273 | * prio(pending_interrupt) < mfrr && | ||
274 | * prio(pending_interrupt) < cppr | ||
275 | * where pending interrupt is the one that was rejected. But | ||
276 | * we don't have that state, so we simply trigger a resend | ||
277 | * whenever the MFRR is made less favored. | ||
261 | */ | 278 | */ |
262 | do { | 279 | do { |
263 | old_state = new_state = ACCESS_ONCE(icp->state); | 280 | old_state = new_state = ACCESS_ONCE(icp->state); |
@@ -270,13 +287,14 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, | |||
270 | resend = false; | 287 | resend = false; |
271 | if (mfrr < new_state.cppr) { | 288 | if (mfrr < new_state.cppr) { |
272 | /* Reject a pending interrupt if not an IPI */ | 289 | /* Reject a pending interrupt if not an IPI */ |
273 | if (mfrr <= new_state.pending_pri) | 290 | if (mfrr <= new_state.pending_pri) { |
274 | reject = new_state.xisr; | 291 | reject = new_state.xisr; |
275 | new_state.pending_pri = mfrr; | 292 | new_state.pending_pri = mfrr; |
276 | new_state.xisr = XICS_IPI; | 293 | new_state.xisr = XICS_IPI; |
294 | } | ||
277 | } | 295 | } |
278 | 296 | ||
279 | if (mfrr > old_state.mfrr && mfrr > new_state.cppr) { | 297 | if (mfrr > old_state.mfrr) { |
280 | resend = new_state.need_resend; | 298 | resend = new_state.need_resend; |
281 | new_state.need_resend = 0; | 299 | new_state.need_resend = 0; |
282 | } | 300 | } |
@@ -289,8 +307,10 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, | |||
289 | } | 307 | } |
290 | 308 | ||
291 | /* Pass resends to virtual mode */ | 309 | /* Pass resends to virtual mode */ |
292 | if (resend) | 310 | if (resend) { |
293 | this_icp->rm_action |= XICS_RM_CHECK_RESEND; | 311 | this_icp->rm_action |= XICS_RM_CHECK_RESEND; |
312 | this_icp->rm_resend_icp = icp; | ||
313 | } | ||
294 | 314 | ||
295 | return check_too_hard(xics, this_icp); | 315 | return check_too_hard(xics, this_icp); |
296 | } | 316 | } |