1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <pdev/interrupt.h>
8 
9 #include <err.h>
10 #include <kernel/auto_lock.h>
11 #include <kernel/spinlock.h>
12 #include <lk/init.h>
13 #include <zircon/types.h>
14 
15 #define ARM_MAX_INT 1024
16 
17 static SpinLock lock;
18 static struct int_handler_struct int_handler_table[ARM_MAX_INT];
19 
pdev_get_int_handler(unsigned int vector)20 struct int_handler_struct* pdev_get_int_handler(unsigned int vector) {
21     DEBUG_ASSERT(vector < ARM_MAX_INT);
22     return &int_handler_table[vector];
23 }
24 
register_int_handler(unsigned int vector,int_handler handler,void * arg)25 zx_status_t register_int_handler(unsigned int vector, int_handler handler, void* arg) {
26     if (!is_valid_interrupt(vector, 0)) {
27         return ZX_ERR_INVALID_ARGS;
28     }
29 
30     AutoSpinLock guard(&lock);
31 
32     auto h = pdev_get_int_handler(vector);
33     if (handler && h->handler) {
34         return ZX_ERR_ALREADY_BOUND;
35     }
36     h->handler = handler;
37     h->arg = arg;
38 
39     return ZX_OK;
40 }
41 
default_mask(unsigned int vector)42 static zx_status_t default_mask(unsigned int vector) {
43     return ZX_ERR_NOT_CONFIGURED;
44 }
45 
default_unmask(unsigned int vector)46 static zx_status_t default_unmask(unsigned int vector) {
47     return ZX_ERR_NOT_CONFIGURED;
48 }
49 
default_configure(unsigned int vector,enum interrupt_trigger_mode tm,enum interrupt_polarity pol)50 static zx_status_t default_configure(unsigned int vector,
51                                      enum interrupt_trigger_mode tm,
52                                      enum interrupt_polarity pol) {
53     return ZX_ERR_NOT_CONFIGURED;
54 }
55 
default_get_config(unsigned int vector,enum interrupt_trigger_mode * tm,enum interrupt_polarity * pol)56 static zx_status_t default_get_config(unsigned int vector,
57                                       enum interrupt_trigger_mode* tm,
58                                       enum interrupt_polarity* pol) {
59     return ZX_ERR_NOT_CONFIGURED;
60 }
61 
default_is_valid(unsigned int vector,uint32_t flags)62 static bool default_is_valid(unsigned int vector, uint32_t flags) {
63     return false;
64 }
default_remap(unsigned int vector)65 static unsigned int default_remap(unsigned int vector) {
66     return 0;
67 }
68 
default_send_ipi(cpu_mask_t target,mp_ipi_t ipi)69 static zx_status_t default_send_ipi(cpu_mask_t target, mp_ipi_t ipi) {
70     return ZX_ERR_NOT_CONFIGURED;
71 }
72 
default_init_percpu_early()73 static void default_init_percpu_early() {
74 }
75 
default_init_percpu()76 static void default_init_percpu() {
77 }
78 
default_handle_irq(iframe * frame)79 static void default_handle_irq(iframe* frame) {
80 }
81 
default_handle_fiq(iframe * frame)82 static void default_handle_fiq(iframe* frame) {
83 }
84 
default_shutdown()85 static void default_shutdown() {
86 }
87 
default_shutdown_cpu()88 static void default_shutdown_cpu() {
89 }
90 
default_msi_is_supported()91 static bool default_msi_is_supported() {
92     return false;
93 }
94 
default_msi_supports_masking()95 static bool default_msi_supports_masking() {
96     return false;
97 }
98 
default_msi_alloc_block(uint requested_irqs,bool can_target_64bit,bool is_msix,msi_block_t * out_block)99 static zx_status_t default_msi_alloc_block(uint requested_irqs, bool can_target_64bit,
100                                            bool is_msix, msi_block_t* out_block) {
101     return ZX_ERR_NOT_CONFIGURED;
102 }
103 
default_msi_free_block(msi_block_t * block)104 static void default_msi_free_block(msi_block_t* block) {
105 }
106 
default_msi_register_handler(const msi_block_t * block,uint msi_id,int_handler handler,void * ctx)107 static void default_msi_register_handler(const msi_block_t* block, uint msi_id, int_handler handler, void* ctx) {
108 }
109 
default_msi_mask_unmask(const msi_block_t * block,uint msi_id,bool mask)110 static void default_msi_mask_unmask(const msi_block_t* block, uint msi_id, bool mask) {
111 }
112 
default_get_base_vector()113 static uint32_t default_get_base_vector() {
114     return 0;
115 }
116 
default_get_max_vector()117 static uint32_t default_get_max_vector() {
118     return 0;
119 }
120 
121 // by default, most interrupt operations for pdev/arm are implemented in the gic specific source
122 // files and accessed via configuring this pointer table at runtime. By default most of these
123 // are merely empty stubs.
124 static const struct pdev_interrupt_ops default_ops = {
125     .mask = default_mask,
126     .unmask = default_unmask,
127     .configure = default_configure,
128     .get_config = default_get_config,
129     .is_valid = default_is_valid,
130     .get_base_vector = default_get_base_vector,
131     .get_max_vector = default_get_max_vector,
132     .remap = default_remap,
133     .send_ipi = default_send_ipi,
134     .init_percpu_early = default_init_percpu_early,
135     .init_percpu = default_init_percpu,
136     .handle_irq = default_handle_irq,
137     .handle_fiq = default_handle_fiq,
138     .shutdown = default_shutdown,
139     .shutdown_cpu = default_shutdown_cpu,
140     .msi_is_supported = default_msi_is_supported,
141     .msi_supports_masking = default_msi_supports_masking,
142     .msi_mask_unmask = default_msi_mask_unmask,
143     .msi_alloc_block = default_msi_alloc_block,
144     .msi_free_block = default_msi_free_block,
145     .msi_register_handler = default_msi_register_handler,
146 };
147 
148 static const struct pdev_interrupt_ops* intr_ops = &default_ops;
149 
mask_interrupt(unsigned int vector)150 zx_status_t mask_interrupt(unsigned int vector) {
151     return intr_ops->mask(vector);
152 }
153 
unmask_interrupt(unsigned int vector)154 zx_status_t unmask_interrupt(unsigned int vector) {
155     return intr_ops->unmask(vector);
156 }
157 
configure_interrupt(unsigned int vector,enum interrupt_trigger_mode tm,enum interrupt_polarity pol)158 zx_status_t configure_interrupt(unsigned int vector, enum interrupt_trigger_mode tm,
159                                 enum interrupt_polarity pol) {
160     return intr_ops->configure(vector, tm, pol);
161 }
162 
get_interrupt_config(unsigned int vector,enum interrupt_trigger_mode * tm,enum interrupt_polarity * pol)163 zx_status_t get_interrupt_config(unsigned int vector, enum interrupt_trigger_mode* tm,
164                                  enum interrupt_polarity* pol) {
165     return intr_ops->get_config(vector, tm, pol);
166 }
167 
interrupt_get_base_vector()168 uint32_t interrupt_get_base_vector() {
169     return intr_ops->get_base_vector();
170 }
171 
interrupt_get_max_vector()172 uint32_t interrupt_get_max_vector() {
173     return intr_ops->get_max_vector();
174 }
175 
is_valid_interrupt(unsigned int vector,uint32_t flags)176 bool is_valid_interrupt(unsigned int vector, uint32_t flags) {
177     return intr_ops->is_valid(vector, flags);
178 }
179 
remap_interrupt(unsigned int vector)180 unsigned int remap_interrupt(unsigned int vector) {
181     return intr_ops->remap(vector);
182 }
183 
interrupt_send_ipi(cpu_mask_t target,mp_ipi_t ipi)184 zx_status_t interrupt_send_ipi(cpu_mask_t target, mp_ipi_t ipi) {
185     return intr_ops->send_ipi(target, ipi);
186 }
187 
interrupt_init_percpu()188 void interrupt_init_percpu() {
189     intr_ops->init_percpu();
190 }
191 
platform_irq(iframe * frame)192 void platform_irq(iframe* frame) {
193     intr_ops->handle_irq(frame);
194 }
195 
platform_fiq(iframe * frame)196 void platform_fiq(iframe* frame) {
197     intr_ops->handle_fiq(frame);
198 }
199 
pdev_register_interrupts(const struct pdev_interrupt_ops * ops)200 void pdev_register_interrupts(const struct pdev_interrupt_ops* ops) {
201     intr_ops = ops;
202     smp_mb();
203 }
204 
interrupt_init_percpu_early(uint level)205 static void interrupt_init_percpu_early(uint level) {
206     intr_ops->init_percpu_early();
207 }
208 
shutdown_interrupts()209 void shutdown_interrupts() {
210     intr_ops->shutdown();
211 }
212 
shutdown_interrupts_curr_cpu()213 void shutdown_interrupts_curr_cpu() {
214     intr_ops->shutdown_cpu();
215 }
216 
msi_is_supported()217 bool msi_is_supported() {
218     return intr_ops->msi_is_supported();
219 }
220 
msi_supports_masking()221 bool msi_supports_masking() {
222     return intr_ops->msi_supports_masking();
223 }
224 
msi_mask_unmask(const msi_block_t * block,uint msi_id,bool mask)225 void msi_mask_unmask(const msi_block_t* block, uint msi_id, bool mask) {
226     intr_ops->msi_mask_unmask(block, msi_id, mask);
227 }
228 
msi_alloc_block(uint requested_irqs,bool can_target_64bit,bool is_msix,msi_block_t * out_block)229 zx_status_t msi_alloc_block(uint requested_irqs, bool can_target_64bit,
230                             bool is_msix, msi_block_t* out_block) {
231     return intr_ops->msi_alloc_block(requested_irqs, can_target_64bit, is_msix, out_block);
232 }
233 
msi_free_block(msi_block_t * block)234 void msi_free_block(msi_block_t* block) {
235     intr_ops->msi_free_block(block);
236 }
237 
msi_register_handler(const msi_block_t * block,uint msi_id,int_handler handler,void * ctx)238 void msi_register_handler(const msi_block_t* block, uint msi_id, int_handler handler, void* ctx) {
239     intr_ops->msi_register_handler(block, msi_id, handler, ctx);
240 }
241 
242 LK_INIT_HOOK_FLAGS(interrupt_init_percpu_early, interrupt_init_percpu_early, LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_FLAG_SECONDARY_CPUS);
243