diff --git a/core/include/kernel/interrupt.h b/core/include/kernel/interrupt.h index 2c14ae59250..83d6632a9fe 100644 --- a/core/include/kernel/interrupt.h +++ b/core/include/kernel/interrupt.h @@ -338,6 +338,25 @@ static inline TEE_Result interrupt_add_handler(struct itr_handler *hdl) return interrupt_add_configure_handler(hdl, IRQ_TYPE_NONE, 0); } +/* + * interrupt_create_handler() - Allocate/register an interrupt callback handler + * @itr_chip Interrupt chip obtained from dt_get_interrupt_by_*() + * @itr_num Interrupt number obtained from dt_get_interrupt_by_*() + * @callback Callback handler function + * @priv Private dat to pssa to @callback + * @flags INTERRUPT_FLAGS_* or 0 + * @out_hdl Output allocated and registered handler or NULL + * + * This function differs from interrupt_add_handler() in that the + * interrupt is not reconfigured. interrupt_create_handler() expects + * @itr_desc was obtained from a call to dt_get_interrupt_by_index() + * or dt_get_interrupt_by_name(). That call configured the interrupt. + */ +TEE_Result interrupt_create_handler(struct itr_chip *itr_chip, size_t itr_num, + itr_handler_t callback, void *priv, + uint32_t flags, + struct itr_handler **out_hdl); + /* * interrupt_add_handler_with_chip() - Register an interrupt handler providing * the interrupt chip reference in specific argument @chip. diff --git a/core/kernel/interrupt.c b/core/kernel/interrupt.c index 5413dff2187..f46a7700b75 100644 --- a/core/kernel/interrupt.c +++ b/core/kernel/interrupt.c @@ -104,8 +104,9 @@ TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num, return TEE_SUCCESS; } -TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, - uint32_t type, uint32_t prio) +static TEE_Result add_configure_handler(struct itr_handler *hdl, + uint32_t type, uint32_t prio, + bool configure) { struct itr_handler *h = NULL; @@ -122,13 +123,52 @@ TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, } } - interrupt_configure(hdl->chip, hdl->it, type, prio); + if (configure) + interrupt_configure(hdl->chip, hdl->it, type, prio); SLIST_INSERT_HEAD(&hdl->chip->handlers, hdl, link); return TEE_SUCCESS; } +TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, + uint32_t type, uint32_t prio) +{ + return add_configure_handler(hdl, type, prio, true /* configure */); +} + +TEE_Result interrupt_create_handler(struct itr_chip *itr_chip, size_t itr_num, + itr_handler_t callback, void *priv, + uint32_t flags, + struct itr_handler **out_hdl) +{ + TEE_Result res = TEE_ERROR_GENERIC; + struct itr_handler *itr_hdl = NULL; + + itr_hdl = calloc(1, sizeof(*itr_hdl)); + if (!itr_hdl) + return TEE_ERROR_OUT_OF_MEMORY; + + *itr_hdl = (struct itr_handler){ + .chip = itr_chip, + .it = itr_num, + .flags = flags, + .handler = callback, + .data = priv, + }; + + res = add_configure_handler(itr_hdl, 0, 0, false /* configure */); + if (res) { + free(itr_hdl); + return res; + } + + if (out_hdl) + *out_hdl = itr_hdl; + + return TEE_SUCCESS; +} + void interrupt_remove_handler(struct itr_handler *hdl) { struct itr_handler *h = NULL;