riscv: Generalise/SMPify PLIC code

Add SMP support for PLIC code.
This commit is contained in:
Yanyan Shen
2019-08-06 17:12:41 +10:00
committed by Yanyan Shen
parent d1a0de41ff
commit 633412dbf1

View File

@@ -14,27 +14,67 @@
#define __DRIVER_IRQ_HIFIVE_H
#include <plat/machine/devices_gen.h>
#include <arch/model/smp.h>
#define PLIC_PPTR_BASE PLIC_PPTR + 0x0C000000
/* The memory map is based on the PLIC section in
* https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf
*/
#define PLIC_HARTID (CONFIG_FIRST_HART_ID * 2)
#define PLIC_PPTR_BASE (PLIC_PPTR + 0x0C000000)
#define PLIC_HART_ID (CONFIG_FIRST_HART_ID)
#define PLIC_PRIO 0x0
#define PLIC_PRIO_PER_ID 0x4
#define PLIC_EN 0x2000
#define PLIC_EN_PER_HART 0x80
#define PLIC_PENDING 0x1000
#define PLIC_EN 0x2000
#define PLIC_EN_PER_HART 0x100
#define PLIC_EN_PER_CONTEXT 0x80
#define PLIC_THRES 0x200000
#define PLIC_THRES_PER_HART 0x1000
#define PLIC_THRES_CLAIM 0x4
#define PLIC_THRES 0x200000
#define PLIC_SVC_CONTEXT 1
#define PLIC_THRES_PER_HART 0x2000
#define PLIC_THRES_PER_CONTEXT 0x1000
#define PLIC_THRES_CLAIM 0x4
#ifdef CONFIG_PLAT_HIFIVE
/* SiFive U54-MC has 5 cores, and the first core does not
* have supervisor mode. Therefore, we need to compensate
* for the addresses.
*/
#define PLIC_NUM_INTERRUPTS 53
#define PLAT_PLIC_THRES_ADJUST(x) ((x) - PLIC_THRES_PER_CONTEXT)
#define PLAT_PLIC_EN_ADJUST(x) ((x) - PLIC_EN_PER_CONTEXT)
#else
#define PLIC_NUM_INTERRUPTS 511
#define PLAT_PLIC_THRES_ADJUST(x) (x)
#define PLAT_PLIC_EN_ADJUST(x) (x)
#endif
typedef uint32_t interrupt_t;
static inline void write_sie(word_t value)
{
asm volatile("csrw sie, %0" :: "r"(value));
}
static inline word_t read_sie(void)
{
word_t temp;
asm volatile("csrr %0, sie" : "=r"(temp));
return temp;
}
static inline uint32_t readl(const volatile uint64_t addr)
{
uint32_t val;
asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
return val;
}
@@ -43,76 +83,111 @@ static inline void writel(uint32_t val, volatile uint64_t addr)
asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
}
static inline word_t plic_enable_offset(word_t hart_id, word_t context_id)
{
word_t addr = PLAT_PLIC_EN_ADJUST(PLIC_EN + hart_id * PLIC_EN_PER_HART + context_id * PLIC_EN_PER_CONTEXT);
return addr;
}
static inline word_t plic_thres_offset(word_t hart_id, word_t context_id)
{
word_t addr = PLAT_PLIC_THRES_ADJUST(PLIC_THRES + hart_id * PLIC_THRES_PER_HART + context_id * PLIC_THRES_PER_CONTEXT);
return addr;
}
static inline word_t plic_claim_offset(word_t hart_id, word_t context_id)
{
word_t addr = plic_thres_offset(hart_id, context_id) + PLIC_THRES_CLAIM;
return addr;
}
static inline bool_t plic_pending_interrupt(word_t interrupt)
{
word_t addr = PLIC_PPTR_BASE + PLIC_PENDING + (interrupt / 32) * 4;
word_t bit = interrupt % 32;
if (readl(addr) & BIT(bit)) {
return true;
} else {
return false;
}
}
static inline word_t get_hart_id(void)
{
#ifdef ENABLE_SMP_SUPPORT
return cpuIndexToID(getCurrentCPUIndex());
#else
return CONFIG_FIRST_HART_ID;
#endif
}
static inline interrupt_t plic_get_claim(void)
{
/* Read the claim register for our HART interrupt context */
return readl(PLIC_PPTR_BASE + PLIC_THRES + PLIC_THRES_PER_HART * PLIC_HARTID +
PLIC_THRES_CLAIM);
word_t hart_id = get_hart_id();
return readl(PLIC_PPTR_BASE + plic_claim_offset(hart_id, PLIC_SVC_CONTEXT));
}
static inline void plic_complete_claim(interrupt_t irq)
{
/* Complete the IRQ claim by writing back to the claim register. */
writel(irq, PLIC_PPTR_BASE + PLIC_THRES + PLIC_THRES_PER_HART * PLIC_HARTID +
PLIC_THRES_CLAIM);
word_t hart_id = get_hart_id();
writel(irq, PLIC_PPTR_BASE + plic_claim_offset(hart_id, PLIC_SVC_CONTEXT));
}
static inline void plic_mask_irq(bool_t disable, interrupt_t irq)
{
uint64_t addr = 0;
uint32_t val = 0;
uint32_t bit = 0;
if (irq >= 32) {
irq -= 32;
addr = 0x4;
}
word_t hart_id = get_hart_id();
addr = PLIC_PPTR_BASE + plic_enable_offset(hart_id, PLIC_SVC_CONTEXT) + (irq / 32) * 4;
bit = irq % 32;
addr += PLIC_PPTR_BASE + PLIC_EN;
val = readl(addr + PLIC_EN_PER_HART * PLIC_HARTID);
val = readl(addr);
if (disable) {
val &= ~BIT(irq);
val &= ~BIT(bit);
} else {
val |= BIT(irq);
val |= BIT(bit);
}
writel(val, addr);
}
writel(val, addr + PLIC_EN_PER_HART * PLIC_HARTID);
static inline void plic_init_hart(void)
{
if (!disable) {
/* Clear any pending claims if we are enabling otherwise they may not
* be raised again */
plic_complete_claim(irq);
word_t hart_id = get_hart_id();
for (int i = 1; i <= PLIC_NUM_INTERRUPTS; i++) {
/* Disable interrupts */
plic_mask_irq(true, i);
}
#if 0
while (1) {
interrupt_t i = readl(PLIC_PPTR_BASE + plic_claim_offset(hart_id, PLIC_SVC_CONTEXT));
if (i != irqInvalid) {
writel(i, PLIC_PPTR_BASE + plic_claim_offset(hart_id, PLIC_SVC_CONTEXT));
} else {
break;
}
}
#endif
/* Set threshold to zero */
writel(0, (PLIC_PPTR_BASE + plic_thres_offset(hart_id, PLIC_SVC_CONTEXT)));
}
static inline void plic_init_controller(void)
{
uint32_t pending;
/* Clear all pending bits */
pending = readl(PLIC_PPTR_BASE + 0x1000);
for (int i = 0; i < 32 ; i++) {
if (pending & (1 << i)) {
readl(PLIC_PPTR_BASE + PLIC_THRES +
PLIC_THRES_PER_HART * PLIC_HARTID +
PLIC_THRES_CLAIM);
for (int i = 1; i <= PLIC_NUM_INTERRUPTS; i++) {
/* Clear all pending bits */
if (plic_pending_interrupt(i)) {
readl(PLIC_PPTR_BASE + plic_claim_offset(PLIC_HART_ID, PLIC_SVC_CONTEXT));
writel(i, PLIC_PPTR_BASE + plic_claim_offset(PLIC_HART_ID, PLIC_SVC_CONTEXT));
}
}
pending = readl(PLIC_PPTR_BASE + 0x1004);
for (int i = 0; i < 22 ; i++) {
if (pending & (1 << i)) {
readl(PLIC_PPTR_BASE + PLIC_THRES +
PLIC_THRES_PER_HART * PLIC_HARTID +
PLIC_THRES_CLAIM);
}
}
/* Disable interrupts */
writel(0, PLIC_PPTR_BASE + PLIC_EN + PLIC_EN_PER_HART * PLIC_HARTID);
writel(0, PLIC_PPTR_BASE + PLIC_EN + PLIC_EN_PER_HART * PLIC_HARTID + 0x4);
/* Set threshold to zero */
writel(1, (PLIC_PPTR_BASE + PLIC_THRES + PLIC_THRES_PER_HART * PLIC_HARTID));
/* Set the priorities of all interrupts to 1 */
for (int i = 1; i <= PLIC_MAX_IRQ + 1; i++) {