[dev][interrupt][riscv_plic] merge now 3 implementations of the same plic driver into one
Move a copy of the PLIC driver out of one of the platforms and make the setup of the interrupt controller a bit more dynamic.
This commit is contained in:
29
dev/interrupt/riscv_plic/include/dev/interrupt/riscv_plic.h
Normal file
29
dev/interrupt/riscv_plic/include/dev/interrupt/riscv_plic.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <lk/compiler.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_CDECLS
|
||||
|
||||
// Called at early initialization time, generally platform_early_init.
|
||||
// Arguments are base address of mapped registers, number of fixed irqs,
|
||||
// and a special third argument.
|
||||
//
|
||||
// hart0_m_only is used to tell the PLIC to assume that hart0 only has machine
|
||||
// mode, and occupies only one target on the PLIC. So far Sifive and other similar
|
||||
// designs use this, whereas flatter designs do not. See plic.c for more details.
|
||||
void plic_early_init(uintptr_t base, size_t num_irqs_, bool hart0_m_only);
|
||||
|
||||
void plic_init(void);
|
||||
|
||||
__END_CDECLS
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "platform_p.h"
|
||||
#include <dev/interrupt/riscv_plic.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/err.h>
|
||||
@@ -15,24 +15,33 @@
|
||||
#include <kernel/debug.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/jh7110.h>
|
||||
|
||||
// Driver for simplic PLIC implementations for various RISC-V machines.
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// Driver for PLIC implementation for qemu riscv virt machine
|
||||
#define PLIC_PRIORITY(irq) (PLIC_BASE_VIRT + 4 * (irq))
|
||||
#define PLIC_PENDING(irq) (PLIC_BASE_VIRT + 0x1000 + (4 * ((irq) / 32)))
|
||||
#define PLIC_ENABLE(irq, hart) (PLIC_BASE_VIRT + 0x2000 + (0x80 * plic_hart_index(hart)) + (4 * ((irq) / 32)))
|
||||
#define PLIC_THRESHOLD(hart) (PLIC_BASE_VIRT + 0x200000 + (0x1000 * plic_hart_index(hart)))
|
||||
#define PLIC_COMPLETE(hart) (PLIC_BASE_VIRT + 0x200004 + (0x1000 * plic_hart_index(hart)))
|
||||
#define PLIC_CLAIM(hart) PLIC_COMPLETE(hart)
|
||||
|
||||
// Preallocate space for up to 128 vectors.
|
||||
// If more are needed will need to bump this up or switch to a dynamic scheme.
|
||||
#define MAX_IRQS 128
|
||||
static struct int_handlers {
|
||||
int_handler handler;
|
||||
void *arg;
|
||||
} handlers[NUM_IRQS];
|
||||
} handlers[MAX_IRQS];
|
||||
|
||||
// Mapping of HART to interrupt target is annoyingly complex:
|
||||
static uintptr_t plic_base_virt = 0;
|
||||
static size_t num_irqs = 0;
|
||||
static bool hart0_m_only = false;
|
||||
|
||||
#define PLIC_PRIORITY(irq) (plic_base_virt + 4 * (irq))
|
||||
#define PLIC_PENDING(irq) (plic_base_virt + 0x1000 + (4 * ((irq) / 32)))
|
||||
#define PLIC_ENABLE(irq, hart) (plic_base_virt + 0x2000 + (0x80 * plic_hart_index(hart)) + (4 * ((irq) / 32)))
|
||||
#define PLIC_THRESHOLD(hart) (plic_base_virt + 0x200000 + (0x1000 * plic_hart_index(hart)))
|
||||
#define PLIC_COMPLETE(hart) (plic_base_virt + 0x200004 + (0x1000 * plic_hart_index(hart)))
|
||||
#define PLIC_CLAIM(hart) PLIC_COMPLETE(hart)
|
||||
|
||||
// Mapping of HART to interrupt target is annoyingly complex. Switch between two modes
|
||||
// based on the hart0_m_only bool:
|
||||
//
|
||||
// On the JH7110 (like other sifive socs) the first HART only has one mode, machine
|
||||
// and the subsequent harts have both machine and supervisor. The interrupt targets
|
||||
// are thus indexed:
|
||||
@@ -43,24 +52,49 @@ static struct int_handlers {
|
||||
// HART 2 supervisor mode = 4
|
||||
// ...
|
||||
//
|
||||
// On flatter designs, such as qemu's 'virt' machine, all harts are equal and 0 indexed,
|
||||
// so the mapping is simpler:
|
||||
// HART 0 machine mode = 0
|
||||
// HART 0 supervisor mode = 1
|
||||
// HART 1 machine mode = 2
|
||||
// HART 1 supervisor mode = 3
|
||||
// HART 2 machine mode = 4
|
||||
// HART 2 supervisor mode = 5
|
||||
// ...
|
||||
//
|
||||
// This routine maps harts to the current mode's interrupt target
|
||||
static unsigned int plic_hart_index(unsigned int hart) {
|
||||
unsigned int index;
|
||||
if (hart0_m_only) {
|
||||
#if RISCV_M_MODE
|
||||
index = (hart == 0) ? 0 : (2 * hart - 1);
|
||||
index = (hart == 0) ? 0 : (2 * hart - 1);
|
||||
#elif RISCV_S_MODE
|
||||
DEBUG_ASSERT(hart != 0);
|
||||
index = 2 * hart;
|
||||
DEBUG_ASSERT(hart != 0);
|
||||
index = 2 * hart;
|
||||
#else
|
||||
#error undefined
|
||||
#endif
|
||||
} else {
|
||||
#if RISCV_M_MODE
|
||||
index = 2 * hart;
|
||||
#elif RISCV_S_MODE
|
||||
index = 2 * hart + 1;
|
||||
#else
|
||||
#error undefined
|
||||
#endif
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void plic_early_init(void) {
|
||||
void plic_early_init(uintptr_t base, size_t num_irqs_, bool hart0_m_only_) {
|
||||
plic_base_virt = base;
|
||||
DEBUG_ASSERT(num_irqs_ <= MAX_IRQS);
|
||||
num_irqs = num_irqs_;
|
||||
hart0_m_only = hart0_m_only_;
|
||||
|
||||
// mask all irqs and set their priority to 1
|
||||
// TODO: mask on all the other cpus too
|
||||
for (int i = 1; i < NUM_IRQS; i++) {
|
||||
for (size_t i = 1; i < num_irqs; i++) {
|
||||
*REG32(PLIC_ENABLE(i, riscv_current_hart())) &= ~(1 << (i % 32));
|
||||
*REG32(PLIC_PRIORITY(i)) = 1;
|
||||
}
|
||||
@@ -69,8 +103,7 @@ void plic_early_init(void) {
|
||||
*REG32(PLIC_THRESHOLD(riscv_current_hart())) = 0;
|
||||
}
|
||||
|
||||
void plic_init(void) {
|
||||
}
|
||||
void plic_init(void) {}
|
||||
|
||||
status_t mask_interrupt(unsigned int vector) {
|
||||
LTRACEF("vector %u, current hart %u\n", vector, riscv_current_hart());
|
||||
@@ -88,7 +121,7 @@ status_t unmask_interrupt(unsigned int vector) {
|
||||
void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
|
||||
LTRACEF("vector %u handler %p arg %p, hart %u\n", vector, handler, arg, riscv_current_hart());
|
||||
|
||||
DEBUG_ASSERT(vector < NUM_IRQS);
|
||||
DEBUG_ASSERT(vector < num_irqs);
|
||||
|
||||
handlers[vector].handler = handler;
|
||||
handlers[vector].arg = arg;
|
||||
@@ -124,17 +157,3 @@ enum handler_return riscv_platform_irq(void) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {
|
||||
// at the moment there's no translation between PCI IRQs and native irqs
|
||||
*vector = pci_int;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t platform_allocate_interrupts(size_t count, uint align_log2, bool msi, unsigned int *vector) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool edge,
|
||||
uint64_t *msi_address_out, uint16_t *msi_data_out) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
7
dev/interrupt/riscv_plic/rules.mk
Normal file
7
dev/interrupt/riscv_plic/rules.mk
Normal file
@@ -0,0 +1,7 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/plic.c
|
||||
|
||||
include make/module.mk
|
||||
@@ -22,7 +22,7 @@
|
||||
// interrupts
|
||||
#define IRQ_VIRTIO_BASE 1
|
||||
#define IRQ_UART0 0x20
|
||||
#define NUM_IRQS 127
|
||||
#define NUM_IRQS 128
|
||||
|
||||
// addresses of some peripherals
|
||||
#define CLINT_BASE 0x02000000
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <platform/jh7110.h>
|
||||
#include <sys/types.h>
|
||||
#include <lib/fdtwalk.h>
|
||||
#include <dev/interrupt/riscv_plic.h>
|
||||
#if WITH_LIB_MINIP
|
||||
#include <lib/minip.h>
|
||||
#endif
|
||||
@@ -106,7 +107,7 @@ static void pciecallback(const struct fdt_walk_pcie_info *info, void *cookie) {
|
||||
|
||||
void platform_early_init(void) {
|
||||
TRACE;
|
||||
plic_early_init();
|
||||
plic_early_init(PLIC_BASE_VIRT, NUM_IRQS, true);
|
||||
|
||||
LTRACEF("starting FDT scan\n");
|
||||
|
||||
|
||||
@@ -11,7 +11,4 @@
|
||||
|
||||
void uart_init(void);
|
||||
|
||||
void plic_early_init(void);
|
||||
void plic_init(void);
|
||||
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ RISCV_MMU ?= sv39
|
||||
MODULE_DEPS += lib/cbuf
|
||||
MODULE_DEPS += lib/fdt
|
||||
MODULE_DEPS += lib/fdtwalk
|
||||
MODULE_DEPS += dev/interrupt/riscv_plic
|
||||
#MODULE_DEPS += dev/bus/pci
|
||||
#MODULE_DEPS += dev/bus/pci/drivers
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/platform.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/plic.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/uart.c
|
||||
|
||||
MEMBASE ?= 0x40000000
|
||||
|
||||
@@ -11,12 +11,6 @@
|
||||
//
|
||||
// mostly taken from the top of qemu/hw/riscv/virt.c and similar headers
|
||||
|
||||
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
|
||||
#define PLIC_HART_IDX(hart) (2 * (hart))
|
||||
#elif RISCV_XMODE_OFFSET == RISCV_SUPER_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((2 * (hart)) + 1)
|
||||
#endif
|
||||
|
||||
#define MEMORY_BASE_PHYS (0x80000000)
|
||||
#if __riscv_xlen == 64
|
||||
// up to 64 GB of ram, which seems to be a soft cap
|
||||
@@ -42,7 +36,7 @@
|
||||
#define IRQ_VIRTIO_BASE 1
|
||||
#define IRQ_UART0 10
|
||||
#define IRQ_PCIE_BASE 0x20
|
||||
#define NUM_IRQS 127
|
||||
#define NUM_IRQS 128
|
||||
|
||||
// addresses of some peripherals
|
||||
#define CLINT_BASE 0x02000000
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <dev/bus/pci.h>
|
||||
#include <dev/virtio.h>
|
||||
#include <dev/virtio/net.h>
|
||||
#include <dev/interrupt/riscv_plic.h>
|
||||
#if WITH_LIB_MINIP
|
||||
#include <lib/minip.h>
|
||||
#endif
|
||||
@@ -112,7 +113,7 @@ static void pciecallback(const struct fdt_walk_pcie_info *info, void *cookie) {
|
||||
}
|
||||
|
||||
void platform_early_init(void) {
|
||||
plic_early_init();
|
||||
plic_early_init(PLIC_BASE_VIRT, NUM_IRQS, false);
|
||||
|
||||
LTRACEF("starting FDT scan\n");
|
||||
|
||||
@@ -278,3 +279,18 @@ void platform_halt(platform_halt_action suggested_action,
|
||||
for (;;)
|
||||
arch_idle();
|
||||
}
|
||||
|
||||
status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {
|
||||
// at the moment there's no translation between PCI IRQs and native irqs
|
||||
*vector = pci_int;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t platform_allocate_interrupts(size_t count, uint align_log2, bool msi, unsigned int *vector) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool edge,
|
||||
uint64_t *msi_address_out, uint16_t *msi_data_out) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,4 @@
|
||||
|
||||
void uart_init(void);
|
||||
|
||||
void plic_early_init(void);
|
||||
void plic_init(void);
|
||||
|
||||
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "platform_p.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/debug.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/virt.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// Driver for PLIC implementation for qemu riscv virt machine
|
||||
#define PLIC_PRIORITY(irq) (PLIC_BASE_VIRT + 4 * (irq))
|
||||
#define PLIC_PENDING(irq) (PLIC_BASE_VIRT + 0x1000 + (4 * ((irq) / 32)))
|
||||
#define PLIC_ENABLE(irq, hart) (PLIC_BASE_VIRT + 0x2000 + (0x80 * PLIC_HART_IDX(hart)) + (4 * ((irq) / 32)))
|
||||
#define PLIC_THRESHOLD(hart) (PLIC_BASE_VIRT + 0x200000 + (0x1000 * PLIC_HART_IDX(hart)))
|
||||
#define PLIC_COMPLETE(hart) (PLIC_BASE_VIRT + 0x200004 + (0x1000 * PLIC_HART_IDX(hart)))
|
||||
#define PLIC_CLAIM(hart) PLIC_COMPLETE(hart)
|
||||
|
||||
static struct int_handlers {
|
||||
int_handler handler;
|
||||
void *arg;
|
||||
} handlers[NUM_IRQS];
|
||||
|
||||
void plic_early_init(void) {
|
||||
// mask all irqs and set their priority to 1
|
||||
// TODO: mask on all the other cpus too
|
||||
for (int i = 1; i < NUM_IRQS; i++) {
|
||||
*REG32(PLIC_ENABLE(i, riscv_current_hart())) &= ~(1 << (i % 32));
|
||||
*REG32(PLIC_PRIORITY(i)) = 1;
|
||||
}
|
||||
|
||||
// set global priority threshold to 0
|
||||
*REG32(PLIC_THRESHOLD(riscv_current_hart())) = 0;
|
||||
}
|
||||
|
||||
void plic_init(void) {
|
||||
}
|
||||
|
||||
status_t mask_interrupt(unsigned int vector) {
|
||||
*REG32(PLIC_ENABLE(vector, riscv_current_hart())) &= ~(1 << (vector % 32));
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t unmask_interrupt(unsigned int vector) {
|
||||
*REG32(PLIC_ENABLE(vector, riscv_current_hart())) |= (1 << (vector % 32));
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
|
||||
LTRACEF("vector %u handler %p arg %p\n", vector, handler, arg);
|
||||
|
||||
DEBUG_ASSERT(vector < NUM_IRQS);
|
||||
|
||||
handlers[vector].handler = handler;
|
||||
handlers[vector].arg = arg;
|
||||
}
|
||||
|
||||
void register_int_handler_msi(unsigned int vector, int_handler handler, void *arg, bool edge) {
|
||||
PANIC_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
enum handler_return riscv_platform_irq(void) {
|
||||
// see what irq triggered it
|
||||
uint32_t vector = *REG32(PLIC_CLAIM(riscv_current_hart()));
|
||||
LTRACEF("vector %u\n", vector);
|
||||
|
||||
if (unlikely(vector == 0)) {
|
||||
// nothing pending
|
||||
return INT_NO_RESCHEDULE;
|
||||
}
|
||||
|
||||
THREAD_STATS_INC(interrupts);
|
||||
KEVLOG_IRQ_ENTER(vector);
|
||||
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
if (handlers[vector].handler) {
|
||||
ret = handlers[vector].handler(handlers[vector].arg);
|
||||
}
|
||||
|
||||
// ack the interrupt
|
||||
*REG32(PLIC_COMPLETE(riscv_current_hart())) = vector;
|
||||
|
||||
KEVLOG_IRQ_EXIT(vector);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {
|
||||
// at the moment there's no translation between PCI IRQs and native irqs
|
||||
*vector = pci_int;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t platform_allocate_interrupts(size_t count, uint align_log2, bool msi, unsigned int *vector) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool edge,
|
||||
uint64_t *msi_address_out, uint16_t *msi_data_out) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -23,12 +23,12 @@ MODULE_DEPS += lib/fdt
|
||||
MODULE_DEPS += lib/fdtwalk
|
||||
MODULE_DEPS += dev/bus/pci
|
||||
MODULE_DEPS += dev/bus/pci/drivers
|
||||
MODULE_DEPS += dev/interrupt/riscv_plic
|
||||
MODULE_DEPS += dev/virtio/block
|
||||
MODULE_DEPS += dev/virtio/gpu
|
||||
MODULE_DEPS += dev/virtio/net
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/platform.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/plic.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/uart.c
|
||||
|
||||
MEMBASE ?= 0x80000000
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/reg.h>
|
||||
#include <sys/types.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/debug.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform/sifive.h>
|
||||
#include <sys/types.h>
|
||||
#include <dev/interrupt/riscv_plic.h>
|
||||
|
||||
#include "platform_p.h"
|
||||
|
||||
@@ -21,7 +22,7 @@ void platform_early_init(void) {
|
||||
|
||||
sifive_uart_early_init();
|
||||
|
||||
plic_early_init();
|
||||
plic_early_init(PLIC_BASE, SIFIVE_NUM_IRQS, true);
|
||||
}
|
||||
|
||||
void platform_init(void) {
|
||||
|
||||
@@ -14,9 +14,6 @@ int sifive_uart_read(char *c, bool wait);
|
||||
void sifive_uart_early_init(void);
|
||||
void sifive_uart_init(void);
|
||||
|
||||
void plic_early_init(void);
|
||||
void plic_init(void);
|
||||
|
||||
void gpio_early_init(void);
|
||||
void gpio_init(void);
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "platform_p.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/debug.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/sifive.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// Driver for PLIC implementation in SiFive E and U boards
|
||||
|
||||
#define PLIC_PRIORITY(irq) (PLIC_BASE + 4 * (irq))
|
||||
#define PLIC_PENDING(irq) (PLIC_BASE + 0x1000 + (4 * ((irq) / 32)))
|
||||
#define PLIC_ENABLE(irq, hart) (PLIC_BASE + 0x2000 + (0x80 * PLIC_HART_IDX(hart)) + (4 * ((irq) / 32)))
|
||||
#define PLIC_THRESHOLD(hart) (PLIC_BASE + 0x200000 + (0x1000 * PLIC_HART_IDX(hart)))
|
||||
#define PLIC_COMPLETE(hart) (PLIC_BASE + 0x200004 + (0x1000 * PLIC_HART_IDX(hart)))
|
||||
#define PLIC_CLAIM(hart) PLIC_COMPLETE(hart)
|
||||
|
||||
static struct int_handlers {
|
||||
int_handler handler;
|
||||
void *arg;
|
||||
} handlers[SIFIVE_NUM_IRQS];
|
||||
|
||||
void plic_early_init(void) {
|
||||
// mask all irqs and set their priority to 1
|
||||
for (int i = 1; i < SIFIVE_NUM_IRQS; i++) {
|
||||
*REG32(PLIC_ENABLE(i, riscv_current_hart())) &= ~(1 << (i % 32));
|
||||
*REG32(PLIC_PRIORITY(i)) = 1;
|
||||
}
|
||||
|
||||
// set global priority threshold to 0
|
||||
*REG32(PLIC_THRESHOLD(riscv_current_hart())) = 0;
|
||||
}
|
||||
|
||||
void plic_init(void) {
|
||||
}
|
||||
|
||||
status_t mask_interrupt(unsigned int vector) {
|
||||
*REG32(PLIC_ENABLE(vector, riscv_current_hart())) &= ~(1 << (vector % 32));
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t unmask_interrupt(unsigned int vector) {
|
||||
*REG32(PLIC_ENABLE(vector, riscv_current_hart())) |= (1 << (vector % 32));
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
|
||||
LTRACEF("vector %u handler %p arg %p\n", vector, handler, arg);
|
||||
|
||||
DEBUG_ASSERT(vector < SIFIVE_NUM_IRQS);
|
||||
|
||||
handlers[vector].handler = handler;
|
||||
handlers[vector].arg = arg;
|
||||
}
|
||||
|
||||
enum handler_return riscv_platform_irq(void) {
|
||||
// see what irq triggered it
|
||||
uint32_t vector = *REG32(PLIC_CLAIM(riscv_current_hart()));
|
||||
LTRACEF("vector %u\n", vector);
|
||||
|
||||
if (unlikely(vector == 0)) {
|
||||
// nothing pending
|
||||
return INT_NO_RESCHEDULE;
|
||||
}
|
||||
|
||||
THREAD_STATS_INC(interrupts);
|
||||
KEVLOG_IRQ_ENTER(vector);
|
||||
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
if (handlers[vector].handler) {
|
||||
ret = handlers[vector].handler(handlers[vector].arg);
|
||||
}
|
||||
|
||||
// ack the interrupt
|
||||
*REG32(PLIC_COMPLETE(riscv_current_hart())) = vector;
|
||||
|
||||
KEVLOG_IRQ_EXIT(vector);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ SUBARCH ?= 32
|
||||
VARIANT ?= sifive_e
|
||||
|
||||
MODULE_DEPS += dev/gpio
|
||||
MODULE_DEPS += dev/interrupt/riscv_plic
|
||||
MODULE_DEPS += lib/cbuf
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/platform.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/plic.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/uart.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/gpio.c
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#define SIFIVE_IRQ_UART0 4
|
||||
#define SIFIVE_IRQ_UART1 5
|
||||
|
||||
#define SIFIVE_NUM_IRQS 127
|
||||
#define SIFIVE_NUM_IRQS 128
|
||||
|
||||
#define CLINT_BASE 0x02000000
|
||||
#define PLIC_BASE 0x0c000000
|
||||
@@ -18,8 +18,3 @@
|
||||
#define UART1_BASE 0x10011000
|
||||
#define GPIO_BASE 0x10060000
|
||||
|
||||
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((hart) ? ((2 * (hart)) - 1) : 0)
|
||||
#elif RISCV_XMODE_OFFSET == RISCV_SUPER_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((hart) ? (2 * (hart)) : ~0U)
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,5 @@
|
||||
#define GPIO_REG_IOF_EN 14
|
||||
#define GPIO_REG_IOF_SEL 15
|
||||
|
||||
#define PLIC_HART_IDX(hart) 0
|
||||
|
||||
#define GPIO_AF0 (1U << 16)
|
||||
#define GPIO_AF1 (1U << 17)
|
||||
|
||||
@@ -20,9 +20,3 @@
|
||||
#define PWM0_BASE 0x10020000
|
||||
#define PWM1_BASE 0x10021000
|
||||
#define GPIO_BASE 0x10060000
|
||||
|
||||
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((hart) ? ((2 * (hart)) - 1) : 0)
|
||||
#elif RISCV_XMODE_OFFSET == RISCV_SUPER_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((hart) ? (2 * (hart)) : ~0U)
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user