[Skiboot] [PATCH 2/2] hw/phb3: Ensure PQ bits are cleared in the IVC when masking IRQ

Michael Neuling mikey at neuling.org
Thu Feb 11 15:25:33 AEDT 2016


When we mask an interrupt, we may race with another interrupt coming
in from the hardware.  If this occurs, the P and/or Q bit may end up
being set but we never EOI/clear them.  This could result in a lost
interrupt or the next interrupt that comes in after re-enabling never
being presented.

This patch ensures that when masking an interrupt, any pending P/Q
bits are cleared.

This fixes a bug seen with some CAPI workloads which have lots of
interrupt masking at the same time as high interrupt load.  The fix is
not specific to CAPI though.

Signed-off-by: Michael Neuling <mikey at neuling.org>
---
 hw/phb3.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/hw/phb3.c b/hw/phb3.c
index a11f84e..c5c6fe3 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -1698,7 +1698,7 @@ static int64_t phb3_msi_set_xive(void *data,
 {
 	struct phb3 *p = data;
 	uint32_t chip, index;
-	uint64_t *cache, ive_num, data64, m_server, m_prio;
+	uint64_t *cache, ive_num, data64, m_server, m_prio, ivc;
 	uint32_t *ive;
 
 	chip = p8_irq_to_chip(isn);
@@ -1743,14 +1743,34 @@ static int64_t phb3_msi_set_xive(void *data,
 	*ive = (m_server << 8) | m_prio;
 	out_be64(p->regs + PHB_IVC_UPDATE, data64);
 
-	/*
-	 * Handle Q bit if we're going to enable the interrupt.
-	 * The OS should make sure the interrupt handler has
-	 * been installed already.
-	 */
 	if (prio != 0xff) {
+		/*
+		 * Handle Q bit if we're going to enable the
+		 * interrupt.  The OS should make sure the interrupt
+		 * handler has been installed already.
+		 */
 		if (phb3_pci_msi_check_q(p, ive_num))
 			phb3_pci_msi_flush_ive(p, ive_num);
+	} else {
+		/* Read from random PHB reg to force flush */
+		in_be64(p->regs + PHB_IVC_UPDATE);
+
+		/* Order with subsequent read of Q */
+		sync();
+
+		/* Clear P, Q and Gen, preserve PE# */
+		ive[1] &= 0x0000ffff;
+
+		/*
+		 * Update the IVC with a match against the old gen
+		 * count. No need to worry about racing with P being
+		 * set in the cache since IRQ is masked at this point.
+		 */
+		ivc = SETFIELD(PHB_IVC_UPDATE_SID, 0ul, ive_num) |
+			PHB_IVC_UPDATE_ENABLE_P |
+			PHB_IVC_UPDATE_ENABLE_Q |
+			PHB_IVC_UPDATE_ENABLE_GEN;
+		out_be64(p->regs + PHB_IVC_UPDATE, ivc);
 	}
 
 	return OPAL_SUCCESS;
-- 
2.5.0



More information about the Skiboot mailing list