1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Copyright (c) 2016-2019, Linaro Limited 4 */ 5 #ifndef __KERNEL_INTERRUPT_H 6 #define __KERNEL_INTERRUPT_H 7 8 #include <dt-bindings/interrupt-controller/irq.h> 9 #include <kernel/dt_driver.h> 10 #include <mm/core_memprot.h> 11 #include <sys/queue.h> 12 #include <tee_api_types.h> 13 #include <types_ext.h> 14 #include <util.h> 15 16 #define ITRF_TRIGGER_LEVEL BIT(0) 17 #define ITRF_SHARED BIT(1) 18 19 /* Forward the interrupt only to the current CPU */ 20 #define ITR_CPU_MASK_TO_THIS_CPU BIT(31) 21 /* Forward the interrupt to all CPUs except the current CPU */ 22 #define ITR_CPU_MASK_TO_OTHER_CPUS BIT(30) 23 24 struct itr_handler; 25 26 /* 27 * struct itr_chip - Interrupt controller 28 * 29 * @ops Operation callback functions 30 * @name Controller name, for debug purpose 31 * @handlers Registered handlers list head 32 * @dt_get_irq Device tree node parsing function 33 */ 34 struct itr_chip { 35 const struct itr_ops *ops; 36 const char *name; 37 SLIST_HEAD(, itr_handler) handlers; 38 /* 39 * dt_get_irq - parse a device tree interrupt property 40 * 41 * @properties Big-endian interrupt property array from device tree 42 * @count number of elements in @properties 43 * @type If not NULL, output interrupt type (IRQ_TYPE_* defines) 44 * or IRQ_TYPE_NONE if unknown 45 * @prio If not NULL, output interrupt priority value or 0 if unknown 46 * 47 * This handler is required to support dt_get_irq_type_prio() and 48 * dt_get_irq() API function for interrupt consumers manually 49 * retrieving trigger type and/or priority from the device tree. 50 */ 51 int (*dt_get_irq)(const uint32_t *properties, int count, uint32_t *type, 52 uint32_t *prio); 53 }; 54 55 /* 56 * struct itr_ops - Interrupt controller operations 57 * @configure Configure an interrupt 58 * @enable Enable an interrupt 59 * @disable Disable an interrupt 60 * @mask Mask an interrupt, may be called from an interrupt context 61 * @unmask Unmask an interrupt, may be called from an interrupt context 62 * @raise_pi Raise per-cpu interrupt or NULL if not applicable 63 * @raise_sgi Raise a SGI or NULL if not applicable to that controller 64 * @set_affinity Set interrupt/cpu affinity or NULL if not applicable 65 * @set_wake Enable/disable power-management wake-on of an interrupt or NULL 66 * if not applicable 67 * 68 * Handlers @enable, @disable, @mask and @unmask are mandated. Handlers 69 * @mask and @unmask have unpaged memory constraints. These requirements are 70 * verified by itr_chip_init() and itr_chip_dt_only_init(). 71 * 72 * Handler @configure is needed for interrupt providers which do not rely on 73 * DT for consumers interrupt configuration, that is interrupt consumers using 74 * interrupt_configure() or friends (interrupt_add_handler(), 75 * interrupt_add_configure_handler(), interrupt_add_handler_with_chip(), 76 * etc...). 77 */ 78 struct itr_ops { 79 void (*configure)(struct itr_chip *chip, size_t it, uint32_t type, 80 uint32_t prio); 81 void (*enable)(struct itr_chip *chip, size_t it); 82 void (*disable)(struct itr_chip *chip, size_t it); 83 void (*mask)(struct itr_chip *chip, size_t it); 84 void (*unmask)(struct itr_chip *chip, size_t it); 85 void (*raise_pi)(struct itr_chip *chip, size_t it); 86 void (*raise_sgi)(struct itr_chip *chip, size_t it, 87 uint32_t cpu_mask); 88 void (*set_affinity)(struct itr_chip *chip, size_t it, 89 uint8_t cpu_mask); 90 void (*set_wake)(struct itr_chip *chip, size_t it, bool on); 91 }; 92 93 /* 94 * struct itr_desc - Interrupt description 95 * @chip Interrupt controller reference 96 * @itr_num Interrupt number 97 * 98 * This struct is used for binding interrupt device data between 99 * drivers when using DT_DRIVERS means. See itr_dt_get_func type 100 * definition. 101 */ 102 struct itr_desc { 103 struct itr_chip *chip; 104 size_t itr_num; 105 }; 106 107 /* Interrupt handler return value */ 108 enum itr_return { 109 ITRR_NONE, 110 ITRR_HANDLED, 111 }; 112 113 /* Interrupt handler signature */ 114 typedef enum itr_return (*itr_handler_t)(struct itr_handler *h); 115 116 /* 117 * struct itr_handler - Interrupt handler reference 118 * @it Interrupt number 119 * @flags Property bit flags (ITRF_*) or 0 120 * @data Private data for that interrupt handler 121 * @chip Interrupt controller chip device 122 * @link Reference in controller handler list 123 */ 124 struct itr_handler { 125 size_t it; 126 uint32_t flags; 127 itr_handler_t handler; 128 void *data; 129 struct itr_chip *chip; 130 SLIST_ENTRY(itr_handler) link; 131 }; 132 133 #define ITR_HANDLER(_chip, _itr_num, _flags, _fn, _priv) \ 134 ((struct itr_handler){ \ 135 .chip = (_chip), .it = (_itr_num), .flags = (_flags), \ 136 .handler = (_fn), .data = (_priv), \ 137 }) 138 139 /* 140 * Initialise an interrupt controller handle to be used only with the DT 141 * @chip Interrupt controller 142 */ 143 TEE_Result itr_chip_dt_only_init(struct itr_chip *chip); 144 145 /* 146 * Initialise an interrupt controller handle 147 * @chip Interrupt controller 148 */ 149 TEE_Result itr_chip_init(struct itr_chip *chip); 150 151 /* 152 * Initialise main interrupt controller driver 153 * @data Main controller main data reference to register 154 */ 155 void interrupt_main_init(struct itr_chip *data); 156 157 /* Retrieve main interrupt controller reference */ 158 struct itr_chip *interrupt_get_main_chip(void); 159 /* Retrieve main interrupt controller reference, or NULL on failure */ 160 struct itr_chip *interrupt_get_main_chip_may_fail(void); 161 162 #ifdef CFG_DT 163 /* 164 * Get the DT interrupt property at @node. In the DT an interrupt property can 165 * specify additional information which can be retrieved with @type and @prio. 166 * 167 * @fdt reference to the Device Tree 168 * @node is the node offset to read the interrupt property from 169 * @type interrupt type (IRQ_TYPE_* defines) if specified by interrupt property 170 * or IRQ_TYPE_NONE if not. Can be NULL if not needed 171 * @prio interrupt priority if specified by interrupt property or 0 if not. Can 172 * be NULL if not needed 173 * 174 * Returns the interrupt number if value >= 0 175 * otherwise DT_INFO_INVALID_INTERRUPT 176 */ 177 int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type, 178 uint32_t *prio); 179 180 /* 181 * Get the DT interrupt property at @node 182 */ 183 static inline int dt_get_irq(const void *fdt, int node) 184 { 185 return dt_get_irq_type_prio(fdt, node, NULL, NULL); 186 } 187 #endif 188 189 /* 190 * __weak overridable function which is called when a secure interrupt is 191 * received. The default function calls panic() immediately, platforms which 192 * expects to receive secure interrupts should override this function. 193 */ 194 void interrupt_main_handler(void); 195 196 /* 197 * Interrupt controller chip API functions 198 */ 199 200 /* 201 * interrupt_call_handlers() - Call registered handlers for an interrupt 202 * @chip Interrupt controller 203 * @itr_num Interrupt number 204 * 205 * This function is called from an interrupt context by a primary interrupt 206 * handler. This function calls the handlers registered for that interrupt. 207 * If interrupt is not handled, it is masked. 208 */ 209 void interrupt_call_handlers(struct itr_chip *chip, size_t itr_num); 210 211 /* 212 * interrupt_mask() - Mask an interrupt 213 * @chip Interrupt controller 214 * @itr_num Interrupt number 215 * 216 * This function may be called in interrupt context 217 */ 218 static inline void interrupt_mask(struct itr_chip *chip, size_t itr_num) 219 { 220 chip->ops->mask(chip, itr_num); 221 } 222 223 /* 224 * interrupt_unmask() - Unmask an interrupt 225 * @chip Interrupt controller 226 * @itr_num Interrupt number 227 * 228 * This function may be called in interrupt context 229 */ 230 static inline void interrupt_unmask(struct itr_chip *chip, size_t itr_num) 231 { 232 chip->ops->unmask(chip, itr_num); 233 } 234 235 /* 236 * interrupt_enable() - Enable an interrupt 237 * @chip Interrupt controller 238 * @itr_num Interrupt number 239 */ 240 static inline void interrupt_enable(struct itr_chip *chip, size_t itr_num) 241 { 242 chip->ops->enable(chip, itr_num); 243 } 244 245 /* 246 * interrupt_disable() - Disable an interrupt 247 * @chip Interrupt controller 248 * @itr_num Interrupt number 249 */ 250 static inline void interrupt_disable(struct itr_chip *chip, size_t itr_num) 251 { 252 chip->ops->disable(chip, itr_num); 253 } 254 255 /* 256 * interrupt_can_raise_pi() - Return whether controller embeds raise_pi 257 * @chip Interrupt controller 258 */ 259 static inline bool interrupt_can_raise_pi(struct itr_chip *chip) 260 { 261 return chip->ops->raise_pi; 262 } 263 264 /* 265 * interrupt_can_raise_sgi() - Return whether controller embeds raise_sgi 266 * @chip Interrupt controller 267 */ 268 static inline bool interrupt_can_raise_sgi(struct itr_chip *chip) 269 { 270 return chip->ops->raise_sgi; 271 } 272 273 /* 274 * interrupt_can_set_affinity() - Return whether controller embeds set_affinity 275 * @chip Interrupt controller 276 */ 277 static inline bool interrupt_can_set_affinity(struct itr_chip *chip) 278 { 279 return chip->ops->set_affinity; 280 } 281 282 /* 283 * interrupt_can_set_wake() - Return whether controller embeds set_wake 284 * @chip Interrupt controller 285 */ 286 static inline bool interrupt_can_set_wake(struct itr_chip *chip) 287 { 288 return chip->ops->set_wake; 289 } 290 291 /* 292 * interrupt_raise_pi() - Raise a peripheral interrupt of a controller 293 * @chip Interrupt controller 294 * @itr_num Interrupt number to raise 295 */ 296 static inline void interrupt_raise_pi(struct itr_chip *chip, size_t itr_num) 297 { 298 assert(interrupt_can_raise_pi(chip)); 299 chip->ops->raise_pi(chip, itr_num); 300 } 301 302 /* 303 * interrupt_raise_sgi() - Raise a software generiated interrupt of a controller 304 * @chip Interrupt controller 305 * @itr_num Interrupt number to raise 306 * @cpu_mask: A bitfield of CPUs to forward the interrupt to, unless 307 * ITR_CPU_MASK_TO_THIS_CPU or ITR_CPU_MASK_TO_OTHER_CPUS 308 * (mutually exclusive) are set. 309 */ 310 static inline void interrupt_raise_sgi(struct itr_chip *chip, size_t itr_num, 311 uint32_t cpu_mask) 312 { 313 assert(interrupt_can_raise_sgi(chip)); 314 chip->ops->raise_sgi(chip, itr_num, cpu_mask); 315 } 316 317 /* 318 * interrupt_set_affinity() - Set CPU affinity for a controller interrupt 319 * @chip Interrupt controller 320 * @itr_num Interrupt number 321 * @cpu_mask Mask of the CPUs targeted by the interrupt 322 */ 323 static inline void interrupt_set_affinity(struct itr_chip *chip, size_t itr_num, 324 uint8_t cpu_mask) 325 { 326 assert(interrupt_can_set_affinity(chip)); 327 chip->ops->set_affinity(chip, itr_num, cpu_mask); 328 } 329 330 /* 331 * interrupt_set_wake() - Enable/disable power-management wake-on of interrupt 332 * @chip Interrupt controller 333 * @itr_num Interrupt number 334 * @on A boolean for enable/disable 335 */ 336 static inline void interrupt_set_wake(struct itr_chip *chip, size_t itr_num, 337 bool on) 338 { 339 assert(interrupt_can_set_wake(chip)); 340 chip->ops->set_wake(chip, itr_num, on); 341 } 342 343 /* 344 * interrupt_configure() - Configure an interrupt in an interrupt controller 345 * @chip Interrupt controller 346 * @itr_num Interrupt number 347 * @type Interrupt trigger type (IRQ_TYPE_* defines) or IRQ_TYPE_NONE 348 * @prio Interrupt priority or 0 349 * 350 * Interrupt consumers that get their interrupt from the DT do not need to 351 * call interrupt_configure() since the interrupt configuration has already 352 * been done by interrupt controller based on the DT bidings. 353 */ 354 TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num, 355 uint32_t type, uint32_t prio); 356 357 /* 358 * interrupt_add_and_configure_handler() - Register and configure a handler 359 * @hdl Interrupt handler to register 360 * @type Interrupt trigger type (IRQ_TYPE_* defines) or IRQ_TYPE_NONE 361 * @prio Interrupt priority or 0 362 */ 363 TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, 364 uint32_t type, uint32_t prio); 365 366 /* 367 * interrupt_add_handler() - Register an interrupt handler 368 * @hdl Interrupt handler to register 369 * 370 * This helper function assumes interrupt type is set to IRQ_TYPE_NONE 371 * and interrupt priority to 0. 372 */ 373 static inline TEE_Result interrupt_add_handler(struct itr_handler *hdl) 374 { 375 return interrupt_add_configure_handler(hdl, IRQ_TYPE_NONE, 0); 376 } 377 378 /* 379 * interrupt_create_handler() - Allocate/register an interrupt callback handler 380 * @itr_chip Interrupt chip obtained from interrupt_dt_get_by_*() or like 381 * @itr_num Interrupt number obtained from interrupt_dt_get_by_*() or like 382 * @callback Callback handler function 383 * @priv Private dat to pssa to @callback 384 * @flags INTERRUPT_FLAGS_* or 0 385 * @out_hdl Output allocated and registered handler or NULL 386 * 387 * This function differs from interrupt_add_handler() in that the 388 * interrupt is not reconfigured. interrupt_create_handler() expects 389 * @itr_chip and @itr_num were obtained from a call 390 * to interrupt_dt_get_by_index() or interrupt_dt_get_by_name() that 391 * are in charge of configuring the interrupt according to its DT property. 392 */ 393 TEE_Result interrupt_create_handler(struct itr_chip *itr_chip, size_t itr_num, 394 itr_handler_t callback, void *priv, 395 uint32_t flags, 396 struct itr_handler **out_hdl); 397 398 /* 399 * interrupt_add_handler_with_chip() - Register an interrupt handler providing 400 * the interrupt chip reference in specific argument @chip. 401 * @chip Interrupt controller 402 * @h Interrupt handler to register 403 */ 404 static inline TEE_Result interrupt_add_handler_with_chip(struct itr_chip *chip, 405 struct itr_handler *h) 406 { 407 h->chip = chip; 408 return interrupt_add_handler(h); 409 } 410 411 /* 412 * interrupt_remove_handler() - Remove a registered interrupt handler 413 * @hdl Interrupt handler to remove 414 * 415 * This function is the counterpart of interrupt_add_handler(). 416 * This function may panic on non-NULL invalid @hdl reference. 417 */ 418 void interrupt_remove_handler(struct itr_handler *hdl); 419 420 /* 421 * interrupt_alloc_add_conf_handler() - Allocate, configure, register a handler 422 * @chip Interrupt controller 423 * @itr_num Interrupt number 424 * @handler Interrupt handler to register 425 * @flags Bitmask flag ITRF_* 426 * @data Private data reference passed to @handler 427 * @type Interrupt trigger type (IRQ_TYPE_* defines) or IRQ_TYPE_NONE 428 * @prio Interrupt priority or 0 429 * @out_hdl NULL or output pointer to allocated struct itr_handler 430 */ 431 TEE_Result interrupt_alloc_add_conf_handler(struct itr_chip *chip, 432 size_t it_num, 433 itr_handler_t handler, 434 uint32_t flags, void *data, 435 uint32_t type, uint32_t prio, 436 struct itr_handler **out_hdl); 437 438 /* 439 * interrupt_alloc_add_handler() - Allocate and register an interrupt handler 440 * @chip Interrupt controller 441 * @itr_num Interrupt number 442 * @handler Interrupt handler to register 443 * @flags Bitmask flag ITRF_* 444 * @data Private data reference passed to @handler 445 * @out_hdl NULL or output pointer to allocated struct itr_handler 446 */ 447 static inline TEE_Result interrupt_alloc_add_handler(struct itr_chip *chip, 448 size_t it_num, 449 itr_handler_t handler, 450 uint32_t flags, 451 void *data, 452 struct itr_handler **hdl) 453 { 454 return interrupt_alloc_add_conf_handler(chip, it_num, handler, flags, 455 data, IRQ_TYPE_NONE, 0, hdl); 456 } 457 458 /* 459 * interrupt_remove_free_handler() - Remove/free a registered interrupt handler 460 * @hdl Interrupt handler to remove and free 461 * 462 * This function is the counterpart of interrupt_alloc_add_handler() 463 * and interrupt_alloc_add_conf_handler(). 464 * This function may panic on non-NULL invalid @hdl reference. 465 */ 466 void interrupt_remove_free_handler(struct itr_handler *hdl); 467 468 /* 469 * itr_dt_get_func - Typedef of function to get an interrupt in DT node 470 * 471 * @args Reference to phandle arguments 472 * @data Pointer to data given at interrupt_register_provider() call 473 * @itr_desc_p Pointer to the struct itr_desc to fill 474 * Return TEE_SUCCESS in case of success. 475 * Return TEE_ERROR_DEFER_DRIVER_INIT if controller is not initialized. 476 * Return another TEE_Result code otherwise. 477 * 478 * Upon success, the interrupt is configured and consumer can add a handler 479 * function to the interrupt. Yet, the interrupt is not enabled until consumer 480 * calls interrupt_enable(). 481 */ 482 typedef TEE_Result (*itr_dt_get_func)(struct dt_pargs *args, void *data, 483 struct itr_desc *itr_desc_p); 484 485 #ifdef CFG_DT 486 /** 487 * interrupt_register_provider() - Register an interrupt provider 488 * 489 * @fdt Device tree to work on 490 * @node Node offset of the interrupt controller in the DT 491 * @dt_get_itr Callback to match the devicetree interrupt reference with 492 * @data Data which will be passed to the get_dt_its callback 493 */ 494 TEE_Result interrupt_register_provider(const void *fdt, int node, 495 itr_dt_get_func dt_get_itr, void *data); 496 497 /** 498 * interrupt_dt_get_by_index() - Get an interrupt from DT by interrupt index 499 * 500 * Interrupt index (@index) refers to the index of the target interrupt to be 501 * retrieved as DT binding property "interrupts" may define several 502 * interrupts. 503 * 504 * @fdt Device tree to work on 505 * @node Node offset of the subnode containing interrupt(s) references 506 * @index Index in "interrupts" or "interrupts-extended" property list 507 * @chip Output interrupt controller reference upon success 508 * @itr_num Output interrupt number upon success 509 * 510 * Return TEE_SUCCESS in case of success 511 * Return TEE_ERROR_DEFER_DRIVER_INIT if interrupt driver is not yet initialized 512 * Return TEE_ERROR_ITEM_NOT_FOUND if the DT does not reference target interrupt 513 * Return any other TEE_Result compliant code in case of error 514 */ 515 TEE_Result interrupt_dt_get_by_index(const void *fdt, int node, 516 unsigned int index, struct itr_chip **chip, 517 size_t *itr_num); 518 519 /** 520 * interrupt_dt_get_by_name() - Get an interrupt from DT by interrupt name 521 * 522 * @fdt Device tree to work on 523 * @node Node offset of the subnode containing interrupt(s) references 524 * @name Name identifier used in "interrupt-names" property 525 * @chip Output interrupt controller reference upon success 526 * @itr_num Output interrupt number upon success 527 * 528 * Return TEE_SUCCESS in case of success 529 * Return TEE_ERROR_DEFER_DRIVER_INIT if interrupt driver is not yet initialized 530 * Return TEE_ERROR_ITEM_NOT_FOUND if the DT does not reference target interrupt 531 * Return any other TEE_Result compliant code in case of error 532 */ 533 TEE_Result interrupt_dt_get_by_name(const void *fdt, int node, const char *name, 534 struct itr_chip **chip, size_t *itr_num); 535 #else 536 static inline TEE_Result interrupt_register_provider(const void *dt __unused, 537 int node __unused, 538 itr_dt_get_func f __unused, 539 void *data __unused) 540 { 541 return TEE_ERROR_NOT_IMPLEMENTED; 542 } 543 544 static inline TEE_Result interrupt_dt_get_by_index(const void *fdt __unused, 545 int node __unused, 546 unsigned int index __unused, 547 struct itr_chip **c __unused, 548 size_t *itr_num __unused) 549 { 550 return TEE_ERROR_NOT_IMPLEMENTED; 551 } 552 553 static inline TEE_Result interrupt_dt_get_by_name(const void *fdt __unused, 554 int node __unused, 555 const char *name __unused, 556 struct itr_chip **ch __unused, 557 size_t *itr_num __unused) 558 { 559 return TEE_ERROR_NOT_IMPLEMENTED; 560 } 561 #endif /*CFG_DT*/ 562 563 /* 564 * Helper function for when caller retrieves the first interrupt defined 565 * in "interrupts" or "interrupts-extended" DT binding property list. 566 */ 567 static inline TEE_Result interrupt_dt_get(const void *fdt, int node, 568 struct itr_chip **chip, 569 size_t *itr_num) 570 { 571 return interrupt_dt_get_by_index(fdt, node, 0, chip, itr_num); 572 } 573 #endif /*__KERNEL_INTERRUPT_H*/ 574