Skip to content

Commit

Permalink
drivers: intc: plic: use per-instance spinlock
Browse files Browse the repository at this point in the history
Instead of doing an `irq_lock()`, use per-instance spinlock instead.

Refactored out an unlocked version of `local_irq_is_enabled`
from `riscv_plic_irq_is_enabled()` to achieve that.

Signed-off-by: Yong Cong Sin <[email protected]>
  • Loading branch information
ycsin authored and nashif committed Nov 20, 2024
1 parent 1310856 commit 6843240
Showing 1 changed file with 40 additions and 27 deletions.
67 changes: 40 additions & 27 deletions drivers/interrupt_controller/intc_plic.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ struct plic_stats {
};

struct plic_data {
struct k_spinlock lock;

#ifdef CONFIG_PLIC_SHELL_IRQ_COUNT
struct plic_stats stats;
Expand Down Expand Up @@ -279,11 +280,13 @@ static void plic_irq_enable_set_state(uint32_t irq, bool enable)
*/
void riscv_plic_irq_enable(uint32_t irq)
{
uint32_t key = irq_lock();
const struct device *dev = get_plic_dev_from_irq(irq);
struct plic_data *data = dev->data;
k_spinlock_key_t key = k_spin_lock(&data->lock);

plic_irq_enable_set_state(irq, true);

irq_unlock(key);
k_spin_unlock(&data->lock, key);
}

/**
Expand All @@ -298,47 +301,58 @@ void riscv_plic_irq_enable(uint32_t irq)
*/
void riscv_plic_irq_disable(uint32_t irq)
{
uint32_t key = irq_lock();
const struct device *dev = get_plic_dev_from_irq(irq);
struct plic_data *data = dev->data;
k_spinlock_key_t key = k_spin_lock(&data->lock);

plic_irq_enable_set_state(irq, false);

irq_unlock(key);
k_spin_unlock(&data->lock, key);
}

/**
* @brief Check if a riscv PLIC-specific interrupt line is enabled
*
* This routine checks if a RISCV PLIC-specific interrupt line is enabled.
* @param irq IRQ number to check
*
* @return 1 or 0
*/
int riscv_plic_irq_is_enabled(uint32_t irq)
/* Check if the local IRQ of a PLIC instance is enabled */
static int local_irq_is_enabled(const struct device *dev, uint32_t local_irq)
{
const struct device *dev = get_plic_dev_from_irq(irq);
const uint32_t local_irq = irq_from_level_2(irq);
uint32_t bit_position = local_irq & PLIC_REG_MASK;
uint32_t en_value;
int is_enabled = IS_ENABLED(CONFIG_PLIC_IRQ_AFFINITY) ? 0 : 1;
uint32_t key = irq_lock();

for (uint32_t cpu_num = 0; cpu_num < arch_num_cpus(); cpu_num++) {
mem_addr_t en_addr =
get_context_en_addr(dev, cpu_num) + local_irq_to_reg_offset(local_irq);
uint32_t en_value = sys_read32(en_addr);

en_value = sys_read32(en_addr);
if (IS_ENABLED(CONFIG_PLIC_IRQ_AFFINITY)) {
is_enabled |= !!(en_value & BIT(bit_position));
} else {
is_enabled &= !!(en_value & BIT(bit_position));
}
}

irq_unlock(key);

return is_enabled;
}

/**
* @brief Check if a riscv PLIC-specific interrupt line is enabled
*
* This routine checks if a RISCV PLIC-specific interrupt line is enabled.
* @param irq IRQ number to check
*
* @return 1 or 0
*/
int riscv_plic_irq_is_enabled(uint32_t irq)
{
const struct device *dev = get_plic_dev_from_irq(irq);
struct plic_data *data = dev->data;
const uint32_t local_irq = irq_from_level_2(irq);
int ret = 0;

K_SPINLOCK(&data->lock) {
ret = local_irq_is_enabled(dev, local_irq);
}

return ret;
}

/**
* @brief Set priority of a riscv PLIC-specific interrupt line
*
Expand Down Expand Up @@ -413,9 +427,10 @@ const struct device *riscv_plic_get_dev(void)
int riscv_plic_irq_set_affinity(uint32_t irq, uint32_t cpumask)
{
const struct device *dev = get_plic_dev_from_irq(irq);
const struct plic_data *data = dev->data;
struct plic_data *data = dev->data;
__maybe_unused const struct plic_config *config = dev->config;
const uint32_t local_irq = irq_from_level_2(irq);
k_spinlock_key_t key;

if (local_irq >= config->nr_irqs) {
__ASSERT(false, "overflow: irq %d, local_irq %d", irq, local_irq);
Expand All @@ -427,17 +442,15 @@ int riscv_plic_irq_set_affinity(uint32_t irq, uint32_t cpumask)
return -EINVAL;
}

uint32_t key = irq_lock();

key = k_spin_lock(&data->lock);
/* Updated irq_cpumask for next time setting plic enable register */
data->irq_cpumask[local_irq] = (plic_cpumask_t)cpumask;

/* If irq is enabled, apply the new irq affinity */
if (riscv_plic_irq_is_enabled(irq)) {
riscv_plic_irq_enable(irq);
if (local_irq_is_enabled(dev, local_irq)) {
plic_irq_enable_set_state(irq, true);
}

irq_unlock(key);
k_spin_unlock(&data->lock, key);

return 0;
}
Expand Down

0 comments on commit 6843240

Please sign in to comment.