blob: 24c7cc77bce859bb45abcc13f10d81ce2fd006fb [file] [log] [blame]
// Copyright 2016 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
#ifndef ZIRCON_KERNEL_DEV_INTERRUPT_INCLUDE_DEV_INTERRUPT_H_
#define ZIRCON_KERNEL_DEV_INTERRUPT_INCLUDE_DEV_INTERRUPT_H_
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <kernel/mp.h>
__BEGIN_CDECLS
#define MAX_MSI_IRQS 32u
enum interrupt_trigger_mode {
IRQ_TRIGGER_MODE_EDGE = 0,
IRQ_TRIGGER_MODE_LEVEL = 1,
};
enum interrupt_polarity {
IRQ_POLARITY_ACTIVE_HIGH = 0,
IRQ_POLARITY_ACTIVE_LOW = 1,
};
zx_status_t mask_interrupt(unsigned int vector);
zx_status_t unmask_interrupt(unsigned int vector);
zx_status_t deactivate_interrupt(unsigned int vector);
void shutdown_interrupts(void);
// Shutdown interrupts for the calling CPU.
//
// Should be called before powering off the calling CPU.
void shutdown_interrupts_curr_cpu(void);
// Configure the specified interrupt vector. If it is invoked, it muust be
// invoked prior to interrupt registration
zx_status_t configure_interrupt(unsigned int vector, enum interrupt_trigger_mode tm,
enum interrupt_polarity pol);
zx_status_t get_interrupt_config(unsigned int vector, enum interrupt_trigger_mode* tm,
enum interrupt_polarity* pol);
typedef interrupt_eoi (*int_handler)(void* arg);
// Registers a handler+arg to be called for the given interrupt vector. The handler may be called
// with internal spinlocks held and should not itself call register_int_handler. This handler may
// be serialized with other handlers.
// This can be called repeatedly to change the handler/arg for a given vector.
zx_status_t register_int_handler(unsigned int vector, int_handler handler, void* arg);
// Registers a handler+arg to be called for the given interrupt vector. Once this is used to set a
// handler it is an error to modify the vector again through this or register_int_handler.
// Registration via this method allows the interrupt manager to avoid needing to synchronize
// re-registrations with invocations, which can be much more efficient and avoid unneeded
// serialization of handlers.
zx_status_t register_permanent_int_handler(unsigned int vector, int_handler handler, void* arg);
// These return the [base, max] range of vectors that can be used with zx_interrupt syscalls
// This api will need to evolve if valid vector ranges later are not contiguous
uint32_t interrupt_get_base_vector(void);
uint32_t interrupt_get_max_vector(void);
bool is_valid_interrupt(unsigned int vector, uint32_t flags);
unsigned int remap_interrupt(unsigned int vector);
// sends an inter-processor interrupt
void interrupt_send_ipi(cpu_mask_t target, mp_ipi_t ipi);
// performs per-cpu initialization for the interrupt controller
void interrupt_init_percpu(void);
// A structure which holds the state of a block of IRQs allocated by the
// platform to be used for delivering MSI or MSI-X interrupts.
typedef struct msi_block {
uint64_t tgt_addr; // The target write transaction physical address
// The data which the device should write when triggering an IRQ. Note,
// only the lower 16 bits are used when the block has been allocated for MSI
// instead of MSI-X
uint32_t tgt_data;
uint32_t base_irq_id; // The first IRQ id in the allocated block
uint32_t num_irq; // The number of irqs in the allocated block
bool allocated; // Whether or not this block has been allocated
bool is_32bit; // 32 bit if true, 64 bit otherwise
} msi_block_t;
// Methods used to determine if a platform supports MSI or not, and if so,
// whether or not the platform can mask individual MSI vectors at the
// platform level.
//
// If the platform supports MSI, it must supply valid implementations of
// msi_alloc_block, msi_free_block, and msi_register_handler.
//
// If the platform supports MSI masking, it must supply a valid
// implementation of MaskUnmaskMsi.
bool msi_is_supported(void);
bool msi_supports_masking(void);
void msi_mask_unmask(const msi_block_t* block, uint msi_id, bool mask);
// Method used for platform allocation of blocks of MSI and MSI-X compatible
// IRQ targets.
//
// @param requested_irqs The total number of irqs being requested.
// @param can_target_64bit True if the target address of the MSI block can
// be located past the 4GB boundary. False if the target address must be
// in low memory.
// @param is_msix True if this request is for an MSI-X compatible block. False
// for plain old MSI.
// @param out_block A pointer to the allocation bookkeeping to be filled out
// upon successful allocation of the requested block of IRQs.
//
// @return A status code indicating the success or failure of the operation.
zx_status_t msi_alloc_block(uint requested_irqs, bool can_target_64bit, bool is_msix,
msi_block_t* out_block);
// Method used to free a block of MSI IRQs previously allocated by msi_alloc_block().
// This does not unregister IRQ handlers.
//
// @param block A pointer to the block to be returned
void msi_free_block(msi_block_t* block);
// Register a handler function for a given msi_id within an msi_block_t. Passing a
// NULL handler will effectively unregister a handler for a given msi_id within the
// block.
void msi_register_handler(const msi_block_t* block, uint msi_id, int_handler handler, void* ctx);
__END_CDECLS
#endif // ZIRCON_KERNEL_DEV_INTERRUPT_INCLUDE_DEV_INTERRUPT_H_