aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-08-09 16:38:18 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-08-11 19:54:23 +1000
commita3041e3bdb9fb7adb6505e5f3ff4edb63fde1e84 (patch)
treec1c1231318f5500c52eff8efca2d2a97532d7a77 /hw
parent95e7a10634067bd51d1efdf0fac88d75a678014d (diff)
downloadskiboot-a3041e3bdb9fb7adb6505e5f3ff4edb63fde1e84.zip
skiboot-a3041e3bdb9fb7adb6505e5f3ff4edb63fde1e84.tar.gz
skiboot-a3041e3bdb9fb7adb6505e5f3ff4edb63fde1e84.tar.bz2
lpc: Optimize SerIRQ dispatch based on which PSI IRQ fired
We keep a mask for which SerIRQ is associated with which of the 4 PSI IRQs and we only dispatch the ones that correspond to the PSI interrupt that fired. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/lpc.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/hw/lpc.c b/hw/lpc.c
index b252a54..7b6071d 100644
--- a/hw/lpc.c
+++ b/hw/lpc.c
@@ -89,7 +89,7 @@ DEFINE_LOG_ENTRY(OPAL_RC_LPC_SYNC, OPAL_PLATFORM_ERR_EVT, OPAL_LPC,
#define LPC_HC_IRQSER_START_8CLK 0x02000000
#define LPC_HC_IRQMASK 0x34 /* same bit defs as LPC_HC_IRQSTAT */
#define LPC_HC_IRQSTAT 0x38
-#define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to ... */
+#define LPC_HC_IRQ_SERIRQ0 0x80000000u /* all bits down to ... */
#define LPC_HC_IRQ_SERIRQ16 0x00008000 /* IRQ16=IOCHK#, IRQ2=SMI# */
#define LPC_HC_IRQ_SERIRQ_ALL 0xffff8000
#define LPC_HC_IRQ_LRESET 0x00000400
@@ -123,6 +123,7 @@ struct lpcm {
struct list_head clients;
bool has_serirq;
uint8_t sirq_routes[LPC_NUM_SERIRQ];
+ uint32_t sirq_rmasks[4];
};
struct lpc_client_entry {
@@ -658,6 +659,7 @@ void lpc_route_serirq(uint32_t chip_id, uint32_t sirq, uint32_t psi_idx)
{
struct proc_chip *chip;
struct lpcm *lpc;
+ uint32_t psi_old;
if (sirq >= LPC_NUM_SERIRQ) {
prerror("LPC[%03x]: Routing request for invalid SerIRQ %d\n",
@@ -670,6 +672,9 @@ void lpc_route_serirq(uint32_t chip_id, uint32_t sirq, uint32_t psi_idx)
return;
lpc = chip->lpc;
lock(&lpc->lock);
+ psi_old = lpc->sirq_routes[sirq];
+ lpc->sirq_rmasks[psi_old] &= ~(LPC_HC_IRQ_SERIRQ0 >> sirq);
+ lpc->sirq_rmasks[psi_idx] |= (LPC_HC_IRQ_SERIRQ0 >> sirq);
__lpc_route_serirq(lpc, sirq, psi_idx);
unlock(&lpc->lock);
}
@@ -714,8 +719,11 @@ static void lpc_init_interrupts_one(struct proc_chip *chip)
case PROC_CHIP_P9_CUMULUS:
/* On P9, we additionall setup the routing */
lpc->has_serirq = true;
- for (i = 0; i < LPC_NUM_SERIRQ; i++)
- __lpc_route_serirq(lpc, i, lpc->sirq_routes[i]);
+ for (i = 0; i < LPC_NUM_SERIRQ; i++) {
+ uint32_t pin = lpc->sirq_routes[i];
+ __lpc_route_serirq(lpc, i, pin);
+ lpc->sirq_rmasks[pin] |= LPC_HC_IRQ_SERIRQ0 >> i;
+ }
lpc_setup_serirq(lpc);
break;
default:
@@ -891,11 +899,11 @@ void lpc_interrupt(uint32_t chip_id)
unlock(&lpc->lock);
}
-void lpc_serirq(uint32_t chip_id, uint32_t index __unused)
+void lpc_serirq(uint32_t chip_id, uint32_t index)
{
struct proc_chip *chip = get_chip(chip_id);
struct lpcm *lpc;
- uint32_t irqs;
+ uint32_t irqs, rmask;
int rc;
/* No initialized LPC controller on that chip */
@@ -911,11 +919,14 @@ void lpc_serirq(uint32_t chip_id, uint32_t index __unused)
prerror("LPC: Failed to read LPC IRQ state\n");
goto bail;
}
+ rmask = lpc->sirq_rmasks[index];
- DBG_IRQ("LPC: IRQ on chip 0x%x, irqs=0x%08x\n", chip_id, irqs);
+ DBG_IRQ("LPC: IRQ on chip 0x%x, irqs=0x%08x rmask=0x%08x\n",
+ chip_id, irqs, rmask);
+ irqs &= rmask;
/* Handle SerIRQ interrupts */
- if (irqs & LPC_HC_IRQ_SERIRQ_ALL)
+ if (irqs)
lpc_dispatch_ser_irqs(lpc, irqs, true);
bail: