Skip to content

Commit

Permalink
core: kernel: interrupt: add type and prio for interrupts
Browse files Browse the repository at this point in the history
When describing a device in the device tree, it is sometimes necessary
to parse the interrupts properties and propagates them until adding
the interrupt. For instance some interrupt-cells allows to describe
priority and type of interrupt:

  interrupts = <67 IRQ_TYPE_LEVEL_HIGH 2>;

With existing support, only the interrupt number is returned by
`dt_get_irq()`. This patch adds type and prio parameter which are passed
to `dt_get_irq_type_prio()` and `itr_add_type_prio()`. This allows
interrupt drivers to fill this from devicetree in `dt_get_irq()` but also
use these information in the `add()` callback. Additionally, it allows to
specify these flags manually when not using devicetree.

These parameters can then be used by the interrupt controller driver to
setup the irq line correctly.

Signed-off-by: Clément Léger <clement.leger@bootlin.com>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
  • Loading branch information
clementleger authored and jforissier committed Oct 18, 2021
1 parent 888bb63 commit 702fe5a
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 19 deletions.
15 changes: 12 additions & 3 deletions core/drivers/gic.c
Expand Up @@ -70,7 +70,8 @@
#define GICC_IAR_CPU_ID_MASK 0x7
#define GICC_IAR_CPU_ID_SHIFT 10

static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t flags);
static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
uint32_t prio);
static void gic_op_enable(struct itr_chip *chip, size_t it);
static void gic_op_disable(struct itr_chip *chip, size_t it);
static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
Expand Down Expand Up @@ -208,10 +209,17 @@ void gic_init(struct gic_data *gd, vaddr_t gicc_base __maybe_unused,
#endif
}

static int gic_dt_get_irq(const uint32_t *properties, int count)
static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
uint32_t *prio)
{
int it_num = DT_INFO_INVALID_INTERRUPT;

if (type)
*type = IRQ_TYPE_NONE;

if (prio)
*prio = 0;

if (!properties || count < 2)
return DT_INFO_INVALID_INTERRUPT;

Expand Down Expand Up @@ -428,7 +436,8 @@ void gic_it_handle(struct gic_data *gd)
}

static void gic_op_add(struct itr_chip *chip, size_t it,
uint32_t flags __unused)
uint32_t type __unused,
uint32_t prio __unused)
{
struct gic_data *gd = container_of(chip, struct gic_data, chip);

Expand Down
7 changes: 7 additions & 0 deletions core/include/kernel/dt.h
Expand Up @@ -7,6 +7,7 @@
#define KERNEL_DT_H

#include <compiler.h>
#include <kernel/interrupt.h>
#include <kernel/panic.h>
#include <stdint.h>
#include <types_ext.h>
Expand All @@ -33,13 +34,19 @@
* @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK
* @interrupt: Device interrupt identifier (positive value) or
* DT_INFO_INVALID_INTERRUPT
* @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if
* not present
* @prio: interrupt priority parsed from interrupts properties or 0 if not
* present
*/
struct dt_node_info {
unsigned int status;
paddr_t reg;
int clock;
int reset;
int interrupt;
uint32_t type;
uint32_t prio;
};

#if defined(CFG_DT)
Expand Down
57 changes: 49 additions & 8 deletions core/include/kernel/interrupt.h
Expand Up @@ -5,6 +5,7 @@
#ifndef __KERNEL_INTERRUPT_H
#define __KERNEL_INTERRUPT_H

#include <dt-bindings/interrupt-controller/irq.h>
#include <types_ext.h>
#include <sys/queue.h>
#include <util.h>
Expand All @@ -14,11 +15,22 @@

struct itr_chip {
const struct itr_ops *ops;
int (*dt_get_irq)(const uint32_t *properties, int count);
/*
* dt_get_irq - parse a device tree interrupt property
*
* @properties raw interrupt property from device tree
* @count number of elements in @properties
* @type If not NULL, output interrupt type (IRQ_TYPE_* defines)
* or IRQ_TYPE_NONE if unknown
* @prio If not NULL, output interrupt priority value or 0 if unknown
*/
int (*dt_get_irq)(const uint32_t *properties, int count, uint32_t *type,
uint32_t *prio);
};

struct itr_ops {
void (*add)(struct itr_chip *chip, size_t it, uint32_t flags);
void (*add)(struct itr_chip *chip, size_t it, uint32_t type,
uint32_t prio);
void (*enable)(struct itr_chip *chip, size_t it);
void (*disable)(struct itr_chip *chip, size_t it);
void (*raise_pi)(struct itr_chip *chip, size_t it);
Expand Down Expand Up @@ -50,21 +62,37 @@ void itr_handle(size_t it);

#ifdef CFG_DT
/*
* Get the DT interrupt property at @node. In the DT an interrupt
* Get the DT interrupt property at @node. In the DT an interrupt property can
* specify additional information which can be retrieved with @type and @prio.
*
* @fdt reference to the Device Tree
* @node is the node offset to read
* @node is the node offset to read the interrupt property from
* @type interrupt type (IRQ_TYPE_* defines) if specified by interrupt property
* or IRQ_TYPE_NONE if not. Can be NULL if not needed
* @prio interrupt priority if specified by interrupt property or 0 if not. Can
* be NULL if not needed
*
* Returns the interrupt number if value >= 0
* otherwise DT_INFO_INVALID_INTERRUPT
*/
int dt_get_irq(const void *fdt, int node);
int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
uint32_t *prio);

/*
* Get the DT interrupt property at @node
*/
static inline int dt_get_irq(const void *fdt, int node)
{
return dt_get_irq_type_prio(fdt, node, NULL, NULL);
}
#endif

struct itr_handler *itr_alloc_add(size_t it, itr_handler_t handler,
uint32_t flags, void *data);
struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler,
uint32_t flags, void *data,
uint32_t type, uint32_t prio);
void itr_free(struct itr_handler *hdl);
void itr_add(struct itr_handler *handler);
void itr_add_type_prio(struct itr_handler *handler, uint32_t type,
uint32_t prio);
void itr_enable(size_t it);
void itr_disable(size_t it);
/* raise the Peripheral Interrupt corresponding to the interrupt ID */
Expand All @@ -87,4 +115,17 @@ void itr_set_affinity(size_t it, uint8_t cpu_mask);
*/
void itr_core_handler(void);

static inline void itr_add(struct itr_handler *handler)
{
itr_add_type_prio(handler, IRQ_TYPE_NONE, 0);
}

static inline struct itr_handler *itr_alloc_add(size_t it,
itr_handler_t handler,
uint32_t flags, void *data)
{
return itr_alloc_add_type_prio(it, handler, flags, data, IRQ_TYPE_NONE,
0);
}

#endif /*__KERNEL_INTERRUPT_H*/
3 changes: 2 additions & 1 deletion core/kernel/dt.c
Expand Up @@ -282,7 +282,8 @@ void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, int offs)
dinfo.reset = (int)fdt32_to_cpu(*cuint);
}

dinfo.interrupt = dt_get_irq(fdt, offs);
dinfo.interrupt = dt_get_irq_type_prio(fdt, offs, &dinfo.type,
&dinfo.prio);

dinfo.status = _fdt_get_status(fdt, offs);

Expand Down
16 changes: 9 additions & 7 deletions core/kernel/interrupt.c
Expand Up @@ -29,7 +29,8 @@ void itr_init(struct itr_chip *chip)
}

#ifdef CFG_DT
int dt_get_irq(const void *fdt, int node)
int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
uint32_t *prio)
{
const uint32_t *prop = NULL;
int count = 0;
Expand All @@ -42,7 +43,7 @@ int dt_get_irq(const void *fdt, int node)
if (!prop)
return it_num;

return itr_chip->dt_get_irq(prop, count);
return itr_chip->dt_get_irq(prop, count, type, prio);
}
#endif

Expand All @@ -66,8 +67,9 @@ void itr_handle(size_t it)
}
}

struct itr_handler *itr_alloc_add(size_t it, itr_handler_t handler,
uint32_t flags, void *data)
struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler,
uint32_t flags, void *data,
uint32_t type, uint32_t prio)
{
struct itr_handler *hdl = calloc(1, sizeof(*hdl));

Expand All @@ -76,7 +78,7 @@ struct itr_handler *itr_alloc_add(size_t it, itr_handler_t handler,
hdl->handler = handler;
hdl->flags = flags;
hdl->data = data;
itr_add(hdl);
itr_add_type_prio(hdl, type, prio);
}

return hdl;
Expand All @@ -93,7 +95,7 @@ void itr_free(struct itr_handler *hdl)
free(hdl);
}

void itr_add(struct itr_handler *h)
void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio)
{
struct itr_handler __maybe_unused *hdl = NULL;

Expand All @@ -102,7 +104,7 @@ void itr_add(struct itr_handler *h)
assert((hdl->flags & ITRF_SHARED) &&
(h->flags & ITRF_SHARED));

itr_chip->ops->add(itr_chip, h->it, h->flags);
itr_chip->ops->add(itr_chip, h->it, type, prio);
SLIST_INSERT_HEAD(&handlers, h, link);
}

Expand Down

0 comments on commit 702fe5a

Please sign in to comment.