|
7 | 7 | #include <stdbool.h> |
8 | 8 | #include <stdint.h> |
9 | 9 |
|
| 10 | +#include "hw/top/dt/dt_alert_handler.h" |
| 11 | +#include "hw/top/dt/dt_rv_plic.h" |
| 12 | +#include "sw/device/lib/base/macros.h" |
10 | 13 | #include "sw/device/lib/base/math.h" |
11 | 14 | #include "sw/device/lib/base/mmio.h" |
12 | 15 | #include "sw/device/lib/dif/dif_alert_handler.h" |
13 | 16 | #include "sw/device/lib/dif/dif_rv_plic.h" |
14 | 17 | #include "sw/device/lib/runtime/irq.h" |
15 | 18 | #include "sw/device/lib/runtime/log.h" |
16 | 19 | #include "sw/device/lib/testing/alert_handler_testutils.h" |
17 | | -#include "sw/device/lib/testing/rv_plic_testutils.h" |
18 | 20 | #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h" |
19 | 21 | #include "sw/device/lib/testing/test_framework/check.h" |
20 | 22 | #include "sw/device/lib/testing/test_framework/ottf_main.h" |
21 | 23 |
|
22 | 24 | #include "hw/top/alert_handler_regs.h" // Generated. |
23 | | -#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" |
24 | | -#include "sw/device/lib/testing/autogen/isr_testutils.h" |
25 | 25 |
|
26 | 26 | OTTF_DEFINE_TEST_CONFIG(); |
27 | 27 |
|
28 | 28 | static dif_rv_plic_t plic; |
29 | 29 | static dif_alert_handler_t alert_handler; |
30 | | -static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0; |
31 | 30 |
|
32 | | -static plic_isr_ctx_t plic_ctx = { |
33 | | - .rv_plic = &plic, |
34 | | - .hart_id = kPlicTarget, |
| 31 | +enum { |
| 32 | + /** |
| 33 | + * PLIC target for the Ibex core. |
| 34 | + */ |
| 35 | + kDtRvPlicTargetIbex0 = 0, |
35 | 36 | }; |
36 | 37 |
|
37 | 38 | // Depends on the clock domain, sometimes alert handler will trigger a spurious |
38 | 39 | // alert after the alert timeout. (Issue #2321) |
39 | 40 | // So we allow class A interrupt to fire after the real timeout interrupt is |
40 | 41 | // triggered. |
41 | | -static alert_handler_isr_ctx_t alert_handler_ctx = { |
42 | | - .alert_handler = &alert_handler, |
43 | | - .plic_alert_handler_start_irq_id = kTopEarlgreyPlicIrqIdAlertHandlerClassa, |
44 | | - .expected_irq = kDifAlertHandlerIrqClassb, |
45 | | - .is_only_irq = false, |
46 | | -}; |
| 42 | +static volatile bool irq_fired = false; |
47 | 43 |
|
48 | 44 | /** |
49 | 45 | * Initialize the peripherals used in this test. |
50 | 46 | */ |
51 | 47 | static void init_peripherals(void) { |
52 | | - mmio_region_t base_addr = |
53 | | - mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR); |
54 | | - CHECK_DIF_OK(dif_rv_plic_init(base_addr, &plic)); |
55 | | - |
56 | | - base_addr = mmio_region_from_addr(TOP_EARLGREY_ALERT_HANDLER_BASE_ADDR); |
57 | | - CHECK_DIF_OK(dif_alert_handler_init(base_addr, &alert_handler)); |
| 48 | + CHECK_DIF_OK(dif_rv_plic_init_from_dt(kDtRvPlic, &plic)); |
| 49 | + CHECK_DIF_OK(dif_alert_handler_init_from_dt(kDtAlertHandler, &alert_handler)); |
58 | 50 |
|
59 | 51 | // Enable all the alert_handler interrupts used in this test. |
60 | | - rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, |
61 | | - kTopEarlgreyPlicIrqIdAlertHandlerClassa, |
62 | | - kTopEarlgreyPlicIrqIdAlertHandlerClassd); |
| 52 | + dt_plic_irq_id_t classa_irq = dt_alert_handler_irq_to_plic_id( |
| 53 | + kDtAlertHandler, kDtAlertHandlerIrqClassa); |
| 54 | + dt_plic_irq_id_t classb_irq = dt_alert_handler_irq_to_plic_id( |
| 55 | + kDtAlertHandler, kDtAlertHandlerIrqClassb); |
| 56 | + dt_plic_irq_id_t classc_irq = dt_alert_handler_irq_to_plic_id( |
| 57 | + kDtAlertHandler, kDtAlertHandlerIrqClassc); |
| 58 | + dt_plic_irq_id_t classd_irq = dt_alert_handler_irq_to_plic_id( |
| 59 | + kDtAlertHandler, kDtAlertHandlerIrqClassd); |
| 60 | + |
| 61 | + dt_plic_irq_id_t irq_ids[] = {classa_irq, classb_irq, classc_irq, classd_irq}; |
| 62 | + for (size_t i = 0; i < ARRAYSIZE(irq_ids); ++i) { |
| 63 | + CHECK_DIF_OK( |
| 64 | + dif_rv_plic_irq_set_priority(&plic, irq_ids[i], /*priority=*/1u)); |
| 65 | + CHECK_DIF_OK(dif_rv_plic_irq_set_enabled( |
| 66 | + &plic, irq_ids[i], kDtRvPlicTargetIbex0, kDifToggleEnabled)); |
| 67 | + } |
| 68 | + |
| 69 | + CHECK_DIF_OK(dif_rv_plic_target_set_threshold(&plic, kDtRvPlicTargetIbex0, |
| 70 | + /*threshold=*/0u)); |
63 | 71 | } |
64 | 72 |
|
65 | 73 | /** |
@@ -129,37 +137,48 @@ static void alert_handler_config(void) { |
129 | 137 | * line to the CPU, which results in a call to this OTTF ISR. This ISR |
130 | 138 | * overrides the default OTTF implementation. |
131 | 139 | */ |
132 | | -void ottf_external_isr(uint32_t *exc_info) { |
133 | | - top_earlgrey_plic_peripheral_t peripheral_serviced; |
134 | | - dif_alert_handler_irq_t irq_serviced; |
135 | | - isr_testutils_alert_handler_isr(plic_ctx, alert_handler_ctx, |
136 | | - &peripheral_serviced, &irq_serviced); |
137 | | - CHECK(peripheral_serviced == kTopEarlgreyPlicPeripheralAlertHandler, |
138 | | - "Interrupt from unexpected peripheral: %d", peripheral_serviced); |
139 | | - |
140 | | - // Only interrupts from class B alerts are expected for this test. Report the |
141 | | - // unexpected class. |
142 | | - CHECK(irq_serviced == kDifAlertHandlerIrqClassb, |
143 | | - "Interrupt from unexpected class: Class %c", 'A' + irq_serviced); |
144 | | - // Disable the interrupt after seeing a single ping timeout. |
145 | | - CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( |
146 | | - &alert_handler, kDifAlertHandlerIrqClassb, kDifToggleDisabled)); |
| 140 | +bool ottf_handle_irq(uint32_t *exc_info, dt_instance_id_t inst_id, |
| 141 | + dif_rv_plic_irq_id_t plic_irq_id) { |
| 142 | + // Check if this is the alert handler peripheral |
| 143 | + if (inst_id != dt_alert_handler_instance_id(kDtAlertHandler)) { |
| 144 | + return false; |
| 145 | + } |
| 146 | + |
| 147 | + // Convert PLIC IRQ ID to alert handler IRQ |
| 148 | + dt_alert_handler_irq_t irq = |
| 149 | + dt_alert_handler_irq_from_plic_id(kDtAlertHandler, plic_irq_id); |
| 150 | + |
| 151 | + // Acknowledge the interrupt |
| 152 | + CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(&alert_handler, irq)); |
| 153 | + |
| 154 | + // We expect Class B interrupt primarily, but may see Class A due to timing |
| 155 | + // (Issue #2321 - spurious alerts after timeout) |
| 156 | + if (irq == kDtAlertHandlerIrqClassb) { |
| 157 | + irq_fired = true; |
| 158 | + // Disable the interrupt after seeing the ping timeout |
| 159 | + CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( |
| 160 | + &alert_handler, kDifAlertHandlerIrqClassb, kDifToggleDisabled)); |
| 161 | + } else if (irq == kDtAlertHandlerIrqClassa) { |
| 162 | + // Allow Class A as per Issue #2321 |
| 163 | + LOG_INFO("Received spurious Class A interrupt (expected per Issue #2321)"); |
| 164 | + } else { |
| 165 | + CHECK(false, "Interrupt from unexpected class: %d", irq); |
| 166 | + } |
| 167 | + |
| 168 | + return true; |
147 | 169 | } |
148 | 170 |
|
149 | 171 | bool test_main(void) { |
150 | 172 | init_peripherals(); |
151 | 173 |
|
152 | | - // Stop Ibex from servicing interrupts just before WFI, which would lead to a |
153 | | - // long sleep if the test changes to only handle a single ping timeout. |
154 | | - irq_global_ctrl(false); |
| 174 | + // Enable interrupts globally |
| 175 | + irq_global_ctrl(true); |
155 | 176 | irq_external_ctrl(true); |
156 | 177 |
|
157 | 178 | alert_handler_config(); |
158 | 179 |
|
159 | | - wait_for_interrupt(); |
160 | | - |
161 | | - // Enable the external IRQ at Ibex to jump to servicing it. |
162 | | - irq_global_ctrl(true); |
| 180 | + // Wait for the ping timeout interrupt to fire |
| 181 | + ATOMIC_WAIT_FOR_INTERRUPT(irq_fired); |
163 | 182 |
|
164 | 183 | // Check local alert cause. |
165 | 184 | bool is_cause; |
|
0 commit comments