| // 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_ |