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

Commit 9728a7c8 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Michael Ellerman
Browse files

powerpc/icp-opal: Fix missing KVM case and harden replay



The icp-opal call is missing the code from icp-native to recover
interrupts snatched by KVM. Without that, when running KVM, we can
get into a situation where an interrupt is lost and the CPU stuck
with an elevated CPPR.

Also harden replay by always checking the return from opal_int_eoi().

Fixes: d7436188 ("powerpc/xics: Add ICP OPAL backend")
Cc: stable@vger.kernel.org # v4.8+
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 32b53c01
Loading
Loading
Loading
Loading
+24 −7
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <asm/xics.h>
#include <asm/io.h>
#include <asm/opal.h>
#include <asm/kvm_ppc.h>

static void icp_opal_teardown_cpu(void)
{
@@ -39,7 +40,26 @@ static void icp_opal_flush_ipi(void)
	 * Should we be flagging idle loop instead?
	 * Or creating some task to be scheduled?
	 */
	opal_int_eoi((0x00 << 24) | XICS_IPI);
	if (opal_int_eoi((0x00 << 24) | XICS_IPI) > 0)
		force_external_irq_replay();
}

static unsigned int icp_opal_get_xirr(void)
{
	unsigned int kvm_xirr;
	__be32 hw_xirr;
	int64_t rc;

	/* Handle an interrupt latched by KVM first */
	kvm_xirr = kvmppc_get_xics_latch();
	if (kvm_xirr)
		return kvm_xirr;

	/* Then ask OPAL */
	rc = opal_int_get_xirr(&hw_xirr, false);
	if (rc < 0)
		return 0;
	return be32_to_cpu(hw_xirr);
}

static unsigned int icp_opal_get_irq(void)
@@ -47,12 +67,8 @@ static unsigned int icp_opal_get_irq(void)
	unsigned int xirr;
	unsigned int vec;
	unsigned int irq;
	int64_t rc;

	rc = opal_int_get_xirr(&xirr, false);
	if (rc < 0)
		return 0;
	xirr = be32_to_cpu(xirr);
	xirr = icp_opal_get_xirr();
	vec = xirr & 0x00ffffff;
	if (vec == XICS_IRQ_SPURIOUS)
		return 0;
@@ -67,7 +83,8 @@ static unsigned int icp_opal_get_irq(void)
	xics_mask_unknown_vec(vec);

	/* We might learn about it later, so EOI it */
	opal_int_eoi(xirr);
	if (opal_int_eoi(xirr) > 0)
		force_external_irq_replay();

	return 0;
}