blob: 6df314d013f38fac877d12ef316257b7bf44dc39 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <err.h>
#include <pdev/interrupt.h>
#include <lk/init.h>
#define ARM_MAX_INT 1024
static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE;
static struct int_handler_struct int_handler_table[ARM_MAX_INT];
struct int_handler_struct* pdev_get_int_handler(unsigned int vector)
{
DEBUG_ASSERT(vector < ARM_MAX_INT);
return &int_handler_table[vector];
}
void register_int_handler(unsigned int vector, int_handler handler, void* arg)
{
struct int_handler_struct *h;
spin_lock_saved_state_t state;
if (!is_valid_interrupt(vector, 0)) {
panic("register_int_handler: vector out of range %u\n", vector);
}
spin_lock_save(&lock, &state, SPIN_LOCK_FLAG_INTERRUPTS);
h = pdev_get_int_handler(vector);
h->handler = handler;
h->arg = arg;
spin_unlock_restore(&lock, state, SPIN_LOCK_FLAG_INTERRUPTS);
}
static status_t default_mask(unsigned int vector) {
return ZX_ERR_NOT_CONFIGURED;
}
static status_t default_unmask(unsigned int vector) {
return ZX_ERR_NOT_CONFIGURED;
}
static status_t default_configure(unsigned int vector,
enum interrupt_trigger_mode tm,
enum interrupt_polarity pol) {
return ZX_ERR_NOT_CONFIGURED;
}
static status_t default_get_config(unsigned int vector,
enum interrupt_trigger_mode* tm,
enum interrupt_polarity* pol) {
return ZX_ERR_NOT_CONFIGURED;
}
static bool default_is_valid(unsigned int vector, uint32_t flags) {
return false;
}
static unsigned int default_remap(unsigned int vector) {
return 0;
}
static status_t default_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) {
return ZX_ERR_NOT_CONFIGURED;
}
static void default_init_percpu_early(void) {
}
static void default_init_percpu(void) {
}
static enum handler_return default_handle_irq(iframe* frame) {
return INT_NO_RESCHEDULE;
}
static enum handler_return default_handle_fiq(iframe* frame) {
return INT_NO_RESCHEDULE;
}
static void default_shutdown(void) {
}
static const struct pdev_interrupt_ops default_ops = {
.mask = default_mask,
.unmask = default_unmask,
.configure = default_configure,
.get_config = default_get_config,
.is_valid = default_is_valid,
.remap = default_remap,
.send_ipi = default_send_ipi,
.init_percpu_early = default_init_percpu_early,
.init_percpu = default_init_percpu,
.handle_irq = default_handle_irq,
.handle_fiq = default_handle_fiq,
.shutdown = default_shutdown,
};
static const struct pdev_interrupt_ops* intr_ops = &default_ops;
status_t mask_interrupt(unsigned int vector) {
return intr_ops->mask(vector);
}
status_t unmask_interrupt(unsigned int vector) {
return intr_ops->unmask(vector);
}
status_t configure_interrupt(unsigned int vector, enum interrupt_trigger_mode tm,
enum interrupt_polarity pol) {
return intr_ops->configure(vector, tm, pol);
}
status_t get_interrupt_config(unsigned int vector, enum interrupt_trigger_mode* tm,
enum interrupt_polarity* pol) {
return intr_ops->get_config(vector, tm, pol);
}
bool is_valid_interrupt(unsigned int vector, uint32_t flags) {
return intr_ops->is_valid(vector, flags);
}
unsigned int remap_interrupt(unsigned int vector) {
return intr_ops->remap(vector);
}
status_t interrupt_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) {
return intr_ops->send_ipi(target, ipi);
}
void interrupt_init_percpu(void) {
intr_ops->init_percpu();
}
enum handler_return platform_irq(iframe* frame) {
return intr_ops->handle_irq(frame);
}
enum handler_return platform_fiq(iframe* frame) {
return intr_ops->handle_fiq(frame);
}
void pdev_register_interrupts(const struct pdev_interrupt_ops* ops) {
intr_ops = ops;
smp_mb();
}
static void interrupt_init_percpu_early(uint level) {
intr_ops->init_percpu_early();
}
void shutdown_interrupts(void) {
intr_ops->shutdown();
}
LK_INIT_HOOK_FLAGS(interrupt_init_percpu_early, interrupt_init_percpu_early, LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_FLAG_SECONDARY_CPUS);