1 // Copyright 2016 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 #pragma once 8 9 #include <kernel/mp.h> 10 #include <stdbool.h> 11 #include <sys/types.h> 12 #include <zircon/compiler.h> 13 #include <zircon/types.h> 14 15 __BEGIN_CDECLS 16 17 #define MAX_MSI_IRQS 32u 18 19 enum interrupt_trigger_mode { 20 IRQ_TRIGGER_MODE_EDGE = 0, 21 IRQ_TRIGGER_MODE_LEVEL = 1, 22 }; 23 24 enum interrupt_polarity { 25 IRQ_POLARITY_ACTIVE_HIGH = 0, 26 IRQ_POLARITY_ACTIVE_LOW = 1, 27 }; 28 29 zx_status_t mask_interrupt(unsigned int vector); 30 zx_status_t unmask_interrupt(unsigned int vector); 31 32 void shutdown_interrupts(void); 33 34 // Shutdown interrupts for the calling CPU. 35 // 36 // Should be called before powering off the calling CPU. 37 void shutdown_interrupts_curr_cpu(void); 38 39 // Configure the specified interrupt vector. If it is invoked, it muust be 40 // invoked prior to interrupt registration 41 zx_status_t configure_interrupt(unsigned int vector, 42 enum interrupt_trigger_mode tm, 43 enum interrupt_polarity pol); 44 45 zx_status_t get_interrupt_config(unsigned int vector, 46 enum interrupt_trigger_mode* tm, 47 enum interrupt_polarity* pol); 48 49 typedef interrupt_eoi (*int_handler)(void* arg); 50 51 zx_status_t register_int_handler(unsigned int vector, int_handler handler, void* arg); 52 53 // These return the [base, max] range of vectors that can be used with zx_interrupt syscalls 54 // This api will need to evolve if valid vector ranges later are not contiguous 55 uint32_t interrupt_get_base_vector(void); 56 uint32_t interrupt_get_max_vector(void); 57 58 bool is_valid_interrupt(unsigned int vector, uint32_t flags); 59 60 unsigned int remap_interrupt(unsigned int vector); 61 62 // sends an inter-processor interrupt 63 zx_status_t interrupt_send_ipi(cpu_mask_t target, mp_ipi_t ipi); 64 65 // performs per-cpu initialization for the interrupt controller 66 void interrupt_init_percpu(void); 67 68 // A structure which holds the state of a block of IRQs allocated by the 69 // platform to be used for delivering MSI or MSI-X interrupts. 70 typedef struct msi_block { 71 void* platform_ctx; // Allocation context owned by the platform 72 uint64_t tgt_addr; // The target write transaction physical address 73 bool allocated; // Whether or not this block has been allocated 74 uint base_irq_id; // The first IRQ id in the allocated block 75 uint num_irq; // The number of irqs in the allocated block 76 77 // The data which the device should write when triggering an IRQ. Note, 78 // only the lower 16 bits are used when the block has been allocated for MSI 79 // instead of MSI-X 80 uint32_t tgt_data; 81 } msi_block_t; 82 83 // Methods used to determine if a platform supports MSI or not, and if so, 84 // whether or not the platform can mask individual MSI vectors at the 85 // platform level. 86 // 87 // If the platform supports MSI, it must supply valid implementations of 88 // msi_alloc_block, msi_free_block, and msi_register_handler. 89 // 90 // If the platform supports MSI masking, it must supply a valid 91 // implementation of MaskUnmaskMsi. 92 bool msi_is_supported(void); 93 bool msi_supports_masking(void); 94 void msi_mask_unmask(const msi_block_t* block, uint msi_id, bool mask); 95 96 // Method used for platform allocation of blocks of MSI and MSI-X compatible 97 // IRQ targets. 98 // 99 // @param requested_irqs The total number of irqs being requested. 100 // @param can_target_64bit True if the target address of the MSI block can 101 // be located past the 4GB boundary. False if the target address must be 102 // in low memory. 103 // @param is_msix True if this request is for an MSI-X compatible block. False 104 // for plain old MSI. 105 // @param out_block A pointer to the allocation bookkeeping to be filled out 106 // upon successful allocation of the requested block of IRQs. 107 // 108 // @return A status code indicating the success or failure of the operation. 109 zx_status_t msi_alloc_block(uint requested_irqs, 110 bool can_target_64bit, 111 bool is_msix, 112 msi_block_t* out_block); 113 114 // Method used to free a block of MSI IRQs previously allocated by msi_alloc_block(). 115 // This does not unregister IRQ handlers. 116 // 117 // @param block A pointer to the block to be returned 118 void msi_free_block(msi_block_t* block); 119 120 // Register a handler function for a given msi_id within an msi_block_t. Passing a 121 // NULL handler will effectively unregister a handler for a given msi_id within the 122 // block. 123 void msi_register_handler(const msi_block_t* block, uint msi_id, int_handler handler, void *ctx); 124 __END_CDECLS 125