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