aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2016-02-11 15:25:33 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-04-27 07:42:53 +1000
commitc8bea6e01608f77550ef686bb7359094311de810 (patch)
tree73dbf7d9b50fe6055646dcaa9875da514416df53 /hw
parentca31bfedc8f94a2070b4a2d29636a3b050c12d33 (diff)
downloadskiboot-c8bea6e01608f77550ef686bb7359094311de810.zip
skiboot-c8bea6e01608f77550ef686bb7359094311de810.tar.gz
skiboot-c8bea6e01608f77550ef686bb7359094311de810.tar.bz2
hw/phb3: Ensure PQ bits are cleared in the IVC when masking IRQ
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@neuling.org> Tested-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/phb3.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/hw/phb3.c b/hw/phb3.c
index 11fcf39..5d865f6 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -1613,7 +1613,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);
@@ -1658,14 +1658,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;