diff options
Diffstat (limited to 'hw/intc/aspeed_intc.c')
-rw-r--r-- | hw/intc/aspeed_intc.c | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index 6f37afc..1cbee0e 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -42,20 +42,32 @@ REG32(GICINT136_STATUS, 0x804) #define GICINT_STATUS_BASE R_GICINT128_STATUS -static void aspeed_intc_update(AspeedINTCState *s, int irq, int level) +/* + * Update the state of an interrupt controller pin by setting + * the specified output pin to the given level. + * The input pin index should be between 0 and the number of input pins. + * The output pin index should be between 0 and the number of output pins. + */ +static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx, + int outpin_idx, int level) { AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); const char *name = object_get_typename(OBJECT(s)); - if (irq >= aic->num_inpins) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Invalid input pin index: %d\n", - __func__, irq); + if (inpin_idx >= aic->num_inpins) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid input pin index: %d\n", + __func__, inpin_idx); return; } - trace_aspeed_intc_update_irq(name, irq, level); - qemu_set_irq(s->output_pins[irq], level); + if (outpin_idx >= aic->num_outpins) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid output pin index: %d\n", + __func__, outpin_idx); + return; + } + + trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level); + qemu_set_irq(s->output_pins[outpin_idx], level); } /* @@ -72,23 +84,28 @@ static void aspeed_intc_set_irq(void *opaque, int irq, int level) uint32_t status_reg = GICINT_STATUS_BASE + ((0x100 * irq) >> 2); uint32_t select = 0; uint32_t enable; + int outpin_idx; + int inpin_idx; int i; + outpin_idx = irq; + inpin_idx = irq; + if (irq >= aic->num_inpins) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid input pin index: %d\n", __func__, irq); return; } - trace_aspeed_intc_set_irq(name, irq, level); - enable = s->enable[irq]; + trace_aspeed_intc_set_irq(name, inpin_idx, level); + enable = s->enable[inpin_idx]; if (!level) { return; } for (i = 0; i < aic->num_lines; i++) { - if (s->orgates[irq].levels[i]) { + if (s->orgates[inpin_idx].levels[i]) { if (enable & BIT(i)) { select |= BIT(i); } @@ -101,7 +118,7 @@ static void aspeed_intc_set_irq(void *opaque, int irq, int level) trace_aspeed_intc_select(name, select); - if (s->mask[irq] || s->regs[status_reg]) { + if (s->mask[inpin_idx] || s->regs[status_reg]) { /* * a. mask is not 0 means in ISR mode * sources interrupt routine are executing. @@ -110,16 +127,17 @@ static void aspeed_intc_set_irq(void *opaque, int irq, int level) * * save source interrupt to pending variable. */ - s->pending[irq] |= select; - trace_aspeed_intc_pending_irq(name, irq, s->pending[irq]); + s->pending[inpin_idx] |= select; + trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]); } else { /* * notify firmware which source interrupt are coming * by setting status register */ s->regs[status_reg] = select; - trace_aspeed_intc_trigger_irq(name, irq, s->regs[status_reg]); - aspeed_intc_update(s, irq, 1); + trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx, + s->regs[status_reg]); + aspeed_intc_update(s, inpin_idx, outpin_idx, 1); } } @@ -131,14 +149,16 @@ static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset, uint32_t reg = offset >> 2; uint32_t old_enable; uint32_t change; + int inpin_idx; uint32_t irq; irq = (offset & 0x0f00) >> 8; + inpin_idx = irq; - if (irq >= aic->num_inpins) { + if (inpin_idx >= aic->num_inpins) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid input pin index: %d\n", - __func__, irq); + __func__, inpin_idx); return; } @@ -149,17 +169,17 @@ static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset, */ /* disable all source interrupt */ - if (!data && !s->enable[irq]) { + if (!data && !s->enable[inpin_idx]) { s->regs[reg] = data; return; } - old_enable = s->enable[irq]; - s->enable[irq] |= data; + old_enable = s->enable[inpin_idx]; + s->enable[inpin_idx] |= data; /* enable new source interrupt */ - if (old_enable != s->enable[irq]) { - trace_aspeed_intc_enable(name, s->enable[irq]); + if (old_enable != s->enable[inpin_idx]) { + trace_aspeed_intc_enable(name, s->enable[inpin_idx]); s->regs[reg] = data; return; } @@ -167,11 +187,11 @@ static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset, /* mask and unmask source interrupt */ change = s->regs[reg] ^ data; if (change & data) { - s->mask[irq] &= ~change; - trace_aspeed_intc_unmask(name, change, s->mask[irq]); + s->mask[inpin_idx] &= ~change; + trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]); } else { - s->mask[irq] |= change; - trace_aspeed_intc_mask(name, change, s->mask[irq]); + s->mask[inpin_idx] |= change; + trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]); } s->regs[reg] = data; @@ -183,6 +203,8 @@ static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset, AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); const char *name = object_get_typename(OBJECT(s)); uint32_t reg = offset >> 2; + int outpin_idx; + int inpin_idx; uint32_t irq; if (!data) { @@ -191,11 +213,13 @@ static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset, } irq = (offset & 0x0f00) >> 8; + outpin_idx = irq; + inpin_idx = irq; - if (irq >= aic->num_inpins) { + if (inpin_idx >= aic->num_inpins) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid input pin index: %d\n", - __func__, irq); + __func__, inpin_idx); return; } @@ -214,21 +238,22 @@ static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset, /* All source ISR execution are done */ if (!s->regs[reg]) { - trace_aspeed_intc_all_isr_done(name, irq); - if (s->pending[irq]) { + trace_aspeed_intc_all_isr_done(name, inpin_idx); + if (s->pending[inpin_idx]) { /* * handle pending source interrupt * notify firmware which source interrupt are pending * by setting status register */ - s->regs[reg] = s->pending[irq]; - s->pending[irq] = 0; - trace_aspeed_intc_trigger_irq(name, irq, s->regs[reg]); - aspeed_intc_update(s, irq, 1); + s->regs[reg] = s->pending[inpin_idx]; + s->pending[inpin_idx] = 0; + trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx, + s->regs[reg]); + aspeed_intc_update(s, inpin_idx, outpin_idx, 1); } else { /* clear irq */ - trace_aspeed_intc_clear_irq(name, irq, 0); - aspeed_intc_update(s, irq, 0); + trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0); + aspeed_intc_update(s, inpin_idx, outpin_idx, 0); } } } |