Skip to content

Commit 70e3ae8

Browse files
committed
[riscv]统一plic和中断控制的接口实现
1 parent 0500df5 commit 70e3ae8

File tree

18 files changed

+339
-1206
lines changed

18 files changed

+339
-1206
lines changed

bsp/qemu-virt64-riscv/driver/board.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ void rt_hw_board_init(void)
7676
rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END);
7777
#endif
7878

79-
plic_init();
80-
8179
rt_hw_interrupt_init();
8280

8381
rt_hw_uart_init();

libcpu/risc-v/SConscript

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ list = os.listdir(cwd)
1313
# add common code files
1414
if rtconfig.CPU in common64_arch :
1515
group += SConscript(os.path.join('common64', 'SConscript'))
16+
group += SConscript(os.path.join('plic', 'SConscript'))
1617
else :
1718
group += SConscript(os.path.join('common', 'SConscript'))
1819

libcpu/risc-v/common64/interrupt.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright (c) 2006-2021, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2018/10/01 Bernard The first version
9+
* 2018/12/27 Jesven Change irq enable/disable to cpu0
10+
*/
11+
#include <rtthread.h>
12+
#include <plic.h>
13+
#include <rthw.h>
14+
#include "encoding.h"
15+
#include "riscv.h"
16+
#include "interrupt.h"
17+
18+
#ifdef RT_USING_SMART
19+
#include <ioremap.h>
20+
#endif
21+
22+
/* TODO define PLIC_PHY_ADDR in BSP and remove me */
23+
#ifdef C908_PLIC_PHY_ADDR
24+
#define PLIC_PHY_ADDR C908_PLIC_PHY_ADDR
25+
#elif defined(C906_PLIC_PHY_ADDR)
26+
#define PLIC_PHY_ADDR C906_PLIC_PHY_ADDR
27+
#elif !defined(PLIC_PHY_ADDR)
28+
#define PLIC_PHY_ADDR 0x0c000000L
29+
#endif
30+
31+
static struct rt_irq_desc isr_table[INTERRUPTS_MAX];
32+
static struct plic_handler plic_handlers[1];
33+
34+
rt_inline struct plic_handler *plic_handler_get(void)
35+
{
36+
return &plic_handlers[0];
37+
}
38+
39+
static void plic_init(void)
40+
{
41+
void *plic_base = (void *)PLIC_PHY_ADDR;
42+
43+
#ifdef RT_USING_SMART
44+
// PLIC takes up 64 MB space
45+
plic_base = rt_ioremap(plic_base, 64 * 1024 * 1024);
46+
#endif
47+
/* skip contexts other than supervisor external interrupt */
48+
plic_handler_init(plic_handler_get(), plic_base, 1);
49+
50+
plic_set_threshold(plic_handler_get(), 0);
51+
}
52+
53+
static void rt_hw_interrupt_handle(int vector, void *param)
54+
{
55+
rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
56+
}
57+
58+
/**
59+
* This function will mask a interrupt.
60+
* @param vector the interrupt number
61+
*/
62+
void rt_hw_interrupt_mask(int vector)
63+
{
64+
if ((vector < 0) || (vector > IRQ_MAX_NR))
65+
{
66+
return;
67+
}
68+
69+
plic_irq_disable(plic_handler_get(), vector);
70+
}
71+
72+
/**
73+
* This function will un-mask a interrupt.
74+
* @param vector the interrupt number
75+
*/
76+
void rt_hw_interrupt_umask(int vector)
77+
{
78+
if ((vector < 0) || (vector > IRQ_MAX_NR))
79+
{
80+
return;
81+
}
82+
83+
plic_set_priority(plic_handler_get(), vector, 1);
84+
85+
plic_irq_enable(plic_handler_get(), vector);
86+
}
87+
88+
/**
89+
* This function will install a interrupt service routine to a interrupt.
90+
* @param vector the interrupt number
91+
* @param new_handler the interrupt service routine to be installed
92+
* @param old_handler the old interrupt service routine
93+
*/
94+
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
95+
void *param, const char *name)
96+
{
97+
rt_isr_handler_t old_handler = RT_NULL;
98+
99+
if ((vector < 0) || (vector > IRQ_MAX_NR))
100+
{
101+
return old_handler;
102+
}
103+
104+
old_handler = isr_table[IRQ_OFFSET + vector].handler;
105+
106+
isr_table[IRQ_OFFSET + vector].handler = handler;
107+
isr_table[IRQ_OFFSET + vector].param = param;
108+
109+
return old_handler;
110+
}
111+
112+
void rt_hw_interrupt_init(void)
113+
{
114+
/* init exceptions table */
115+
for (int idx = 0; idx < INTERRUPTS_MAX; idx++)
116+
{
117+
isr_table[idx].handler = rt_hw_interrupt_handle;
118+
isr_table[idx].param = RT_NULL;
119+
}
120+
121+
plic_init();
122+
123+
/* Enable supervisor external interrupts. */
124+
set_csr(sie, SIE_SEIE);
125+
}
126+
127+
/*
128+
* Handling an interrupt is a two-step process: first you claim the interrupt
129+
* by reading the claim register, then you complete the interrupt by writing
130+
* that source ID back to the same claim register. This automatically enables
131+
* and disables the interrupt, so there's nothing else to do.
132+
*/
133+
void plic_handle_irq(void)
134+
{
135+
struct plic_handler *plic;
136+
rt_isr_handler_t isr;
137+
void *param;
138+
int irq;
139+
140+
plic = plic_handler_get();
141+
142+
while ((irq = plic_claim(plic)))
143+
{
144+
isr = isr_table[IRQ_OFFSET + irq].handler;
145+
param = isr_table[IRQ_OFFSET + irq].param;
146+
if (isr)
147+
{
148+
isr(irq, param);
149+
}
150+
151+
plic_complete(plic, irq);
152+
}
153+
}
Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
#ifndef INTERRUPT_H__
1212
#define INTERRUPT_H__
1313

14-
#define MAX_HANDLERS 128
15-
16-
#include <rthw.h>
17-
#include "stack.h"
14+
#define IRQ_OFFSET 16
15+
#ifndef IRQ_MAX_NR
16+
#define IRQ_MAX_NR 200
17+
#endif
18+
#define INTERRUPTS_MAX (IRQ_OFFSET + IRQ_MAX_NR)
1819

1920
enum
2021
{
@@ -33,14 +34,14 @@ enum
3334
EP_INSTRUCTION_PAGE_FAULT, /* page attr */
3435
EP_LOAD_PAGE_FAULT, /* read data */
3536
EP_RESERVED14,
36-
EP_STORE_PAGE_FAULT, /* write data */
37+
EP_STORE_PAGE_FAULT, /* write data */
3738
};
3839

39-
int rt_hw_plic_irq_enable(int irq_number);
40-
int rt_hw_plic_irq_disable(int irq_number);
4140
void rt_hw_interrupt_init(void);
4241
void rt_hw_interrupt_mask(int vector);
42+
void rt_hw_interrupt_umask(int vector);
4343
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name);
44-
void handle_trap(rt_ubase_t xcause, rt_ubase_t xtval, rt_ubase_t xepc, struct rt_hw_stack_frame *sp);
44+
45+
void plic_handle_irq(void);
4546

4647
#endif

libcpu/risc-v/plic/SConscript

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# RT-Thread building script for component
2+
3+
from building import *
4+
cwd = GetCurrentDir()
5+
src = []
6+
CPPPATH = []
7+
8+
src += Glob('*.c')
9+
CPPPATH += [cwd]
10+
11+
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
12+
13+
Return('group')

libcpu/risc-v/plic/plic.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2006-2021, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2021-05-20 bigmagic first version
9+
* 2022-09-16 WangXiaoyao Porting to rv64
10+
*/
11+
#include <rtdef.h>
12+
#include "plic.h"
13+
#include <riscv_io.h>
14+
15+
/*
16+
* Each interrupt source has a priority register associated with it.
17+
* We always hardwire it to one in Linux.
18+
*/
19+
#define PRIORITY_BASE 0
20+
#define PRIORITY_PER_ID 4
21+
22+
/*
23+
* Each hart context has a vector of interrupt enable bits associated with it.
24+
* There's one bit for each interrupt source.
25+
*/
26+
#define CONTEXT_ENABLE_BASE 0x2000
27+
#define CONTEXT_ENABLE_SIZE 0x80
28+
29+
/*
30+
* Each hart context has a set of control registers associated with it. Right
31+
* now there's only two: a source priority threshold over which the hart will
32+
* take an interrupt, and a register to claim interrupts.
33+
*/
34+
#define CONTEXT_BASE 0x200000
35+
#define CONTEXT_SIZE 0x1000
36+
#define CONTEXT_THRESHOLD 0x00
37+
#define CONTEXT_CLAIM 0x04
38+
39+
static void plic_toggle(struct plic_handler *handler, unsigned int irq, int enable)
40+
{
41+
void *reg = handler->enable_base + (irq / 32) * sizeof(unsigned int);
42+
unsigned int hwirq_mask = 1 << (irq % 32);
43+
44+
if (enable)
45+
writel(readl(reg) | hwirq_mask, reg);
46+
else
47+
writel(readl(reg) & ~hwirq_mask, reg);
48+
}
49+
50+
/*
51+
* Each PLIC interrupt source can be assigned a priority by writing
52+
* to its 32-bit memory-mapped priority register.
53+
* The QEMU-virt (the same as FU540-C000) supports 7 levels of priority.
54+
* A priority value of 0 is reserved to mean "never interrupt" and
55+
* effectively disables the interrupt.
56+
* Priority 1 is the lowest active priority, and priority 7 is the highest.
57+
* Ties between global interrupts of the same priority are broken by
58+
* the Interrupt ID; interrupts with the lowest ID have the highest
59+
* effective priority.
60+
*/
61+
void plic_set_priority(struct plic_handler *handler, int irq, int priority)
62+
{
63+
writel(priority, handler->base + PRIORITY_BASE + irq * PRIORITY_PER_ID);
64+
}
65+
66+
/*
67+
* Each global interrupt can be enabled by setting the corresponding
68+
* bit in the enables registers.
69+
*/
70+
void plic_irq_enable(struct plic_handler *handler, int irq)
71+
{
72+
plic_toggle(handler, irq, 1);
73+
}
74+
75+
void plic_irq_disable(struct plic_handler *handler, int irq)
76+
{
77+
plic_toggle(handler, irq, 1);
78+
}
79+
80+
/*
81+
* PLIC will mask all interrupts of a priority less than or equal to threshold.
82+
* Maximum threshold is 7.
83+
* For example, a threshold value of zero permits all interrupts with
84+
* non-zero priority, whereas a value of 7 masks all interrupts.
85+
* Notice, the threshold is global for PLIC, not for each interrupt source.
86+
*/
87+
void plic_set_threshold(struct plic_handler *handler, int threshold)
88+
{
89+
writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
90+
}
91+
92+
/*
93+
* DESCRIPTION:
94+
* Query the PLIC what interrupt we should serve.
95+
* Perform an interrupt claim by reading the claim register, which
96+
* returns the ID of the highest-priority pending interrupt or zero if there
97+
* is no pending interrupt.
98+
* A successful claim also atomically clears the corresponding pending bit
99+
* on the interrupt source.
100+
* RETURN VALUE:
101+
* the ID of the highest-priority pending interrupt or zero if there
102+
* is no pending interrupt.
103+
*/
104+
int plic_claim(struct plic_handler *handler)
105+
{
106+
void *claim = handler->hart_base + CONTEXT_CLAIM;
107+
108+
return readl(claim);
109+
}
110+
111+
/*
112+
* DESCRIPTION:
113+
* Writing the interrupt ID it received from the claim (irq) to the
114+
* complete register would signal the PLIC we've served this IRQ.
115+
* The PLIC does not check whether the completion ID is the same as the
116+
* last claim ID for that target. If the completion ID does not match an
117+
* interrupt source that is currently enabled for the target, the completion
118+
* is silently ignored.
119+
* RETURN VALUE: none
120+
*/
121+
void plic_complete(struct plic_handler *handler, int irq)
122+
{
123+
void *claim = handler->hart_base + CONTEXT_CLAIM;
124+
125+
writel(irq, claim);
126+
}
127+
128+
void plic_handler_init(struct plic_handler *handler, void *base, unsigned int context_id)
129+
{
130+
handler->base = base;
131+
handler->hart_base = base + CONTEXT_BASE + context_id * CONTEXT_SIZE;
132+
handler->enable_base = base + CONTEXT_ENABLE_BASE + context_id * CONTEXT_ENABLE_SIZE;
133+
}

libcpu/risc-v/plic/plic.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) 2006-2021, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2021-05-20 bigmagic first version
9+
* 2021-10-20 bernard fix s-mode issue
10+
*/
11+
12+
#ifndef __PLIC_H__
13+
#define __PLIC_H__
14+
15+
struct plic_handler
16+
{
17+
void *base;
18+
void *hart_base;
19+
void *enable_base;
20+
};
21+
22+
void plic_set_priority(struct plic_handler *handler, int irq, int priority);
23+
void plic_irq_enable(struct plic_handler *handler, int irq);
24+
void plic_irq_disable(struct plic_handler *handler, int irq);
25+
void plic_set_threshold(struct plic_handler *handler, int mthreshold);
26+
int plic_claim(struct plic_handler *handler);
27+
void plic_complete(struct plic_handler *handler, int irq);
28+
void plic_handler_init(struct plic_handler *handler, void *base, unsigned int context_id);
29+
30+
#endif

0 commit comments

Comments
 (0)