blob: eb0e801136cd7ef7f62e45ccf92dfbe77a14d664 [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
#pragma once
#include <kernel/mp.h>
#include <stdbool.h>
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/types.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);
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);
zx_status_t register_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
zx_status_t 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 {
void* platform_ctx; // Allocation context owned by the platform
uint64_t tgt_addr; // The target write transaction physical address
bool allocated; // Whether or not this block has been allocated
uint base_irq_id; // The first IRQ id in the allocated block
uint num_irq; // The number of irqs in the allocated block
// 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;
} 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