aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-11-18 11:34:04 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-11-19 14:43:23 +1100
commit53def38014107ca522af8ee0a1004d36b31e3681 (patch)
treeb0a2b44b8cdf41b6189ea20f86e96195a216a67f
parent396de731b044578233b7f2f977c876971586e1c0 (diff)
downloadskiboot-53def38014107ca522af8ee0a1004d36b31e3681.zip
skiboot-53def38014107ca522af8ee0a1004d36b31e3681.tar.gz
skiboot-53def38014107ca522af8ee0a1004d36b31e3681.tar.bz2
hw/phb3: Flush cache line after updating P/Q bits
When doing an MSI EOI, we update the P and Q bits in the IVE. That causes the corresponding cache line to be dirty in the L3 which will cause a subsequent update by the PHB (upon recieving the next MSI) to get a few retries until it gets flushed. We can improve the situation (and thus performance) by doing a dcbf instruction to force a flush of the update we do in SW. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--hw/phb3.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/hw/phb3.c b/hw/phb3.c
index 36e8c58..220740a 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -1045,7 +1045,7 @@ static int64_t phb3_map_pe_dma_window_real(struct phb *phb,
return OPAL_SUCCESS;
}
-static void phb3_pci_msi_check_q(struct phb3 *p, uint32_t ive_num)
+static bool phb3_pci_msi_check_q(struct phb3 *p, uint32_t ive_num)
{
uint64_t ive, ivc, ffi, state;
uint8_t *q_byte;
@@ -1067,7 +1067,7 @@ static void phb3_pci_msi_check_q(struct phb3 *p, uint32_t ive_num)
/* Q still not set, bail out */
if (!(*q_byte & 0x1))
- return;
+ return false;
}
/* Lock FFI and send interrupt */
@@ -1076,7 +1076,7 @@ static void phb3_pci_msi_check_q(struct phb3 *p, uint32_t ive_num)
if (!state)
break;
if (state == ~0ULL) /* PHB Fenced */
- return;
+ return false;
}
/* Clear Q bit and update IVC */
@@ -1092,6 +1092,16 @@ static void phb3_pci_msi_check_q(struct phb3 *p, uint32_t ive_num)
*/
ffi = SETFIELD(PHB_FFI_REQUEST_ISN, 0ul, ive_num) | PHB_FFI_LOCK_CLEAR;
out_be64(p->regs + PHB_FFI_REQUEST, ffi);
+
+ return true;
+}
+
+static void phb3_pci_msi_flush_ive(struct phb3 *p, uint32_t ive_num)
+{
+ asm volatile("dcbf %0,%1"
+ :
+ : "b" (p->tbl_ivt), "r" (ive_num * IVT_TABLE_STRIDE * 8)
+ : "memory");
}
static int64_t phb3_pci_msi_eoi(struct phb *phb,
@@ -1127,6 +1137,8 @@ static int64_t phb3_pci_msi_eoi(struct phb *phb,
/* Handle Q bit */
phb3_pci_msi_check_q(p, ive_num);
+ phb3_pci_msi_flush_ive(p, ive_num);
+
return OPAL_SUCCESS;
}
@@ -1637,8 +1649,10 @@ static int64_t phb3_msi_set_xive(void *data,
* The OS should make sure the interrupt handler has
* been installed already.
*/
- if (prio != 0xff)
- phb3_pci_msi_check_q(p, ive_num);
+ if (prio != 0xff) {
+ if (phb3_pci_msi_check_q(p, ive_num))
+ phb3_pci_msi_flush_ive(p, ive_num);
+ }
return OPAL_SUCCESS;
}