drivers: intc: plic: Use sys IO APIs to access memory-mapped registers
Use arch-specific sys IO APIs to access the memory-mapped registers to ensure safe memory operations fixes #62956 Signed-off-by: Yong Cong Sin <ycsin@meta.com>
This commit is contained in:
parent
980fb4b846
commit
ffb8f31bff
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
* Copyright (c) 2023 Meta
|
||||
* Contributors: 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
|
@ -31,6 +32,8 @@
|
|||
#define PLIC_REG_PRIO_OFFSET 0x0
|
||||
#define PLIC_REG_IRQ_EN_OFFSET 0x2000
|
||||
#define PLIC_REG_REGS_OFFSET 0x200000
|
||||
#define PLIC_REG_REGS_THRES_PRIORITY_OFFSET 0
|
||||
#define PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET sizeof(uint32_t)
|
||||
/*
|
||||
* Trigger type is mentioned, but not defined in the RISCV PLIC specs.
|
||||
* However, it is defined and supported by at least the Andes & Telink datasheet, and supported
|
||||
|
@ -42,11 +45,6 @@
|
|||
#define PLIC_REG_SIZE 32
|
||||
#define PLIC_REG_MASK BIT_MASK(LOG2(PLIC_REG_SIZE))
|
||||
|
||||
struct plic_regs_t {
|
||||
uint32_t threshold_prio;
|
||||
uint32_t claim_complete;
|
||||
};
|
||||
|
||||
typedef void (*riscv_plic_irq_config_func_t)(void);
|
||||
struct plic_config {
|
||||
mem_addr_t prio;
|
||||
|
@ -73,6 +71,20 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev)
|
|||
return local_irq_to_reg_offset(config->num_irqs) + 1;
|
||||
}
|
||||
|
||||
static inline uint32_t get_claim_complete_offset(const struct device *dev)
|
||||
{
|
||||
const struct plic_config *config = dev->config;
|
||||
|
||||
return config->reg + PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET;
|
||||
}
|
||||
|
||||
static inline uint32_t get_threshold_priority_offset(const struct device *dev)
|
||||
{
|
||||
const struct plic_config *config = dev->config;
|
||||
|
||||
return config->reg + PLIC_REG_REGS_THRES_PRIORITY_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine the PLIC device from the IRQ
|
||||
*
|
||||
|
@ -103,10 +115,9 @@ static inline const struct device *get_plic_dev_from_irq(uint32_t irq)
|
|||
static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq)
|
||||
{
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile uint32_t *trig = (volatile uint32_t *) config->trig;
|
||||
mem_addr_t trig_addr = config->trig + local_irq_to_reg_offset(local_irq);
|
||||
|
||||
trig += local_irq_to_reg_offset(local_irq);
|
||||
return *trig & BIT(local_irq);
|
||||
return sys_read32(trig_addr) & BIT(local_irq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,13 +134,15 @@ void riscv_plic_irq_enable(uint32_t irq)
|
|||
{
|
||||
const struct device *dev = get_plic_dev_from_irq(irq);
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile uint32_t *en = (volatile uint32_t *) config->irq_en;
|
||||
const uint32_t local_irq = irq_from_level_2(irq);
|
||||
mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq);
|
||||
uint32_t en_value;
|
||||
uint32_t key;
|
||||
|
||||
key = irq_lock();
|
||||
en += local_irq_to_reg_offset(local_irq);
|
||||
WRITE_BIT(*en, local_irq & PLIC_REG_MASK, true);
|
||||
en_value = sys_read32(en_addr);
|
||||
WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, true);
|
||||
sys_write32(en_value, en_addr);
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
|
@ -147,13 +160,15 @@ void riscv_plic_irq_disable(uint32_t irq)
|
|||
{
|
||||
const struct device *dev = get_plic_dev_from_irq(irq);
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile uint32_t *en = (volatile uint32_t *) config->irq_en;
|
||||
const uint32_t local_irq = irq_from_level_2(irq);
|
||||
mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq);
|
||||
uint32_t en_value;
|
||||
uint32_t key;
|
||||
|
||||
key = irq_lock();
|
||||
en += local_irq_to_reg_offset(local_irq);
|
||||
WRITE_BIT(*en, local_irq & PLIC_REG_MASK, false);
|
||||
en_value = sys_read32(en_addr);
|
||||
WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, false);
|
||||
sys_write32(en_value, en_addr);
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
|
@ -169,11 +184,14 @@ int riscv_plic_irq_is_enabled(uint32_t irq)
|
|||
{
|
||||
const struct device *dev = get_plic_dev_from_irq(irq);
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile uint32_t *en = (volatile uint32_t *) config->irq_en;
|
||||
const uint32_t local_irq = irq_from_level_2(irq);
|
||||
mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq);
|
||||
uint32_t en_value;
|
||||
|
||||
en += local_irq_to_reg_offset(local_irq);
|
||||
return !!(*en & BIT(local_irq & PLIC_REG_MASK));
|
||||
en_value = sys_read32(en_addr);
|
||||
en_value &= BIT(local_irq & PLIC_REG_MASK);
|
||||
|
||||
return !!en_value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,14 +208,13 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority)
|
|||
{
|
||||
const struct device *dev = get_plic_dev_from_irq(irq);
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile uint32_t *prio = (volatile uint32_t *) config->prio;
|
||||
const uint32_t local_irq = irq_from_level_2(irq);
|
||||
mem_addr_t prio_addr = config->prio + (local_irq * sizeof(uint32_t));
|
||||
|
||||
if (priority > config->max_prio)
|
||||
priority = config->max_prio;
|
||||
|
||||
prio += local_irq;
|
||||
*prio = priority;
|
||||
sys_write32(priority, prio_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,12 +240,12 @@ const struct device *riscv_plic_get_dev(void)
|
|||
static void plic_irq_handler(const struct device *dev)
|
||||
{
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg;
|
||||
mem_addr_t claim_complete_addr = get_claim_complete_offset(dev);
|
||||
struct _isr_table_entry *ite;
|
||||
int edge_irq;
|
||||
|
||||
/* Get the IRQ number generating the interrupt */
|
||||
const uint32_t local_irq = regs->claim_complete;
|
||||
const uint32_t local_irq = sys_read32(claim_complete_addr);
|
||||
|
||||
/*
|
||||
* Save IRQ in save_irq. To be used, if need be, by
|
||||
|
@ -254,7 +271,7 @@ static void plic_irq_handler(const struct device *dev)
|
|||
* for edge triggered interrupts.
|
||||
*/
|
||||
if (edge_irq)
|
||||
regs->claim_complete = local_irq;
|
||||
sys_write32(local_irq, claim_complete_addr);
|
||||
|
||||
const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS),
|
||||
(z_get_sw_isr_irq_from_device(dev)), (0U));
|
||||
|
@ -273,7 +290,7 @@ static void plic_irq_handler(const struct device *dev)
|
|||
* for level triggered interrupts.
|
||||
*/
|
||||
if (!edge_irq)
|
||||
regs->claim_complete = local_irq;
|
||||
sys_write32(local_irq, claim_complete_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,24 +303,22 @@ static void plic_irq_handler(const struct device *dev)
|
|||
static int plic_init(const struct device *dev)
|
||||
{
|
||||
const struct plic_config *config = dev->config;
|
||||
volatile uint32_t *en = (volatile uint32_t *) config->irq_en;
|
||||
volatile uint32_t *prio = (volatile uint32_t *) config->prio;
|
||||
volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg;
|
||||
mem_addr_t en_addr = config->irq_en;
|
||||
mem_addr_t prio_addr = config->prio;
|
||||
mem_addr_t thres_prio_addr = get_threshold_priority_offset(dev);
|
||||
|
||||
/* Ensure that all interrupts are disabled initially */
|
||||
for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) {
|
||||
*en = 0U;
|
||||
en++;
|
||||
sys_write32(0U, en_addr + (i * sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
/* Set priority of each interrupt line to 0 initially */
|
||||
for (uint32_t i = 0; i < config->num_irqs; i++) {
|
||||
*prio = 0U;
|
||||
prio++;
|
||||
sys_write32(0U, prio_addr + (i * sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
/* Set threshold priority to 0 */
|
||||
regs->threshold_prio = 0U;
|
||||
sys_write32(0U, thres_prio_addr);
|
||||
|
||||
/* Configure IRQ for PLIC driver */
|
||||
config->irq_config_func();
|
||||
|
|
Loading…
Reference in a new issue