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