blob: 5128df71fe51564c7f149354150243578f1cd5eb [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Boyan Karatotev794b0ac2025-06-20 13:13:29 +01002 * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02008#include <assert.h>
9#include <debug.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +000010#include <drivers/arm/arm_gic.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020011#include <irq.h>
12#include <plat_topology.h>
13#include <platform.h>
14#include <platform_def.h>
15#include <power_management.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020016#include <spinlock.h>
17#include <string.h>
18#include <tftf.h>
19#include <tftf_lib.h>
20
21#define IS_PLAT_SPI(irq_num) \
22 (((irq_num) >= MIN_SPI_ID) && \
23 ((irq_num) <= MIN_SPI_ID + PLAT_MAX_SPI_OFFSET_ID))
24
Chandni Cherukurifdd08232018-12-05 12:34:45 +053025static spi_desc spi_desc_table[PLAT_MAX_SPI_OFFSET_ID + 1];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020026static ppi_desc ppi_desc_table[PLATFORM_CORE_COUNT][
27 (MAX_PPI_ID + 1) - MIN_PPI_ID];
28static sgi_desc sgi_desc_table[PLATFORM_CORE_COUNT][MAX_SGI_ID + 1];
29static spurious_desc spurious_desc_handler;
30
31/*
32 * For a given SPI, the associated IRQ handler is common to all CPUs.
33 * Therefore, we need a lock to prevent simultaneous updates.
34 *
35 * We use one lock for all SPIs. This will make it impossible to update
36 * different SPIs' handlers at the same time (although it would be fine) but it
37 * saves memory. Updating an SPI handler shouldn't occur that often anyway so we
38 * shouldn't suffer from this restriction too much.
39 */
40static spinlock_t spi_lock;
41
42static irq_handler_t *get_irq_handler(unsigned int irq_num)
43{
44 if (IS_PLAT_SPI(irq_num))
45 return &spi_desc_table[irq_num - MIN_SPI_ID].handler;
46
47 unsigned int mpid = read_mpidr_el1();
48 unsigned int linear_id = platform_get_core_pos(mpid);
49
50 if (IS_PPI(irq_num))
51 return &ppi_desc_table[linear_id][irq_num - MIN_PPI_ID].handler;
52
53 if (IS_SGI(irq_num))
54 return &sgi_desc_table[linear_id][irq_num - MIN_SGI_ID].handler;
55
56 /*
57 * The only possibility is for it to be a spurious
58 * interrupt.
59 */
60 assert(irq_num == GIC_SPURIOUS_INTERRUPT);
61 return &spurious_desc_handler;
62}
63
Boyan Karatotev6d144db2025-06-23 15:04:53 +010064unsigned int tftf_irq_get_my_sgi_num(unsigned int seq_id)
65{
66 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
67 return arm_gic_get_sgi_num(seq_id, core_pos);
68}
69
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020070void tftf_send_sgi(unsigned int sgi_id, unsigned int core_pos)
71{
72 assert(IS_SGI(sgi_id));
73
74 /*
75 * Ensure that all memory accesses prior to sending the SGI are
76 * completed.
77 */
78 dsbish();
79
80 /*
81 * Don't send interrupts to CPUs that are powering down. That would be a
82 * violation of the PSCI CPU_OFF caller responsibilities. The PSCI
83 * specification explicitely says:
84 * "Asynchronous wake-ups on a core that has been switched off through a
85 * PSCI CPU_OFF call results in an erroneous state. When this erroneous
86 * state is observed, it is IMPLEMENTATION DEFINED how the PSCI
87 * implementation reacts."
88 */
89 assert(tftf_is_core_pos_online(core_pos));
90 arm_gic_send_sgi(sgi_id, core_pos);
91}
92
93void tftf_irq_enable(unsigned int irq_num, uint8_t irq_priority)
94{
95 if (IS_PLAT_SPI(irq_num)) {
96 /*
97 * Instruct the GIC Distributor to forward the interrupt to
98 * the calling core
99 */
100 arm_gic_set_intr_target(irq_num, platform_get_core_pos(read_mpidr_el1()));
101 }
102
103 arm_gic_set_intr_priority(irq_num, irq_priority);
104 arm_gic_intr_enable(irq_num);
105
106 VERBOSE("Enabled IRQ #%u\n", irq_num);
107}
108
Boyan Karatotev6d144db2025-06-23 15:04:53 +0100109void tftf_irq_enable_sgi(unsigned int sgi_id, uint8_t irq_priority)
110{
111 unsigned int irq_num = tftf_irq_get_my_sgi_num(sgi_id);
112
113 tftf_irq_enable(irq_num, irq_priority);
114}
115
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200116void tftf_irq_disable(unsigned int irq_num)
117{
118 /* Disable the interrupt */
119 arm_gic_intr_disable(irq_num);
120
121 VERBOSE("Disabled IRQ #%u\n", irq_num);
122}
123
Boyan Karatotev6d144db2025-06-23 15:04:53 +0100124void tftf_irq_disable_sgi(unsigned int sgi_id)
125{
126 unsigned int irq_num = tftf_irq_get_my_sgi_num(sgi_id);
127
128 tftf_irq_disable(irq_num);
129}
130
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200131#define HANDLER_VALID(handler, expect_handler) \
132 ((expect_handler) ? ((handler) != NULL) : ((handler) == NULL))
133
134static int tftf_irq_update_handler(unsigned int irq_num,
135 irq_handler_t irq_handler,
136 bool expect_handler)
137{
138 irq_handler_t *cur_handler;
139 int ret = -1;
140
141 cur_handler = get_irq_handler(irq_num);
142 if (IS_PLAT_SPI(irq_num))
143 spin_lock(&spi_lock);
144
145 /*
146 * Update the IRQ handler, if the current handler is in the expected
147 * state
148 */
149 assert(HANDLER_VALID(*cur_handler, expect_handler));
150 if (HANDLER_VALID(*cur_handler, expect_handler)) {
151 *cur_handler = irq_handler;
152 ret = 0;
153 }
154
155 if (IS_PLAT_SPI(irq_num))
156 spin_unlock(&spi_lock);
157
158 return ret;
159}
160
161int tftf_irq_register_handler(unsigned int irq_num, irq_handler_t irq_handler)
162{
163 int ret;
164
165 ret = tftf_irq_update_handler(irq_num, irq_handler, false);
166 if (ret == 0)
167 INFO("Registered IRQ handler %p for IRQ #%u\n",
168 (void *)(uintptr_t) irq_handler, irq_num);
169
170 return ret;
171}
172
Boyan Karatotev6d144db2025-06-23 15:04:53 +0100173int tftf_irq_register_handler_sgi(unsigned int sgi_id, irq_handler_t irq_handler)
174{
175 unsigned int irq_num = tftf_irq_get_my_sgi_num(sgi_id);
176 return tftf_irq_register_handler(irq_num, irq_handler);
177}
178
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200179int tftf_irq_unregister_handler(unsigned int irq_num)
180{
181 int ret;
182
183 ret = tftf_irq_update_handler(irq_num, NULL, true);
184 if (ret == 0)
185 INFO("Unregistered IRQ handler for IRQ #%u\n", irq_num);
186
187 return ret;
188}
189
Boyan Karatotev6d144db2025-06-23 15:04:53 +0100190int tftf_irq_unregister_handler_sgi(unsigned int sgi_id)
191{
192 unsigned int irq_num = tftf_irq_get_my_sgi_num(sgi_id);
193 return tftf_irq_unregister_handler(irq_num);
194}
195
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200196int tftf_irq_handler_dispatcher(void)
197{
198 unsigned int raw_iar;
199 unsigned int irq_num;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200200 irq_handler_t *handler;
201 void *irq_data = NULL;
202 int rc = 0;
203
204 /* Acknowledge the interrupt */
205 irq_num = arm_gic_intr_ack(&raw_iar);
206
207 handler = get_irq_handler(irq_num);
Boyan Karatotev794b0ac2025-06-20 13:13:29 +0100208 irq_data = &irq_num;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200209
210 if (*handler != NULL)
211 rc = (*handler)(irq_data);
212
213 /* Mark the processing of the interrupt as complete */
214 if (irq_num != GIC_SPURIOUS_INTERRUPT)
215 arm_gic_end_of_intr(raw_iar);
216
217 return rc;
218}
219
220void tftf_irq_setup(void)
221{
222 memset(spi_desc_table, 0, sizeof(spi_desc_table));
223 memset(ppi_desc_table, 0, sizeof(ppi_desc_table));
224 memset(sgi_desc_table, 0, sizeof(sgi_desc_table));
225 memset(&spurious_desc_handler, 0, sizeof(spurious_desc_handler));
226 init_spinlock(&spi_lock);
227}