[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v1 05/18] hw/intc/aspeed: Introduce helper functions for enable a
From: |
Jamin Lin |
Subject: |
[PATCH v1 05/18] hw/intc/aspeed: Introduce helper functions for enable and status registers |
Date: |
Tue, 21 Jan 2025 15:04:11 +0800 |
The behavior of the enable and status registers is almost identical between
INTC0 and INTC1. To reduce duplicated code, adds
"aspeed_2700_intc_enable_handler" functions to handle enable register write
behavior and "aspeed_2700_intc_status_handler" functions to handle status
register write behavior.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/intc/aspeed_intc.c | 189 ++++++++++++++++++++++++------------------
1 file changed, 107 insertions(+), 82 deletions(-)
diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
index 25035c65ca..7dff5e6039 100644
--- a/hw/intc/aspeed_intc.c
+++ b/hw/intc/aspeed_intc.c
@@ -114,6 +114,111 @@ static void aspeed_intc_set_irq(void *opaque, int irq,
int level)
}
}
+static void aspeed_2700_intc_enable_handler(AspeedINTCState *s, uint32_t addr,
+ uint64_t data)
+{
+ AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
+ uint32_t offset = addr << 2;
+ uint32_t old_enable;
+ uint32_t change;
+ uint32_t irq;
+
+ irq = (offset & 0x0f00) >> 8;
+
+ if (irq >= aic->num_ints) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
+ __func__, irq);
+ return;
+ }
+
+ /*
+ * The enable registers are used to enable source interrupts.
+ * They also handle masking and unmasking of source interrupts
+ * during the execution of the source ISR.
+ */
+
+ /* disable all source interrupt */
+ if (!data && !s->enable[irq]) {
+ s->regs[addr] = data;
+ return;
+ }
+
+ old_enable = s->enable[irq];
+ s->enable[irq] |= data;
+
+ /* enable new source interrupt */
+ if (old_enable != s->enable[irq]) {
+ trace_aspeed_intc_enable(s->enable[irq]);
+ s->regs[addr] = data;
+ return;
+ }
+
+ /* mask and unmask source interrupt */
+ change = s->regs[addr] ^ data;
+ if (change & data) {
+ s->mask[irq] &= ~change;
+ trace_aspeed_intc_unmask(change, s->mask[irq]);
+ } else {
+ s->mask[irq] |= change;
+ trace_aspeed_intc_mask(change, s->mask[irq]);
+ }
+ s->regs[addr] = data;
+}
+
+static void aspeed_2700_intc_status_handler(AspeedINTCState *s, uint32_t addr,
+ uint64_t data)
+{
+ AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
+ uint32_t offset = addr << 2;
+ uint32_t irq;
+
+ irq = (offset & 0x0f00) >> 8;
+
+ if (!data) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
+ return;
+ }
+
+ if (irq >= aic->num_ints) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
+ __func__, irq);
+ return;
+ }
+
+ /* clear status */
+ s->regs[addr] &= ~data;
+
+ /*
+ * The status registers are used for notify sources ISR are executed.
+ * If one source ISR is executed, it will clear one bit.
+ * If it clear all bits, it means to initialize this register status
+ * rather than sources ISR are executed.
+ */
+ if (data == 0xffffffff) {
+ return;
+ }
+
+ /* All source ISR execution are done */
+ if (!s->regs[addr]) {
+ trace_aspeed_intc_all_isr_done(irq);
+ if (s->pending[irq]) {
+ /*
+ * handle pending source interrupt
+ * notify firmware which source interrupt are pending
+ * by setting status register
+ */
+ s->regs[addr] = s->pending[irq];
+ s->pending[irq] = 0;
+ trace_aspeed_intc_trigger_irq(irq, s->regs[addr]);
+ aspeed_intc_update(s, irq, 1);
+ } else {
+ /* clear irq */
+ trace_aspeed_intc_clear_irq(irq, 0);
+ aspeed_intc_update(s, irq, 0);
+ }
+ }
+}
+
static uint64_t aspeed_2700_intc0_read(void *opaque, hwaddr offset,
unsigned int size)
{
@@ -141,9 +246,6 @@ static void aspeed_2700_intc0_write(void *opaque, hwaddr
offset, uint64_t data,
AspeedINTCState *s = ASPEED_INTC(opaque);
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
uint32_t addr = offset >> 2;
- uint32_t old_enable;
- uint32_t change;
- uint32_t irq;
if (offset >= aic->reg_size) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -164,45 +266,7 @@ static void aspeed_2700_intc0_write(void *opaque, hwaddr
offset, uint64_t data,
case R_INTC0_GICINT134_EN:
case R_INTC0_GICINT135_EN:
case R_INTC0_GICINT136_EN:
- irq = (offset & 0x0f00) >> 8;
-
- if (irq >= aic->num_ints) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number:
%d\n",
- __func__, irq);
- return;
- }
-
- /*
- * These registers are used for enable sources interrupt and
- * mask and unmask source interrupt while executing source ISR.
- */
-
- /* disable all source interrupt */
- if (!data && !s->enable[irq]) {
- s->regs[addr] = data;
- return;
- }
-
- old_enable = s->enable[irq];
- s->enable[irq] |= data;
-
- /* enable new source interrupt */
- if (old_enable != s->enable[irq]) {
- trace_aspeed_intc_enable(s->enable[irq]);
- s->regs[addr] = data;
- return;
- }
-
- /* mask and unmask source interrupt */
- change = s->regs[addr] ^ data;
- if (change & data) {
- s->mask[irq] &= ~change;
- trace_aspeed_intc_unmask(change, s->mask[irq]);
- } else {
- s->mask[irq] |= change;
- trace_aspeed_intc_mask(change, s->mask[irq]);
- }
- s->regs[addr] = data;
+ aspeed_2700_intc_enable_handler(s, addr, data);
break;
case R_INTC0_GICINT128_STATUS:
case R_INTC0_GICINT129_STATUS:
@@ -213,46 +277,7 @@ static void aspeed_2700_intc0_write(void *opaque, hwaddr
offset, uint64_t data,
case R_INTC0_GICINT134_STATUS:
case R_INTC0_GICINT135_STATUS:
case R_INTC0_GICINT136_STATUS:
- irq = (offset & 0x0f00) >> 8;
-
- if (irq >= aic->num_ints) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number:
%d\n",
- __func__, irq);
- return;
- }
-
- /* clear status */
- s->regs[addr] &= ~data;
-
- /*
- * These status registers are used for notify sources ISR are executed.
- * If one source ISR is executed, it will clear one bit.
- * If it clear all bits, it means to initialize this register status
- * rather than sources ISR are executed.
- */
- if (data == 0xffffffff) {
- return;
- }
-
- /* All source ISR execution are done */
- if (!s->regs[addr]) {
- trace_aspeed_intc_all_isr_done(irq);
- if (s->pending[irq]) {
- /*
- * handle pending source interrupt
- * notify firmware which source interrupt are pending
- * by setting status register
- */
- s->regs[addr] = s->pending[irq];
- s->pending[irq] = 0;
- trace_aspeed_intc_trigger_irq(irq, s->regs[addr]);
- aspeed_intc_update(s, irq, 1);
- } else {
- /* clear irq */
- trace_aspeed_intc_clear_irq(irq, 0);
- aspeed_intc_update(s, irq, 0);
- }
- }
+ aspeed_2700_intc_status_handler(s, addr, data);
break;
default:
s->regs[addr] = data;
--
2.34.1
- [PATCH v1 00/18] Support AST2700 A1, Jamin Lin, 2025/01/21
- [PATCH v1 01/18] hw/intc/aspeed: Rename INTC to INTC0, Jamin Lin, 2025/01/21
- [PATCH v1 02/18] hw/intc/aspeed: Support different memory region ops, Jamin Lin, 2025/01/21
- [PATCH v1 03/18] hw/intc/aspeed: Introduce a new aspeed_2700_intc0_ops for INTC0, Jamin Lin, 2025/01/21
- [PATCH v1 05/18] hw/intc/aspeed: Introduce helper functions for enable and status registers,
Jamin Lin <=
- [PATCH v1 04/18] hw/intc/aspeed: Support setting different memory and register size, Jamin Lin, 2025/01/21
- [PATCH v1 06/18] hw/intc/aspeed: Introduce AspeedINTCIRQ structure to save the irq index and register address, Jamin Lin, 2025/01/21
- [PATCH v1 07/18] hw/intc/aspeed: Introduce IRQ handler function to reduce code duplication, Jamin Lin, 2025/01/21
- [PATCH v1 08/18] hw/intc/aspeed: Add Support for Multi-Output IRQ Handling, Jamin Lin, 2025/01/21
- [PATCH v1 09/18] hw/intc/aspeed: Add ID to trace events for better debugging, Jamin Lin, 2025/01/21
- [PATCH v1 10/18] hw/intc/aspeed: Add Support for AST2700 INTC1 Controller, Jamin Lin, 2025/01/21
- [PATCH v1 11/18] hw/misc/aspeed_scu: Add Support for AST2700/AST2750 A1 Silicon Revisions, Jamin Lin, 2025/01/21
- [PATCH v1 12/18] hw/arm/aspeed_ast27x0: Support two levels of INTC controllers for AST2700 A1, Jamin Lin, 2025/01/21