Skip to content

Commit 6843240

Browse files
ycsinnashif
authored andcommitted
drivers: intc: plic: use per-instance spinlock
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]>
1 parent 1310856 commit 6843240

File tree

1 file changed

+40
-27
lines changed

1 file changed

+40
-27
lines changed

drivers/interrupt_controller/intc_plic.c

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ struct plic_stats {
103103
};
104104

105105
struct plic_data {
106+
struct k_spinlock lock;
106107

107108
#ifdef CONFIG_PLIC_SHELL_IRQ_COUNT
108109
struct plic_stats stats;
@@ -279,11 +280,13 @@ static void plic_irq_enable_set_state(uint32_t irq, bool enable)
279280
*/
280281
void riscv_plic_irq_enable(uint32_t irq)
281282
{
282-
uint32_t key = irq_lock();
283+
const struct device *dev = get_plic_dev_from_irq(irq);
284+
struct plic_data *data = dev->data;
285+
k_spinlock_key_t key = k_spin_lock(&data->lock);
283286

284287
plic_irq_enable_set_state(irq, true);
285288

286-
irq_unlock(key);
289+
k_spin_unlock(&data->lock, key);
287290
}
288291

289292
/**
@@ -298,47 +301,58 @@ void riscv_plic_irq_enable(uint32_t irq)
298301
*/
299302
void riscv_plic_irq_disable(uint32_t irq)
300303
{
301-
uint32_t key = irq_lock();
304+
const struct device *dev = get_plic_dev_from_irq(irq);
305+
struct plic_data *data = dev->data;
306+
k_spinlock_key_t key = k_spin_lock(&data->lock);
302307

303308
plic_irq_enable_set_state(irq, false);
304309

305-
irq_unlock(key);
310+
k_spin_unlock(&data->lock, key);
306311
}
307312

308-
/**
309-
* @brief Check if a riscv PLIC-specific interrupt line is enabled
310-
*
311-
* This routine checks if a RISCV PLIC-specific interrupt line is enabled.
312-
* @param irq IRQ number to check
313-
*
314-
* @return 1 or 0
315-
*/
316-
int riscv_plic_irq_is_enabled(uint32_t irq)
313+
/* Check if the local IRQ of a PLIC instance is enabled */
314+
static int local_irq_is_enabled(const struct device *dev, uint32_t local_irq)
317315
{
318-
const struct device *dev = get_plic_dev_from_irq(irq);
319-
const uint32_t local_irq = irq_from_level_2(irq);
320316
uint32_t bit_position = local_irq & PLIC_REG_MASK;
321-
uint32_t en_value;
322317
int is_enabled = IS_ENABLED(CONFIG_PLIC_IRQ_AFFINITY) ? 0 : 1;
323-
uint32_t key = irq_lock();
324318

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

329-
en_value = sys_read32(en_addr);
330324
if (IS_ENABLED(CONFIG_PLIC_IRQ_AFFINITY)) {
331325
is_enabled |= !!(en_value & BIT(bit_position));
332326
} else {
333327
is_enabled &= !!(en_value & BIT(bit_position));
334328
}
335329
}
336330

337-
irq_unlock(key);
338-
339331
return is_enabled;
340332
}
341333

334+
/**
335+
* @brief Check if a riscv PLIC-specific interrupt line is enabled
336+
*
337+
* This routine checks if a RISCV PLIC-specific interrupt line is enabled.
338+
* @param irq IRQ number to check
339+
*
340+
* @return 1 or 0
341+
*/
342+
int riscv_plic_irq_is_enabled(uint32_t irq)
343+
{
344+
const struct device *dev = get_plic_dev_from_irq(irq);
345+
struct plic_data *data = dev->data;
346+
const uint32_t local_irq = irq_from_level_2(irq);
347+
int ret = 0;
348+
349+
K_SPINLOCK(&data->lock) {
350+
ret = local_irq_is_enabled(dev, local_irq);
351+
}
352+
353+
return ret;
354+
}
355+
342356
/**
343357
* @brief Set priority of a riscv PLIC-specific interrupt line
344358
*
@@ -413,9 +427,10 @@ const struct device *riscv_plic_get_dev(void)
413427
int riscv_plic_irq_set_affinity(uint32_t irq, uint32_t cpumask)
414428
{
415429
const struct device *dev = get_plic_dev_from_irq(irq);
416-
const struct plic_data *data = dev->data;
430+
struct plic_data *data = dev->data;
417431
__maybe_unused const struct plic_config *config = dev->config;
418432
const uint32_t local_irq = irq_from_level_2(irq);
433+
k_spinlock_key_t key;
419434

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

430-
uint32_t key = irq_lock();
431-
445+
key = k_spin_lock(&data->lock);
432446
/* Updated irq_cpumask for next time setting plic enable register */
433447
data->irq_cpumask[local_irq] = (plic_cpumask_t)cpumask;
434448

435449
/* If irq is enabled, apply the new irq affinity */
436-
if (riscv_plic_irq_is_enabled(irq)) {
437-
riscv_plic_irq_enable(irq);
450+
if (local_irq_is_enabled(dev, local_irq)) {
451+
plic_irq_enable_set_state(irq, true);
438452
}
439-
440-
irq_unlock(key);
453+
k_spin_unlock(&data->lock, key);
441454

442455
return 0;
443456
}

0 commit comments

Comments
 (0)