-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[riscv]统一plic和中断控制的接口实现 #10147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
heyuanjie87
wants to merge
2
commits into
RT-Thread:master
Choose a base branch
from
heyuanjie87:plic
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[riscv]统一plic和中断控制的接口实现 #10147
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* | ||
* Copyright (c) 2006-2021, RT-Thread Development Team | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Change Logs: | ||
* Date Author Notes | ||
* 2018/10/01 Bernard The first version | ||
* 2018/12/27 Jesven Change irq enable/disable to cpu0 | ||
*/ | ||
#include <rtthread.h> | ||
#include <plic.h> | ||
#include <rthw.h> | ||
#include "encoding.h" | ||
#include "riscv.h" | ||
#include "interrupt.h" | ||
|
||
#ifdef RT_USING_SMART | ||
#include <ioremap.h> | ||
#endif | ||
|
||
/* TODO define PLIC_PHY_ADDR in BSP and remove me */ | ||
#ifdef C908_PLIC_PHY_ADDR | ||
#define PLIC_PHY_ADDR C908_PLIC_PHY_ADDR | ||
#elif defined(C906_PLIC_PHY_ADDR) | ||
#define PLIC_PHY_ADDR C906_PLIC_PHY_ADDR | ||
#elif !defined(PLIC_PHY_ADDR) | ||
#define PLIC_PHY_ADDR 0x0c000000L | ||
#endif | ||
|
||
static struct rt_irq_desc isr_table[INTERRUPTS_MAX]; | ||
static struct plic_handler plic_handlers[1]; | ||
|
||
rt_inline struct plic_handler *plic_handler_get(void) | ||
{ | ||
return &plic_handlers[0]; | ||
} | ||
|
||
static void plic_init(void) | ||
{ | ||
void *plic_base = (void *)PLIC_PHY_ADDR; | ||
|
||
#ifdef RT_USING_SMART | ||
// PLIC takes up 64 MB space | ||
plic_base = rt_ioremap(plic_base, 64 * 1024 * 1024); | ||
#endif | ||
/* skip contexts other than supervisor external interrupt */ | ||
plic_handler_init(plic_handler_get(), plic_base, 1); | ||
|
||
plic_set_threshold(plic_handler_get(), 0); | ||
} | ||
|
||
static void rt_hw_interrupt_handle(int vector, void *param) | ||
{ | ||
rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector); | ||
} | ||
|
||
/** | ||
* This function will mask a interrupt. | ||
* @param vector the interrupt number | ||
*/ | ||
void rt_hw_interrupt_mask(int vector) | ||
{ | ||
if ((vector < 0) || (vector > IRQ_MAX_NR)) | ||
{ | ||
return; | ||
} | ||
|
||
plic_irq_disable(plic_handler_get(), vector); | ||
} | ||
|
||
/** | ||
* This function will un-mask a interrupt. | ||
* @param vector the interrupt number | ||
*/ | ||
void rt_hw_interrupt_umask(int vector) | ||
{ | ||
if ((vector < 0) || (vector > IRQ_MAX_NR)) | ||
{ | ||
return; | ||
} | ||
|
||
plic_set_priority(plic_handler_get(), vector, 1); | ||
|
||
plic_irq_enable(plic_handler_get(), vector); | ||
} | ||
|
||
/** | ||
* This function will install a interrupt service routine to a interrupt. | ||
* @param vector the interrupt number | ||
* @param new_handler the interrupt service routine to be installed | ||
* @param old_handler the old interrupt service routine | ||
*/ | ||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, | ||
void *param, const char *name) | ||
{ | ||
rt_isr_handler_t old_handler = RT_NULL; | ||
|
||
if ((vector < 0) || (vector > IRQ_MAX_NR)) | ||
{ | ||
return old_handler; | ||
} | ||
|
||
old_handler = isr_table[IRQ_OFFSET + vector].handler; | ||
|
||
isr_table[IRQ_OFFSET + vector].handler = handler; | ||
isr_table[IRQ_OFFSET + vector].param = param; | ||
|
||
return old_handler; | ||
} | ||
|
||
void rt_hw_interrupt_init(void) | ||
{ | ||
/* init exceptions table */ | ||
for (int idx = 0; idx < INTERRUPTS_MAX; idx++) | ||
{ | ||
isr_table[idx].handler = rt_hw_interrupt_handle; | ||
isr_table[idx].param = RT_NULL; | ||
} | ||
|
||
plic_init(); | ||
|
||
/* Enable supervisor external interrupts. */ | ||
set_csr(sie, SIE_SEIE); | ||
} | ||
|
||
/* | ||
* Handling an interrupt is a two-step process: first you claim the interrupt | ||
* by reading the claim register, then you complete the interrupt by writing | ||
* that source ID back to the same claim register. This automatically enables | ||
* and disables the interrupt, so there's nothing else to do. | ||
*/ | ||
void plic_handle_irq(void) | ||
{ | ||
struct plic_handler *plic; | ||
rt_isr_handler_t isr; | ||
void *param; | ||
int irq; | ||
|
||
plic = plic_handler_get(); | ||
|
||
while ((irq = plic_claim(plic))) | ||
{ | ||
isr = isr_table[IRQ_OFFSET + irq].handler; | ||
param = isr_table[IRQ_OFFSET + irq].param; | ||
if (isr) | ||
{ | ||
isr(irq, param); | ||
} | ||
|
||
plic_complete(plic, irq); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# RT-Thread building script for component | ||
|
||
from building import * | ||
cwd = GetCurrentDir() | ||
src = [] | ||
CPPPATH = [] | ||
|
||
src += Glob('*.c') | ||
CPPPATH += [cwd] | ||
|
||
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH) | ||
|
||
Return('group') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
* Copyright (c) 2006-2021, RT-Thread Development Team | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Change Logs: | ||
* Date Author Notes | ||
* 2021-05-20 bigmagic first version | ||
* 2022-09-16 WangXiaoyao Porting to rv64 | ||
*/ | ||
#include <rtdef.h> | ||
#include "plic.h" | ||
#include <riscv_io.h> | ||
|
||
/* | ||
* Each interrupt source has a priority register associated with it. | ||
* We always hardwire it to one in Linux. | ||
*/ | ||
#define PRIORITY_BASE 0 | ||
#define PRIORITY_PER_ID 4 | ||
|
||
/* | ||
* Each hart context has a vector of interrupt enable bits associated with it. | ||
* There's one bit for each interrupt source. | ||
*/ | ||
#define CONTEXT_ENABLE_BASE 0x2000 | ||
#define CONTEXT_ENABLE_SIZE 0x80 | ||
|
||
/* | ||
* Each hart context has a set of control registers associated with it. Right | ||
* now there's only two: a source priority threshold over which the hart will | ||
* take an interrupt, and a register to claim interrupts. | ||
*/ | ||
#define CONTEXT_BASE 0x200000 | ||
#define CONTEXT_SIZE 0x1000 | ||
#define CONTEXT_THRESHOLD 0x00 | ||
#define CONTEXT_CLAIM 0x04 | ||
|
||
static void plic_toggle(struct plic_handler *handler, unsigned int irq, int enable) | ||
{ | ||
void *reg = handler->enable_base + (irq / 32) * sizeof(unsigned int); | ||
unsigned int hwirq_mask = 1 << (irq % 32); | ||
|
||
if (enable) | ||
writel(readl(reg) | hwirq_mask, reg); | ||
else | ||
writel(readl(reg) & ~hwirq_mask, reg); | ||
} | ||
|
||
/* | ||
* Each PLIC interrupt source can be assigned a priority by writing | ||
* to its 32-bit memory-mapped priority register. | ||
* The QEMU-virt (the same as FU540-C000) supports 7 levels of priority. | ||
* A priority value of 0 is reserved to mean "never interrupt" and | ||
* effectively disables the interrupt. | ||
* Priority 1 is the lowest active priority, and priority 7 is the highest. | ||
* Ties between global interrupts of the same priority are broken by | ||
* the Interrupt ID; interrupts with the lowest ID have the highest | ||
* effective priority. | ||
*/ | ||
void plic_set_priority(struct plic_handler *handler, int irq, int priority) | ||
{ | ||
writel(priority, handler->base + PRIORITY_BASE + irq * PRIORITY_PER_ID); | ||
} | ||
|
||
/* | ||
* Each global interrupt can be enabled by setting the corresponding | ||
* bit in the enables registers. | ||
*/ | ||
void plic_irq_enable(struct plic_handler *handler, int irq) | ||
{ | ||
plic_toggle(handler, irq, 1); | ||
} | ||
|
||
void plic_irq_disable(struct plic_handler *handler, int irq) | ||
{ | ||
plic_toggle(handler, irq, 1); | ||
} | ||
|
||
/* | ||
* PLIC will mask all interrupts of a priority less than or equal to threshold. | ||
* Maximum threshold is 7. | ||
* For example, a threshold value of zero permits all interrupts with | ||
* non-zero priority, whereas a value of 7 masks all interrupts. | ||
* Notice, the threshold is global for PLIC, not for each interrupt source. | ||
*/ | ||
void plic_set_threshold(struct plic_handler *handler, int threshold) | ||
{ | ||
writel(threshold, handler->hart_base + CONTEXT_THRESHOLD); | ||
} | ||
|
||
/* | ||
* DESCRIPTION: | ||
* Query the PLIC what interrupt we should serve. | ||
* Perform an interrupt claim by reading the claim register, which | ||
* returns the ID of the highest-priority pending interrupt or zero if there | ||
* is no pending interrupt. | ||
* A successful claim also atomically clears the corresponding pending bit | ||
* on the interrupt source. | ||
* RETURN VALUE: | ||
* the ID of the highest-priority pending interrupt or zero if there | ||
* is no pending interrupt. | ||
*/ | ||
int plic_claim(struct plic_handler *handler) | ||
{ | ||
void *claim = handler->hart_base + CONTEXT_CLAIM; | ||
|
||
return readl(claim); | ||
} | ||
|
||
/* | ||
* DESCRIPTION: | ||
* Writing the interrupt ID it received from the claim (irq) to the | ||
* complete register would signal the PLIC we've served this IRQ. | ||
* The PLIC does not check whether the completion ID is the same as the | ||
* last claim ID for that target. If the completion ID does not match an | ||
* interrupt source that is currently enabled for the target, the completion | ||
* is silently ignored. | ||
* RETURN VALUE: none | ||
*/ | ||
void plic_complete(struct plic_handler *handler, int irq) | ||
{ | ||
void *claim = handler->hart_base + CONTEXT_CLAIM; | ||
|
||
writel(irq, claim); | ||
} | ||
|
||
void plic_handler_init(struct plic_handler *handler, void *base, unsigned int context_id) | ||
{ | ||
handler->base = base; | ||
handler->hart_base = base + CONTEXT_BASE + context_id * CONTEXT_SIZE; | ||
handler->enable_base = base + CONTEXT_ENABLE_BASE + context_id * CONTEXT_ENABLE_SIZE; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Copyright (c) 2006-2021, RT-Thread Development Team | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Change Logs: | ||
* Date Author Notes | ||
* 2021-05-20 bigmagic first version | ||
* 2021-10-20 bernard fix s-mode issue | ||
*/ | ||
|
||
#ifndef __PLIC_H__ | ||
#define __PLIC_H__ | ||
|
||
struct plic_handler | ||
{ | ||
void *base; | ||
void *hart_base; | ||
void *enable_base; | ||
}; | ||
|
||
void plic_set_priority(struct plic_handler *handler, int irq, int priority); | ||
void plic_irq_enable(struct plic_handler *handler, int irq); | ||
void plic_irq_disable(struct plic_handler *handler, int irq); | ||
void plic_set_threshold(struct plic_handler *handler, int mthreshold); | ||
int plic_claim(struct plic_handler *handler); | ||
void plic_complete(struct plic_handler *handler, int irq); | ||
void plic_handler_init(struct plic_handler *handler, void *base, unsigned int context_id); | ||
|
||
#endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.