Skip to content

Commit

Permalink
core: interrupts: add interrupt_release api for reset properties
Browse files Browse the repository at this point in the history
This patch introduces a interrupt_release API to reset the properties of
an interrupt to its previous settings. This functionality is essential
for scenarios where a specific interrupt needs to be dynamically set to
either Group 1 Secure (G1S) or Group 1 Non-Secure (G1NS) at different
times.

Signed-off-by: Runyang Chen <[email protected]>
  • Loading branch information
Runyang Chen committed Jun 24, 2024
1 parent c5e3e79 commit 6675631
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
63 changes: 63 additions & 0 deletions core/drivers/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <kernel/misc.h>
#include <kernel/panic.h>
#include <libfdt.h>
#include <malloc.h>
#include <mm/core_memprot.h>
#include <mm/core_mmu.h>
#include <trace.h>
Expand Down Expand Up @@ -133,6 +134,8 @@ struct gic_data {
uint32_t per_cpu_group_status;
uint32_t per_cpu_group_modifier;
uint32_t per_cpu_enable;
uint8_t *pre_prio;
uint8_t *pre_tar;
struct itr_chip chip;
};

Expand All @@ -146,6 +149,7 @@ 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);
static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
uint32_t cpu_mask);
static void gic_op_release(struct itr_chip *chip, size_t it);
static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
uint8_t cpu_mask);

Expand All @@ -157,6 +161,7 @@ static const struct itr_ops gic_ops = {
.disable = gic_op_disable,
.raise_pi = gic_op_raise_pi,
.raise_sgi = gic_op_raise_sgi,
.release = gic_op_release,
.set_affinity = gic_op_set_affinity,
};
DECLARE_KEEP_PAGER(gic_ops);
Expand Down Expand Up @@ -530,13 +535,27 @@ static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
gd->chip.dt_get_irq = gic_dt_get_irq;
}

static void gic_init_pre_prop(void)
{
struct gic_data *gd = &gic_data;

gd->pre_prio = calloc(gd->max_it + 1, sizeof(*gd->pre_prio));
if (!gd->pre_prio)
panic("Fail to allocate memory for pre_prio of gic");

gd->pre_tar = calloc(gd->max_it + 1, sizeof(*gd->pre_tar));
if (!gd->pre_tar)
panic("Faile to allocate memory for pre_tar of gic");
}

void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
paddr_t gicr_base_pa)
{
struct gic_data __maybe_unused *gd = &gic_data;
size_t __maybe_unused n = 0;

gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
gic_init_pre_prop();

#if defined(CFG_WITH_ARM_TRUSTED_FW)
/* GIC configuration is initialized from TF-A when embedded */
Expand Down Expand Up @@ -786,6 +805,26 @@ static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
#endif
}

static void gic_it_release(struct gic_data *gd, size_t it)
{
size_t idx = it / NUM_INTS_PER_REG;
uint32_t mask = 1 << (it % NUM_INTS_PER_REG);

/* Assigned to group0 */
assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));

gic_it_set_cpu_mask(gd, it, *(gd->pre_tar + it));
gic_it_set_prio(gd, it, *(gd->pre_prio + it));

/* Clear pending status */
io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
/* Assign it to group1 */
io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
#if defined(CFG_ARM_GICV3)
io_clrbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
#endif
}

static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
{
assert(gd == &gic_data);
Expand Down Expand Up @@ -838,6 +877,12 @@ static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
return (target & target_mask) >> target_shift;
}

static uint8_t __maybe_unused gic_it_get_prio(struct gic_data *gd, size_t it)
{
assert(gd == &gic_data);
return io_read8(gd->gicd_base + GICD_IPRIORITYR(0) + it);
}

void gic_dump_state(void)
{
struct gic_data *gd = &gic_data;
Expand Down Expand Up @@ -924,6 +969,9 @@ static void gic_op_add(struct itr_chip *chip, size_t it,
gd->per_cpu_group_modifier);
} else {
gic_it_add(gd, it);
/* Save the cpu_mask and prio */
*(gd->pre_tar + it) = (uint8_t)gic_it_get_target(gd, it);
*(gd->pre_prio + it) = gic_it_get_prio(gd, it);
/* Set the CPU mask to deliver interrupts to any online core */
gic_it_set_cpu_mask(gd, it, 0xff);
gic_it_set_prio(gd, it, 0x1);
Expand Down Expand Up @@ -996,6 +1044,21 @@ static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
gic_it_raise_sgi(gd, it, cpu_mask, ns);
}

static void gic_op_release(struct itr_chip *chip, size_t it)
{
struct gic_data *gd = container_of(chip, struct gic_data, chip);

assert(gd == &gic_data);

if (it > gd->max_it)
panic();

if (it < GIC_SPI_BASE)
panic("SGIs and PPIs are not supported");

gic_it_release(gd, it);
}

static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
uint8_t cpu_mask)
{
Expand Down
12 changes: 12 additions & 0 deletions core/include/kernel/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct itr_ops {
void (*raise_pi)(struct itr_chip *chip, size_t it);
void (*raise_sgi)(struct itr_chip *chip, size_t it,
uint32_t cpu_mask);
void (*release)(struct itr_chip *chip, size_t it);
void (*set_affinity)(struct itr_chip *chip, size_t it,
uint8_t cpu_mask);
};
Expand Down Expand Up @@ -299,6 +300,17 @@ static inline void interrupt_raise_sgi(struct itr_chip *chip, size_t itr_num,
chip->ops->raise_sgi(chip, itr_num, cpu_mask);
}

/*
* interrupt_release() - Reset the property for a shared peripheral interrupt
* @chip Interrupt controller
* @itr_num Interrupt number to release
*/
static inline void interrupt_release(struct itr_chip *chip, size_t itr_num)
{
assert(chip->ops->release);
chip->ops->release(chip, itr_num);
}

/*
* interrupt_set_affinity() - Set CPU affinity for a controller interrupt
* @chip Interrupt controller
Expand Down

0 comments on commit 6675631

Please sign in to comment.