blob: 70c321b19554e69767a154165804b2672faa24e2 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
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>
16#include <sgi.h>
17#include <spinlock.h>
18#include <string.h>
19#include <tftf.h>
20#include <tftf_lib.h>
21
22#define IS_PLAT_SPI(irq_num) \
23 (((irq_num) >= MIN_SPI_ID) && \
24 ((irq_num) <= MIN_SPI_ID + PLAT_MAX_SPI_OFFSET_ID))
25
Chandni Cherukurifdd08232018-12-05 12:34:45 +053026static spi_desc spi_desc_table[PLAT_MAX_SPI_OFFSET_ID + 1];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020027static ppi_desc ppi_desc_table[PLATFORM_CORE_COUNT][
28 (MAX_PPI_ID + 1) - MIN_PPI_ID];
29static sgi_desc sgi_desc_table[PLATFORM_CORE_COUNT][MAX_SGI_ID + 1];
30static spurious_desc spurious_desc_handler;
31
32/*
33 * For a given SPI, the associated IRQ handler is common to all CPUs.
34 * Therefore, we need a lock to prevent simultaneous updates.
35 *
36 * We use one lock for all SPIs. This will make it impossible to update
37 * different SPIs' handlers at the same time (although it would be fine) but it
38 * saves memory. Updating an SPI handler shouldn't occur that often anyway so we
39 * shouldn't suffer from this restriction too much.
40 */
41static spinlock_t spi_lock;
42
43static irq_handler_t *get_irq_handler(unsigned int irq_num)
44{
45 if (IS_PLAT_SPI(irq_num))
46 return &spi_desc_table[irq_num - MIN_SPI_ID].handler;
47
48 unsigned int mpid = read_mpidr_el1();
49 unsigned int linear_id = platform_get_core_pos(mpid);
50
51 if (IS_PPI(irq_num))
52 return &ppi_desc_table[linear_id][irq_num - MIN_PPI_ID].handler;
53
54 if (IS_SGI(irq_num))
55 return &sgi_desc_table[linear_id][irq_num - MIN_SGI_ID].handler;
56
57 /*
58 * The only possibility is for it to be a spurious
59 * interrupt.
60 */
61 assert(irq_num == GIC_SPURIOUS_INTERRUPT);
62 return &spurious_desc_handler;
63}
64
65void tftf_send_sgi(unsigned int sgi_id, unsigned int core_pos)
66{
67 assert(IS_SGI(sgi_id));
68
69 /*
70 * Ensure that all memory accesses prior to sending the SGI are
71 * completed.
72 */
73 dsbish();
74
75 /*
76 * Don't send interrupts to CPUs that are powering down. That would be a
77 * violation of the PSCI CPU_OFF caller responsibilities. The PSCI
78 * specification explicitely says:
79 * "Asynchronous wake-ups on a core that has been switched off through a
80 * PSCI CPU_OFF call results in an erroneous state. When this erroneous
81 * state is observed, it is IMPLEMENTATION DEFINED how the PSCI
82 * implementation reacts."
83 */
84 assert(tftf_is_core_pos_online(core_pos));
85 arm_gic_send_sgi(sgi_id, core_pos);
86}
87
88void tftf_irq_enable(unsigned int irq_num, uint8_t irq_priority)
89{
90 if (IS_PLAT_SPI(irq_num)) {
91 /*
92 * Instruct the GIC Distributor to forward the interrupt to
93 * the calling core
94 */
95 arm_gic_set_intr_target(irq_num, platform_get_core_pos(read_mpidr_el1()));
96 }
97
98 arm_gic_set_intr_priority(irq_num, irq_priority);
99 arm_gic_intr_enable(irq_num);
100
101 VERBOSE("Enabled IRQ #%u\n", irq_num);
102}
103
104void tftf_irq_disable(unsigned int irq_num)
105{
106 /* Disable the interrupt */
107 arm_gic_intr_disable(irq_num);
108
109 VERBOSE("Disabled IRQ #%u\n", irq_num);
110}
111
112#define HANDLER_VALID(handler, expect_handler) \
113 ((expect_handler) ? ((handler) != NULL) : ((handler) == NULL))
114
115static int tftf_irq_update_handler(unsigned int irq_num,
116 irq_handler_t irq_handler,
117 bool expect_handler)
118{
119 irq_handler_t *cur_handler;
120 int ret = -1;
121
122 cur_handler = get_irq_handler(irq_num);
123 if (IS_PLAT_SPI(irq_num))
124 spin_lock(&spi_lock);
125
126 /*
127 * Update the IRQ handler, if the current handler is in the expected
128 * state
129 */
130 assert(HANDLER_VALID(*cur_handler, expect_handler));
131 if (HANDLER_VALID(*cur_handler, expect_handler)) {
132 *cur_handler = irq_handler;
133 ret = 0;
134 }
135
136 if (IS_PLAT_SPI(irq_num))
137 spin_unlock(&spi_lock);
138
139 return ret;
140}
141
142int tftf_irq_register_handler(unsigned int irq_num, irq_handler_t irq_handler)
143{
144 int ret;
145
146 ret = tftf_irq_update_handler(irq_num, irq_handler, false);
147 if (ret == 0)
148 INFO("Registered IRQ handler %p for IRQ #%u\n",
149 (void *)(uintptr_t) irq_handler, irq_num);
150
151 return ret;
152}
153
154int tftf_irq_unregister_handler(unsigned int irq_num)
155{
156 int ret;
157
158 ret = tftf_irq_update_handler(irq_num, NULL, true);
159 if (ret == 0)
160 INFO("Unregistered IRQ handler for IRQ #%u\n", irq_num);
161
162 return ret;
163}
164
165int tftf_irq_handler_dispatcher(void)
166{
167 unsigned int raw_iar;
168 unsigned int irq_num;
169 sgi_data_t sgi_data;
170 irq_handler_t *handler;
171 void *irq_data = NULL;
172 int rc = 0;
173
174 /* Acknowledge the interrupt */
175 irq_num = arm_gic_intr_ack(&raw_iar);
176
177 handler = get_irq_handler(irq_num);
178 if (IS_PLAT_SPI(irq_num)) {
179 irq_data = &irq_num;
180 } else if (IS_PPI(irq_num)) {
181 irq_data = &irq_num;
182 } else if (IS_SGI(irq_num)) {
183 sgi_data.irq_id = irq_num;
184 irq_data = &sgi_data;
185 }
186
187 if (*handler != NULL)
188 rc = (*handler)(irq_data);
189
190 /* Mark the processing of the interrupt as complete */
191 if (irq_num != GIC_SPURIOUS_INTERRUPT)
192 arm_gic_end_of_intr(raw_iar);
193
194 return rc;
195}
196
197void tftf_irq_setup(void)
198{
199 memset(spi_desc_table, 0, sizeof(spi_desc_table));
200 memset(ppi_desc_table, 0, sizeof(ppi_desc_table));
201 memset(sgi_desc_table, 0, sizeof(sgi_desc_table));
202 memset(&spurious_desc_handler, 0, sizeof(spurious_desc_handler));
203 init_spinlock(&spi_lock);
204}