Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a47908e authored by Michael Ellerman's avatar Michael Ellerman
Browse files

Merge branch 'topic/ppc-kvm' into next

Merge our ppc-kvm topic branch. This contains several fixes for the XIVE
interrupt controller that we are sharing with the KVM tree.
parents 4215fa2d da15c03b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -46,7 +46,15 @@ struct xive_irq_data {

	/* Setup/used by frontend */
	int target;
	/*
	 * saved_p means that there is a queue entry for this interrupt
	 * in some CPU's queue (not including guest vcpu queues), even
	 * if P is not set in the source ESB.
	 * stale_p means that there is no queue entry for this interrupt
	 * in some CPU's queue, even if P is set in the source ESB.
	 */
	bool saved_p;
	bool stale_p;
};
#define XIVE_IRQ_FLAG_STORE_EOI	0x01
#define XIVE_IRQ_FLAG_LSI	0x02
+25 −13
Original line number Diff line number Diff line
@@ -942,6 +942,8 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
	ld	r11, VCPU_XIVE_SAVED_STATE(r4)
	li	r9, TM_QW1_OS
	lwz	r8, VCPU_XIVE_CAM_WORD(r4)
	cmpwi	r8, 0
	beq	no_xive
	li	r7, TM_QW1_OS + TM_WORD2
	mfmsr	r0
	andi.	r0, r0, MSR_DR		/* in real mode? */
@@ -2831,29 +2833,39 @@ kvm_cede_prodded:
kvm_cede_exit:
	ld	r9, HSTATE_KVM_VCPU(r13)
#ifdef CONFIG_KVM_XICS
	/* Abort if we still have a pending escalation */
	/* are we using XIVE with single escalation? */
	ld	r10, VCPU_XIVE_ESC_VADDR(r9)
	cmpdi	r10, 0
	beq	3f
	li	r6, XIVE_ESB_SET_PQ_00
	/*
	 * If we still have a pending escalation, abort the cede,
	 * and we must set PQ to 10 rather than 00 so that we don't
	 * potentially end up with two entries for the escalation
	 * interrupt in the XIVE interrupt queue.  In that case
	 * we also don't want to set xive_esc_on to 1 here in
	 * case we race with xive_esc_irq().
	 */
	lbz	r5, VCPU_XIVE_ESC_ON(r9)
	cmpwi	r5, 0
	beq	1f
	beq	4f
	li	r0, 0
	stb	r0, VCPU_CEDED(r9)
1:	/* Enable XIVE escalation */
	li	r5, XIVE_ESB_SET_PQ_00
	li	r6, XIVE_ESB_SET_PQ_10
	b	5f
4:	li	r0, 1
	stb	r0, VCPU_XIVE_ESC_ON(r9)
	/* make sure store to xive_esc_on is seen before xive_esc_irq runs */
	sync
5:	/* Enable XIVE escalation */
	mfmsr	r0
	andi.	r0, r0, MSR_DR		/* in real mode? */
	beq	1f
	ld	r10, VCPU_XIVE_ESC_VADDR(r9)
	cmpdi	r10, 0
	beq	3f
	ldx	r0, r10, r5
	ldx	r0, r10, r6
	b	2f
1:	ld	r10, VCPU_XIVE_ESC_RADDR(r9)
	cmpdi	r10, 0
	beq	3f
	ldcix	r0, r10, r5
	ldcix	r0, r10, r6
2:	sync
	li	r0, 1
	stb	r0, VCPU_XIVE_ESC_ON(r9)
#endif /* CONFIG_KVM_XICS */
3:	b	guest_exit_cont

+51 −9
Original line number Diff line number Diff line
@@ -67,8 +67,14 @@ void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu)
	void __iomem *tima = local_paca->kvm_hstate.xive_tima_virt;
	u64 pq;

	if (!tima)
	/*
	 * Nothing to do if the platform doesn't have a XIVE
	 * or this vCPU doesn't have its own XIVE context
	 * (e.g. because it's not using an in-kernel interrupt controller).
	 */
	if (!tima || !vcpu->arch.xive_cam_word)
		return;

	eieio();
	__raw_writeq(vcpu->arch.xive_saved_state.w01, tima + TM_QW1_OS);
	__raw_writel(vcpu->arch.xive_cam_word, tima + TM_QW1_OS + TM_WORD2);
@@ -160,6 +166,9 @@ static irqreturn_t xive_esc_irq(int irq, void *data)
	 */
	vcpu->arch.xive_esc_on = false;

	/* This orders xive_esc_on = false vs. subsequent stale_p = true */
	smp_wmb();	/* goes with smp_mb() in cleanup_single_escalation */

	return IRQ_HANDLED;
}

@@ -1113,6 +1122,31 @@ void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
	vcpu->arch.xive_esc_raddr = 0;
}

/*
 * In single escalation mode, the escalation interrupt is marked so
 * that EOI doesn't re-enable it, but just sets the stale_p flag to
 * indicate that the P bit has already been dealt with.  However, the
 * assembly code that enters the guest sets PQ to 00 without clearing
 * stale_p (because it has no easy way to address it).  Hence we have
 * to adjust stale_p before shutting down the interrupt.
 */
void xive_cleanup_single_escalation(struct kvm_vcpu *vcpu,
				    struct kvmppc_xive_vcpu *xc, int irq)
{
	struct irq_data *d = irq_get_irq_data(irq);
	struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);

	/*
	 * This slightly odd sequence gives the right result
	 * (i.e. stale_p set if xive_esc_on is false) even if
	 * we race with xive_esc_irq() and xive_irq_eoi().
	 */
	xd->stale_p = false;
	smp_mb();		/* paired with smb_wmb in xive_esc_irq */
	if (!vcpu->arch.xive_esc_on)
		xd->stale_p = true;
}

void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
{
	struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
@@ -1134,20 +1168,28 @@ void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
	/* Mask the VP IPI */
	xive_vm_esb_load(&xc->vp_ipi_data, XIVE_ESB_SET_PQ_01);

	/* Disable the VP */
	xive_native_disable_vp(xc->vp_id);

	/* Free the queues & associated interrupts */
	/* Free escalations */
	for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
		struct xive_q *q = &xc->queues[i];

		/* Free the escalation irq */
		if (xc->esc_virq[i]) {
			if (xc->xive->single_escalation)
				xive_cleanup_single_escalation(vcpu, xc,
							xc->esc_virq[i]);
			free_irq(xc->esc_virq[i], vcpu);
			irq_dispose_mapping(xc->esc_virq[i]);
			kfree(xc->esc_virq_names[i]);
		}
		/* Free the queue */
	}

	/* Disable the VP */
	xive_native_disable_vp(xc->vp_id);

	/* Clear the cam word so guest entry won't try to push context */
	vcpu->arch.xive_cam_word = 0;

	/* Free the queues */
	for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
		struct xive_q *q = &xc->queues[i];

		xive_native_disable_queue(xc->vp_id, q, i);
		if (q->qpage) {
			free_pages((unsigned long)q->qpage,
+2 −0
Original line number Diff line number Diff line
@@ -282,6 +282,8 @@ int kvmppc_xive_select_target(struct kvm *kvm, u32 *server, u8 prio);
int kvmppc_xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio,
				  bool single_escalation);
struct kvmppc_xive *kvmppc_xive_get_device(struct kvm *kvm, u32 type);
void xive_cleanup_single_escalation(struct kvm_vcpu *vcpu,
				    struct kvmppc_xive_vcpu *xc, int irq);

#endif /* CONFIG_KVM_XICS */
#endif /* _KVM_PPC_BOOK3S_XICS_H */
+13 −5
Original line number Diff line number Diff line
@@ -67,20 +67,28 @@ void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu)
	xc->valid = false;
	kvmppc_xive_disable_vcpu_interrupts(vcpu);

	/* Disable the VP */
	xive_native_disable_vp(xc->vp_id);

	/* Free the queues & associated interrupts */
	/* Free escalations */
	for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
		/* Free the escalation irq */
		if (xc->esc_virq[i]) {
			if (xc->xive->single_escalation)
				xive_cleanup_single_escalation(vcpu, xc,
							xc->esc_virq[i]);
			free_irq(xc->esc_virq[i], vcpu);
			irq_dispose_mapping(xc->esc_virq[i]);
			kfree(xc->esc_virq_names[i]);
			xc->esc_virq[i] = 0;
		}
	}

		/* Free the queue */
	/* Disable the VP */
	xive_native_disable_vp(xc->vp_id);

	/* Clear the cam word so guest entry won't try to push context */
	vcpu->arch.xive_cam_word = 0;

	/* Free the queues */
	for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
		kvmppc_xive_native_cleanup_queue(vcpu, i);
	}

Loading