diff options
author | Michael Neuling <mikey@neuling.org> | 2016-02-11 15:25:33 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-04-27 07:42:53 +1000 |
commit | c8bea6e01608f77550ef686bb7359094311de810 (patch) | |
tree | 73dbf7d9b50fe6055646dcaa9875da514416df53 /hw | |
parent | ca31bfedc8f94a2070b4a2d29636a3b050c12d33 (diff) | |
download | skiboot-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.c | 32 |
1 files changed, 26 insertions, 6 deletions
@@ -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; |