aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2018-05-09 23:06:42 -0400
committerPaul Mackerras <paulus@ozlabs.org>2018-05-17 01:17:06 -0400
commit9dc81d6b0f1e3c40bdf97671dd26a24f128e1182 (patch)
tree7582e7317a7947d1ea5eeddfd39538c30919877a
parent7e3d9a1d0f2c681456a2e04b8ba9a2fb448fe515 (diff)
KVM: PPC: Book3S HV: XIVE: Resend re-routed interrupts on CPU priority change
When a vcpu priority (CPPR) is set to a lower value (masking more interrupts), we stop processing interrupts already in the queue for the priorities that have now been masked. If those interrupts were previously re-routed to a different CPU, they might still be stuck until the older one that has them in its queue processes them. In the case of guest CPU unplug, that can be never. To address that without creating additional overhead for the normal interrupt processing path, this changes H_CPPR handling so that when such a priority change occurs, we scan the interrupt queue for that vCPU, and for any interrupt in there that has been re-routed, we replace it with a dummy and force a re-trigger. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Tested-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
-rw-r--r--arch/powerpc/kvm/book3s_xive_template.c108
1 files changed, 101 insertions, 7 deletions
diff --git a/arch/powerpc/kvm/book3s_xive_template.c b/arch/powerpc/kvm/book3s_xive_template.c
index c7a5deadd1cc..99c3620b40d9 100644
--- a/arch/powerpc/kvm/book3s_xive_template.c
+++ b/arch/powerpc/kvm/book3s_xive_template.c
@@ -11,6 +11,9 @@
11#define XGLUE(a,b) a##b 11#define XGLUE(a,b) a##b
12#define GLUE(a,b) XGLUE(a,b) 12#define GLUE(a,b) XGLUE(a,b)
13 13
14/* Dummy interrupt used when taking interrupts out of a queue in H_CPPR */
15#define XICS_DUMMY 1
16
14static void GLUE(X_PFX,ack_pending)(struct kvmppc_xive_vcpu *xc) 17static void GLUE(X_PFX,ack_pending)(struct kvmppc_xive_vcpu *xc)
15{ 18{
16 u8 cppr; 19 u8 cppr;
@@ -205,6 +208,10 @@ skip_ipi:
205 goto skip_ipi; 208 goto skip_ipi;
206 } 209 }
207 210
211 /* If it's the dummy interrupt, continue searching */
212 if (hirq == XICS_DUMMY)
213 goto skip_ipi;
214
208 /* If fetching, update queue pointers */ 215 /* If fetching, update queue pointers */
209 if (scan_type == scan_fetch) { 216 if (scan_type == scan_fetch) {
210 q->idx = idx; 217 q->idx = idx;
@@ -385,9 +392,76 @@ static void GLUE(X_PFX,push_pending_to_hw)(struct kvmppc_xive_vcpu *xc)
385 __x_writeb(prio, __x_tima + TM_SPC_SET_OS_PENDING); 392 __x_writeb(prio, __x_tima + TM_SPC_SET_OS_PENDING);
386} 393}
387 394
395static void GLUE(X_PFX,scan_for_rerouted_irqs)(struct kvmppc_xive *xive,
396 struct kvmppc_xive_vcpu *xc)
397{
398 unsigned int prio;
399
400 /* For each priority that is now masked */
401 for (prio = xc->cppr; prio < KVMPPC_XIVE_Q_COUNT; prio++) {
402 struct xive_q *q = &xc->queues[prio];
403 struct kvmppc_xive_irq_state *state;
404 struct kvmppc_xive_src_block *sb;
405 u32 idx, toggle, entry, irq, hw_num;
406 struct xive_irq_data *xd;
407 __be32 *qpage;
408 u16 src;
409
410 idx = q->idx;
411 toggle = q->toggle;
412 qpage = READ_ONCE(q->qpage);
413 if (!qpage)
414 continue;
415
416 /* For each interrupt in the queue */
417 for (;;) {
418 entry = be32_to_cpup(qpage + idx);
419
420 /* No more ? */
421 if ((entry >> 31) == toggle)
422 break;
423 irq = entry & 0x7fffffff;
424
425 /* Skip dummies and IPIs */
426 if (irq == XICS_DUMMY || irq == XICS_IPI)
427 goto next;
428 sb = kvmppc_xive_find_source(xive, irq, &src);
429 if (!sb)
430 goto next;
431 state = &sb->irq_state[src];
432
433 /* Has it been rerouted ? */
434 if (xc->server_num == state->act_server)
435 goto next;
436
437 /*
438 * Allright, it *has* been re-routed, kill it from
439 * the queue.
440 */
441 qpage[idx] = cpu_to_be32((entry & 0x80000000) | XICS_DUMMY);
442
443 /* Find the HW interrupt */
444 kvmppc_xive_select_irq(state, &hw_num, &xd);
445
446 /* If it's not an LSI, set PQ to 11 the EOI will force a resend */
447 if (!(xd->flags & XIVE_IRQ_FLAG_LSI))
448 GLUE(X_PFX,esb_load)(xd, XIVE_ESB_SET_PQ_11);
449
450 /* EOI the source */
451 GLUE(X_PFX,source_eoi)(hw_num, xd);
452
453 next:
454 idx = (idx + 1) & q->msk;
455 if (idx == 0)
456 toggle ^= 1;
457 }
458 }
459}
460
388X_STATIC int GLUE(X_PFX,h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr) 461X_STATIC int GLUE(X_PFX,h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr)
389{ 462{
390 struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; 463 struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
464 struct kvmppc_xive *xive = vcpu->kvm->arch.xive;
391 u8 old_cppr; 465 u8 old_cppr;
392 466
393 pr_devel("H_CPPR(cppr=%ld)\n", cppr); 467 pr_devel("H_CPPR(cppr=%ld)\n", cppr);
@@ -407,14 +481,34 @@ X_STATIC int GLUE(X_PFX,h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr)
407 */ 481 */
408 smp_mb(); 482 smp_mb();
409 483
410 /* 484 if (cppr > old_cppr) {
411 * We are masking less, we need to look for pending things 485 /*
412 * to deliver and set VP pending bits accordingly to trigger 486 * We are masking less, we need to look for pending things
413 * a new interrupt otherwise we might miss MFRR changes for 487 * to deliver and set VP pending bits accordingly to trigger
414 * which we have optimized out sending an IPI signal. 488 * a new interrupt otherwise we might miss MFRR changes for
415 */ 489 * which we have optimized out sending an IPI signal.
416 if (cppr > old_cppr) 490 */
417 GLUE(X_PFX,push_pending_to_hw)(xc); 491 GLUE(X_PFX,push_pending_to_hw)(xc);
492 } else {
493 /*
494 * We are masking more, we need to check the queue for any
495 * interrupt that has been routed to another CPU, take
496 * it out (replace it with the dummy) and retrigger it.
497 *
498 * This is necessary since those interrupts may otherwise
499 * never be processed, at least not until this CPU restores
500 * its CPPR.
501 *
502 * This is in theory racy vs. HW adding new interrupts to
503 * the queue. In practice this works because the interesting
504 * cases are when the guest has done a set_xive() to move the
505 * interrupt away, which flushes the xive, followed by the
506 * target CPU doing a H_CPPR. So any new interrupt coming into
507 * the queue must still be routed to us and isn't a source
508 * of concern.
509 */
510 GLUE(X_PFX,scan_for_rerouted_irqs)(xive, xc);
511 }
418 512
419 /* Apply new CPPR */ 513 /* Apply new CPPR */
420 xc->hw_cppr = cppr; 514 xc->hw_cppr = cppr;