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