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