1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 // Platform routines for handling hardware IRQs.
6 //
7 // These routines presume that the interrupt controller implements automatic
8 // masking of all interrupts until the end of the handler, and selectively
9 // extending that masking after the end of the interrupt handler for interrupts
10 // forwarded to a VM, similar to an ARM GICv2 or later with EOImode=1. If the
11 // interrupt controller does not implement these semantics, the platform driver
12 // must emulate them.
13 //
14 // The calling code should not assign any particular meaning to IRQ numbers,
15 // beyond assuming that they are not greater than the value returned by
16 // platform_irq_max().
17 //
18 // Note that the platform driver may handle some IRQs internally; for example,
19 // to signal IPIs, or to support a debug console. Such IRQs are not exposed to
20 // this interface.
21 
22 // Obtain the maximum valid IRQ number.
23 //
24 // This returns an irq_t value which is the upper bound for valid irq_t values
25 // on this platform. Note that it is not necessarily the case that all irq_t
26 // values less than this value are valid; see platform_irq_check() below.
27 //
28 // This function may be called by a default-priority boot_cold_init handler. If
29 // the driver needs initialisation to determine this value, it should subscribe
30 // to boot_cold_init with a positive priority.
31 irq_t
32 platform_irq_max(void);
33 
34 // Check whether a specific IRQ number is valid for handler registration.
35 //
36 // This function returns ERROR_DENIED for any IRQ number that is reserved by the
37 // platform driver or by a higher privileged level, ERROR_ARGUMENT_INVALID for
38 // any IRQ number that is greater than the value returned by platform_irq_max()
39 // or is otherwise known not to be implemented by the hardware, and OK for any
40 // other IRQ number.
41 error_t
42 platform_irq_check(irq_t irq);
43 
44 // Check whether a specific IRQ number needs to use the percpu and/or local
45 // variants of the enable and disable APIs.
46 //
47 // Note that a true result does not necessarily mean that the IRQ number can be
48 // used independently on multiple CPUs.
49 //
50 // This function must only be called on IRQ numbers that have previously
51 // returned an OK result from platform_irq_check().
52 bool
53 platform_irq_is_percpu(irq_t irq);
54 
55 // Enable delivery of a specified IRQ, which must not be per-CPU.
56 void
57 platform_irq_enable_shared(irq_t irq);
58 
59 // Enable delivery of a specified per-CPU IRQ, on the calling CPU.
60 void
61 platform_irq_enable_local(irq_t irq) REQUIRE_PREEMPT_DISABLED;
62 
63 // Enable delivery of a specified per-CPU IRQ, on the specified CPU.
64 //
65 // Note that some platforms are unable to implement this function if the CPU
66 // index is not that of the calling CPU.
67 void
68 platform_irq_enable_percpu(irq_t irq, cpu_index_t cpu);
69 
70 // Disable delivery of a specified IRQ, which must not be per-CPU.
71 //
72 // On some platforms, this function must busy-wait until the IRQ controller has
73 // acknowledged that the interrupt is disabled.
74 void
75 platform_irq_disable_shared(irq_t irq);
76 
77 // Disable delivery of a specified per-CPU IRQ, on the calling CPU.
78 //
79 // On some platforms, this function must busy-wait until the IRQ controller has
80 // acknowledged that the interrupt is disabled.
81 void
82 platform_irq_disable_local(irq_t irq) REQUIRE_PREEMPT_DISABLED;
83 
84 // Disable delivery of a specified per-CPU IRQ, on the calling CPU, without
85 // waiting for the physical interrupt controller to acknowledge that delivery is
86 // disabled.
87 //
88 // This may be called if the in-hypervisor driver for the IRQ needs to disable
89 // it in performance-critical code (e.g. a context switch) and is prepared to
90 // handle any spurious interrupts that may occur as a result of not waiting.
91 void
92 platform_irq_disable_local_nowait(irq_t irq) REQUIRE_PREEMPT_DISABLED;
93 
94 // Disable delivery of a specified per-CPU IRQ, on the specified CPU.
95 //
96 // On some platforms, this function must busy-wait until the IRQ controller has
97 // acknowledged that the interrupt is disabled.
98 //
99 // Note that some platforms are unable to implement this function if the CPU
100 // index is not that of the calling CPU.
101 void
102 platform_irq_disable_percpu(irq_t irq, cpu_index_t cpu);
103 
104 // Acknowledge and activate an IRQ.
105 //
106 // This function acknowledges the highest-priority pending IRQ and returns its
107 // IRQ number. If there are multiple IRQs with equal highest priority, it
108 // selects one to acknowledge arbitrarily. Delivery of the acknowledged IRQ is
109 // disabled until the next platform_irq_deactivate() call for that IRQ, unless a
110 // platform-specific mechanism deactivates the IRQ.
111 //
112 // If there is an interrupt to acknowledge, but it is directed to the platform
113 // driver itself (e.g. to signal an IPI), the result will be set to ERROR_RETRY.
114 //
115 // If there are no pending interrupts left to acknowledge, the result will be
116 // set to ERROR_IDLE.
117 //
118 // This function must only be called from an interrupt handler. If it returns an
119 // IRQ number, that number must be passed to platform_irq_priority_drop() before
120 // the interrupt handler returns.
121 irq_result_t
122 platform_irq_acknowledge(void) REQUIRE_PREEMPT_DISABLED;
123 
124 // De-prioritise an acknowledged IRQ.
125 //
126 // This function lowers the effective priority of an acknowledged IRQ, allowing
127 // its handling to be deferred until after the interrupt handler returns without
128 // blocking delivery of further interrupts.
129 //
130 // This must only be called for IRQs returned by platform_irq_acknowledge().
131 // Additionally, the specified IRQ must be the one most recently returned by
132 // that function on the current physical CPU, after excluding any IRQs that have
133 // already been passed to this function.
134 //
135 // This call must be followed (eventually) by a platform_irq_deactivate() call,
136 // unless the IRQ is forwarded to a VCPU and the platform provides a mechanism
137 // for forwarded IRQs to be deactivated directly by the VCPU.
138 void
139 platform_irq_priority_drop(irq_t irq);
140 
141 // Deactivate an acknowledged IRQ.
142 //
143 // This function re-enables delivery of the specified interrupt after it was
144 // previously de-prioritised by platform_irq_priority_drop(). For a per-CPU IRQ
145 // it must be called on the same physical CPU that acknowledged the IRQ;
146 // otherwise it may be called on any CPU.
147 //
148 // Note that the platform may provide an alternative mechanism for performing
149 // this operation for IRQs that are forwarded to a VCPU via a hardware virtual
150 // IRQ delivery mechanism. In that case, the hypervisor need not call this
151 // function for any forwarded IRQ that uses that mechanism.
152 void
153 platform_irq_deactivate(irq_t irq);
154 
155 // Deactivate an acknowledged per-CPU IRQ on a specified physical CPU.
156 //
157 // This works the same way as platform_irq_deactivate(), but allows per-CPU
158 // IRQs acknowledged on one physical CPU to be deactivated from a different
159 // physical CPU.
160 //
161 // Note that this may be slower than platform_irq_deactivate() for such IRQs,
162 // and may not be possible to implement without IPIs.
163 void
164 platform_irq_deactivate_percpu(irq_t irq, cpu_index_t cpu);
165 
166 // Set trigger of per-CPU IRQ on a specified physical CPU.
167 // FIXME: add more details descriptions.
168 irq_trigger_result_t
169 platform_irq_set_mode_percpu(irq_t irq, irq_trigger_t trigger, cpu_index_t cpu);
170 
171 // Support for message-signalled interrupts. These are dynamically allocated
172 // and programmed into the source devices, possibly after being mapped to a
173 // hardware ID that is tagged with a source device identifier (e.g. a PCI bus
174 // responder ID).
175 #if IRQ_HAS_MSI
176 
177 // The base of the platform's MSI range.
178 //
179 // The platform is presumed to support message-signalled interrupts only for
180 // some contiguous limited range of IRQ numbers. This constant must be set to
181 // the first IRQ number in that range.
182 extern const irq_t platform_irq_msi_base;
183 
184 // Obtain the platform's maximum MSI number.
185 //
186 // The platform is presumed to support message-signalled interrupts only for
187 // some contiguous limited range of IRQ numbers. This function should return
188 // the last IRQ number in that range.
189 //
190 // Note that the IRQ framework will configure a bitmap allocator covering the
191 // whole MSI ID range. Platforms that support a very large MSI range may
192 // constrain this to less than the true value to prevent the IRQ framework
193 // unnecessarily allocating a large amount of memory.
194 irq_t
195 platform_irq_msi_max(void);
196 
197 // Obtain a list of known MSI source devices.
198 //
199 // The index is the controller index, which must be between 0 and
200 // PLATFORM_MSI_CONTROLLER_COUNT.
201 //
202 // These are the hardware-tagged devices attached to the specified MSI
203 // controller. For each device, this reports the tag, and the maximum number of
204 // vectors that may be required by the device. If this number is not known, 32
205 // is probably a reasonable choice.
206 //
207 // If the platform does not support hardware-tagged devices, it should return a
208 // single element with id 0.
209 extern const platform_msi_controller_t *
210 platform_irq_msi_devices(platform_msi_controller_id_t ctrl_index);
211 
212 #endif // IRQ_HAS_MSI
213 
214 // Query the IRQ delivery class of a CPU.
215 //
216 // In configurations where the virtual interrupt controller implements automatic
217 // load balancing of interrupts (e.g. GICv3 1-of-N delivery mode), the CPUs can
218 // be divided into two classes, and load-balanced IRQs can be separately enabled
219 // for each class.
220 //
221 // This is similar to a feature implemented in hardware by the GIC-600 and
222 // GIC-700; on platforms that have those interrupt controllers, this function
223 // should reflect the classes configured in the physical GICR_CLASSR registers
224 // (which are only accessible to EL3).
225 //
226 // On platforms where this distinction is not meaningful, this function should
227 // return 0U.
228 index_t
229 platform_irq_cpu_class(cpu_index_t cpu);
230