mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
o Add driver for PLIC (Platform-Level Interrupt Controller) device.
o Convert interrupt machdep support to use INTRNG code. Sponsored by: DARPA, AFRL
This commit is contained in:
parent
ebdf0baf3a
commit
2d53a67c2c
12 changed files with 354 additions and 139 deletions
|
|
@ -9,8 +9,11 @@ dev/ofw/ofw_cpu.c optional fdt
|
||||||
dev/uart/uart_cpu_fdt.c optional uart fdt
|
dev/uart/uart_cpu_fdt.c optional uart fdt
|
||||||
dev/xilinx/axi_quad_spi.c optional xilinx_spi
|
dev/xilinx/axi_quad_spi.c optional xilinx_spi
|
||||||
kern/kern_clocksource.c standard
|
kern/kern_clocksource.c standard
|
||||||
|
kern/msi_if.m standard
|
||||||
|
kern/pic_if.m standard
|
||||||
kern/subr_devmap.c standard
|
kern/subr_devmap.c standard
|
||||||
kern/subr_dummy_vdso_tc.c standard
|
kern/subr_dummy_vdso_tc.c standard
|
||||||
|
kern/subr_intr.c standard
|
||||||
libkern/bcmp.c standard
|
libkern/bcmp.c standard
|
||||||
libkern/bcopy.c standard
|
libkern/bcopy.c standard
|
||||||
libkern/ffs.c standard
|
libkern/ffs.c standard
|
||||||
|
|
@ -44,6 +47,7 @@ riscv/riscv/mp_machdep.c optional smp
|
||||||
riscv/riscv/mem.c standard
|
riscv/riscv/mem.c standard
|
||||||
riscv/riscv/nexus.c standard
|
riscv/riscv/nexus.c standard
|
||||||
riscv/riscv/ofw_machdep.c optional fdt
|
riscv/riscv/ofw_machdep.c optional fdt
|
||||||
|
riscv/riscv/plic.c standard
|
||||||
riscv/riscv/pmap.c standard
|
riscv/riscv/pmap.c standard
|
||||||
riscv/riscv/riscv_console.c optional rcons
|
riscv/riscv/riscv_console.c optional rcons
|
||||||
riscv/riscv/soc.c standard
|
riscv/riscv/soc.c standard
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
RISCV opt_global.h
|
RISCV opt_global.h
|
||||||
FPE opt_global.h
|
FPE opt_global.h
|
||||||
|
INTRNG opt_global.h
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ options RACCT # Resource accounting framework
|
||||||
options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default
|
options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default
|
||||||
options RCTL # Resource limits
|
options RCTL # Resource limits
|
||||||
options SMP
|
options SMP
|
||||||
|
options INTRNG
|
||||||
|
|
||||||
# RISC-V SBI console
|
# RISC-V SBI console
|
||||||
device rcons
|
device rcons
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,19 @@
|
||||||
#ifndef _MACHINE_INTR_MACHDEP_H_
|
#ifndef _MACHINE_INTR_MACHDEP_H_
|
||||||
#define _MACHINE_INTR_MACHDEP_H_
|
#define _MACHINE_INTR_MACHDEP_H_
|
||||||
|
|
||||||
|
#define RISCV_NIRQ 1024
|
||||||
|
|
||||||
|
#ifndef NIRQ
|
||||||
|
#define NIRQ RISCV_NIRQ
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INTRNG
|
||||||
|
#include <sys/intr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct trapframe;
|
struct trapframe;
|
||||||
|
|
||||||
void riscv_init_interrupts(void);
|
|
||||||
int riscv_teardown_intr(void *);
|
int riscv_teardown_intr(void *);
|
||||||
int riscv_config_intr(u_int, enum intr_trigger, enum intr_polarity);
|
|
||||||
int riscv_setup_intr(const char *, driver_filter_t *, driver_intr_t *,
|
int riscv_setup_intr(const char *, driver_filter_t *, driver_intr_t *,
|
||||||
void *, int, int, void **);
|
void *, int, int, void **);
|
||||||
void riscv_cpu_intr(struct trapframe *);
|
void riscv_cpu_intr(struct trapframe *);
|
||||||
|
|
@ -69,12 +77,7 @@ enum {
|
||||||
IRQ_EXTERNAL_SUPERVISOR,
|
IRQ_EXTERNAL_SUPERVISOR,
|
||||||
IRQ_EXTERNAL_HYPERVISOR,
|
IRQ_EXTERNAL_HYPERVISOR,
|
||||||
IRQ_EXTERNAL_MACHINE,
|
IRQ_EXTERNAL_MACHINE,
|
||||||
#if 0
|
INTC_NIRQS
|
||||||
/* lowRISC TODO */
|
|
||||||
IRQ_COP, /* lowRISC only */
|
|
||||||
IRQ_UART, /* lowRISC only */
|
|
||||||
#endif
|
|
||||||
NIRQS
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* !_MACHINE_INTR_MACHDEP_H_ */
|
#endif /* !_MACHINE_INTR_MACHDEP_H_ */
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,8 @@
|
||||||
#define SIE_SSIE (1 << 1)
|
#define SIE_SSIE (1 << 1)
|
||||||
#define SIE_UTIE (1 << 4)
|
#define SIE_UTIE (1 << 4)
|
||||||
#define SIE_STIE (1 << 5)
|
#define SIE_STIE (1 << 5)
|
||||||
|
#define SIE_UEIE (1 << 8)
|
||||||
|
#define SIE_SEIE (1 << 9)
|
||||||
|
|
||||||
#define MIP_SEIP (1 << 9)
|
#define MIP_SEIP (1 << 9)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
#define IPI_STOP_HARD (1 << 4)
|
#define IPI_STOP_HARD (1 << 4)
|
||||||
#define IPI_HARDCLOCK (1 << 5)
|
#define IPI_HARDCLOCK (1 << 5)
|
||||||
|
|
||||||
|
#define INTR_IPI_COUNT 1
|
||||||
|
|
||||||
void ipi_all_but_self(u_int ipi);
|
void ipi_all_but_self(u_int ipi);
|
||||||
void ipi_cpu(int cpu, u_int ipi);
|
void ipi_cpu(int cpu, u_int ipi);
|
||||||
void ipi_selected(cpuset_t cpus, u_int ipi);
|
void ipi_selected(cpuset_t cpus, u_int ipi);
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,13 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/bus.h>
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
#include <sys/cpuset.h>
|
#include <sys/cpuset.h>
|
||||||
#include <sys/interrupt.h>
|
#include <sys/interrupt.h>
|
||||||
#include <sys/smp.h>
|
#include <sys/smp.h>
|
||||||
#include <sys/vmmeter.h>
|
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
#include <machine/clock.h>
|
#include <machine/clock.h>
|
||||||
#include <machine/cpu.h>
|
#include <machine/cpu.h>
|
||||||
#include <machine/cpufunc.h>
|
#include <machine/cpufunc.h>
|
||||||
|
|
@ -50,44 +52,22 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <machine/intr.h>
|
#include <machine/intr.h>
|
||||||
#include <machine/sbi.h>
|
#include <machine/sbi.h>
|
||||||
|
|
||||||
|
#include <dev/ofw/openfirm.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
#ifdef SMP
|
#ifdef SMP
|
||||||
#include <machine/smp.h>
|
#include <machine/smp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u_long intrcnt[NIRQS];
|
void intr_irq_handler(struct trapframe *tf);
|
||||||
size_t sintrcnt = sizeof(intrcnt);
|
|
||||||
|
|
||||||
char intrnames[NIRQS * (MAXCOMLEN + 1) * 2];
|
struct intc_irqsrc {
|
||||||
size_t sintrnames = sizeof(intrnames);
|
struct intr_irqsrc isrc;
|
||||||
|
u_int irq;
|
||||||
|
};
|
||||||
|
|
||||||
static struct intr_event *intr_events[NIRQS];
|
struct intc_irqsrc isrcs[INTC_NIRQS];
|
||||||
static riscv_intrcnt_t riscv_intr_counters[NIRQS];
|
|
||||||
|
|
||||||
static int intrcnt_index;
|
|
||||||
|
|
||||||
riscv_intrcnt_t
|
|
||||||
riscv_intrcnt_create(const char* name)
|
|
||||||
{
|
|
||||||
riscv_intrcnt_t counter;
|
|
||||||
|
|
||||||
counter = &intrcnt[intrcnt_index++];
|
|
||||||
riscv_intrcnt_setname(counter, name);
|
|
||||||
|
|
||||||
return (counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
riscv_intrcnt_setname(riscv_intrcnt_t counter, const char *name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = (counter - intrcnt);
|
|
||||||
|
|
||||||
KASSERT(counter != NULL, ("riscv_intrcnt_setname: NULL counter"));
|
|
||||||
|
|
||||||
snprintf(intrnames + (MAXCOMLEN + 1) * i,
|
|
||||||
MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
riscv_mask_irq(void *source)
|
riscv_mask_irq(void *source)
|
||||||
|
|
@ -102,15 +82,10 @@ riscv_mask_irq(void *source)
|
||||||
break;
|
break;
|
||||||
case IRQ_SOFTWARE_USER:
|
case IRQ_SOFTWARE_USER:
|
||||||
csr_clear(sie, SIE_USIE);
|
csr_clear(sie, SIE_USIE);
|
||||||
|
break;
|
||||||
case IRQ_SOFTWARE_SUPERVISOR:
|
case IRQ_SOFTWARE_SUPERVISOR:
|
||||||
csr_clear(sie, SIE_SSIE);
|
csr_clear(sie, SIE_SSIE);
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
/* lowRISC TODO */
|
|
||||||
case IRQ_UART:
|
|
||||||
machine_command(ECALL_IO_IRQ_MASK, 0);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
panic("Unknown irq %d\n", irq);
|
panic("Unknown irq %d\n", irq);
|
||||||
}
|
}
|
||||||
|
|
@ -133,60 +108,37 @@ riscv_unmask_irq(void *source)
|
||||||
case IRQ_SOFTWARE_SUPERVISOR:
|
case IRQ_SOFTWARE_SUPERVISOR:
|
||||||
csr_set(sie, SIE_SSIE);
|
csr_set(sie, SIE_SSIE);
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
/* lowRISC TODO */
|
|
||||||
case IRQ_UART:
|
|
||||||
machine_command(ECALL_IO_IRQ_MASK, 1);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
panic("Unknown irq %d\n", irq);
|
panic("Unknown irq %d\n", irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
riscv_init_interrupts(void)
|
|
||||||
{
|
|
||||||
char name[MAXCOMLEN + 1];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < NIRQS; i++) {
|
|
||||||
snprintf(name, MAXCOMLEN + 1, "int%d:", i);
|
|
||||||
riscv_intr_counters[i] = riscv_intrcnt_create(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
riscv_setup_intr(const char *name, driver_filter_t *filt,
|
riscv_setup_intr(const char *name, driver_filter_t *filt,
|
||||||
void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
|
void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
|
||||||
{
|
{
|
||||||
struct intr_event *event;
|
struct intr_irqsrc *isrc;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (irq < 0 || irq >= NIRQS)
|
if (irq < 0 || irq >= INTC_NIRQS)
|
||||||
panic("%s: unknown intr %d", __func__, irq);
|
panic("%s: unknown intr %d", __func__, irq);
|
||||||
|
|
||||||
event = intr_events[irq];
|
isrc = &isrcs[irq].isrc;
|
||||||
if (event == NULL) {
|
if (isrc->isrc_event == NULL) {
|
||||||
error = intr_event_create(&event, (void *)(uintptr_t)irq, 0,
|
error = intr_event_create(&isrc->isrc_event, isrc, 0, irq,
|
||||||
irq, riscv_mask_irq, riscv_unmask_irq,
|
riscv_mask_irq, riscv_unmask_irq, NULL, NULL, "int%d", irq);
|
||||||
NULL, NULL, "int%d", irq);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
intr_events[irq] = event;
|
|
||||||
riscv_unmask_irq((void*)(uintptr_t)irq);
|
riscv_unmask_irq((void*)(uintptr_t)irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = intr_event_add_handler(event, name, filt, handler, arg,
|
error = intr_event_add_handler(isrc->isrc_event, name,
|
||||||
intr_priority(flags), flags, cookiep);
|
filt, handler, arg, intr_priority(flags), flags, cookiep);
|
||||||
if (error) {
|
if (error) {
|
||||||
printf("Failed to setup intr: %d\n", irq);
|
printf("Failed to setup intr: %d\n", irq);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_intrcnt_setname(riscv_intr_counters[irq],
|
|
||||||
event->ie_fullname);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,19 +151,10 @@ riscv_teardown_intr(void *ih)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
riscv_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* There is no configuration for interrupts */
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
riscv_cpu_intr(struct trapframe *frame)
|
riscv_cpu_intr(struct trapframe *frame)
|
||||||
{
|
{
|
||||||
struct intr_event *event;
|
struct intr_irqsrc *isrc;
|
||||||
int active_irq;
|
int active_irq;
|
||||||
|
|
||||||
critical_enter();
|
critical_enter();
|
||||||
|
|
@ -222,26 +165,20 @@ riscv_cpu_intr(struct trapframe *frame)
|
||||||
active_irq = (frame->tf_scause & EXCP_MASK);
|
active_irq = (frame->tf_scause & EXCP_MASK);
|
||||||
|
|
||||||
switch (active_irq) {
|
switch (active_irq) {
|
||||||
#if 0
|
|
||||||
/* lowRISC TODO */
|
|
||||||
case IRQ_UART:
|
|
||||||
#endif
|
|
||||||
case IRQ_SOFTWARE_USER:
|
case IRQ_SOFTWARE_USER:
|
||||||
case IRQ_SOFTWARE_SUPERVISOR:
|
case IRQ_SOFTWARE_SUPERVISOR:
|
||||||
case IRQ_TIMER_SUPERVISOR:
|
case IRQ_TIMER_SUPERVISOR:
|
||||||
event = intr_events[active_irq];
|
isrc = &isrcs[active_irq].isrc;
|
||||||
/* Update counters */
|
if (intr_isrc_dispatch(isrc, frame) != 0)
|
||||||
atomic_add_long(riscv_intr_counters[active_irq], 1);
|
printf("stray interrupt %d\n", active_irq);
|
||||||
VM_CNT_INC(v_intr);
|
break;
|
||||||
|
case IRQ_EXTERNAL_SUPERVISOR:
|
||||||
|
intr_irq_handler(frame);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
event = NULL;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event || TAILQ_EMPTY(&event->ie_handlers) ||
|
|
||||||
(intr_event_handle(event, frame) != 0))
|
|
||||||
printf("stray interrupt %d\n", active_irq);
|
|
||||||
|
|
||||||
critical_exit();
|
critical_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,5 +257,22 @@ ipi_selected(cpuset_t cpus, u_int ipi)
|
||||||
}
|
}
|
||||||
sbi_send_ipi(&mask);
|
sbi_send_ipi(&mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Interrupt machdep initialization routine. */
|
||||||
|
static void
|
||||||
|
intc_init(void *dummy __unused)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < INTC_NIRQS; i++) {
|
||||||
|
isrcs[i].irq = i;
|
||||||
|
error = intr_isrc_register(&isrcs[i].isrc, NULL,
|
||||||
|
0, "intc,%u", i);
|
||||||
|
if (error != 0)
|
||||||
|
printf("Can't register interrupt %d\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSINIT(intc_init, SI_SUB_INTR, SI_ORDER_MIDDLE, intc_init, NULL);
|
||||||
|
|
|
||||||
|
|
@ -872,8 +872,6 @@ initriscv(struct riscv_bootparams *rvbp)
|
||||||
init_param2(physmem);
|
init_param2(physmem);
|
||||||
kdb_init();
|
kdb_init();
|
||||||
|
|
||||||
riscv_init_interrupts();
|
|
||||||
|
|
||||||
early_boot = 0;
|
early_boot = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,9 @@ init_secondary(uint64_t cpu)
|
||||||
/* Enable interrupts */
|
/* Enable interrupts */
|
||||||
intr_enable();
|
intr_enable();
|
||||||
|
|
||||||
|
/* Enable external (PLIC) interrupts */
|
||||||
|
csr_set(sie, SIE_SEIE);
|
||||||
|
|
||||||
mtx_lock_spin(&ap_boot_mtx);
|
mtx_lock_spin(&ap_boot_mtx);
|
||||||
|
|
||||||
atomic_add_rel_32(&smp_cpus, 1);
|
atomic_add_rel_32(&smp_cpus, 1);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
* ISA code but it's easier to do it here for now), I/O port addresses,
|
* ISA code but it's easier to do it here for now), I/O port addresses,
|
||||||
* and I/O memory address space.
|
* and I/O memory address space.
|
||||||
*/
|
*/
|
||||||
|
#include "opt_platform.h"
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
@ -48,22 +49,18 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/module.h>
|
#include <sys/module.h>
|
||||||
#include <machine/bus.h>
|
|
||||||
#include <sys/rman.h>
|
#include <sys/rman.h>
|
||||||
#include <sys/interrupt.h>
|
#include <sys/interrupt.h>
|
||||||
|
|
||||||
#include <machine/vmparam.h>
|
#include <machine/bus.h>
|
||||||
#include <machine/pcb.h>
|
|
||||||
#include <vm/vm.h>
|
|
||||||
#include <vm/pmap.h>
|
|
||||||
|
|
||||||
#include <machine/resource.h>
|
#include <machine/resource.h>
|
||||||
#include <machine/intr.h>
|
#include <machine/intr.h>
|
||||||
|
|
||||||
#include "opt_platform.h"
|
#ifdef FDT
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
#include <dev/fdt/fdt_common.h>
|
#include <dev/ofw/openfirm.h>
|
||||||
#include "ofw_bus_if.h"
|
#include "ofw_bus_if.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern struct bus_space memmap_bus;
|
extern struct bus_space memmap_bus;
|
||||||
|
|
||||||
|
|
@ -265,7 +262,7 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
|
||||||
enum intr_polarity pol)
|
enum intr_polarity pol)
|
||||||
{
|
{
|
||||||
|
|
||||||
return (riscv_config_intr(irq, trig, pol));
|
return (EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -282,8 +279,7 @@ nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
error = riscv_setup_intr(device_get_nameunit(child), filt, intr,
|
error = intr_setup_irq(child, res, filt, intr, arg, flags, cookiep);
|
||||||
arg, rman_get_start(res), flags, cookiep);
|
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +288,7 @@ static int
|
||||||
nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
|
nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
|
||||||
{
|
{
|
||||||
|
|
||||||
return (riscv_teardown_intr(ih));
|
return (intr_teardown_irq(child, r, ih));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -321,7 +317,14 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||||
rman_set_bustag(r, &memmap_bus);
|
rman_set_bustag(r, &memmap_bus);
|
||||||
rman_set_virtual(r, (void *)vaddr);
|
rman_set_virtual(r, (void *)vaddr);
|
||||||
rman_set_bushandle(r, vaddr);
|
rman_set_bushandle(r, vaddr);
|
||||||
|
} else if (type == SYS_RES_IRQ) {
|
||||||
|
err = intr_activate_irq(child, r);
|
||||||
|
if (err != 0) {
|
||||||
|
rman_deactivate_resource(r);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -375,16 +378,17 @@ static int
|
||||||
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
|
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
|
||||||
pcell_t *intr)
|
pcell_t *intr)
|
||||||
{
|
{
|
||||||
int irq;
|
struct intr_map_data_fdt *fdt_data;
|
||||||
|
size_t len;
|
||||||
|
u_int irq;
|
||||||
|
|
||||||
if (icells == 3) {
|
len = sizeof(*fdt_data) + icells * sizeof(pcell_t);
|
||||||
irq = intr[1];
|
fdt_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
|
||||||
if (intr[0] == 0)
|
INTR_MAP_DATA_FDT, len, M_WAITOK | M_ZERO);
|
||||||
irq += 32; /* SPI */
|
fdt_data->iparent = iparent;
|
||||||
else
|
fdt_data->ncells = icells;
|
||||||
irq += 16; /* PPI */
|
memcpy(fdt_data->cells, intr, icells * sizeof(pcell_t));
|
||||||
} else
|
irq = intr_map_irq(NULL, iparent, (struct intr_map_data *)fdt_data);
|
||||||
irq = intr[0];
|
|
||||||
|
|
||||||
return (irq);
|
return (irq);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
254
sys/riscv/riscv/plic.c
Normal file
254
sys/riscv/riscv/plic.c
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software was developed by SRI International and the University of
|
||||||
|
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||||
|
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/ktr.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/rman.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
#include <machine/intr.h>
|
||||||
|
|
||||||
|
#include <dev/ofw/openfirm.h>
|
||||||
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
|
#include "pic_if.h"
|
||||||
|
|
||||||
|
#define PLIC_NIRQS 32
|
||||||
|
#define PLIC_PRIORITY(n) (0x000000 + (n) * 0x4)
|
||||||
|
#define PLIC_ENABLE(n, h) (0x002000 + (h) * 0x80 + (n) / 32)
|
||||||
|
#define PLIC_THRESHOLD(h) (0x200000 + (h) * 0x1000 + 0x0)
|
||||||
|
#define PLIC_CLAIM(h) (0x200000 + (h) * 0x1000 + 0x4)
|
||||||
|
|
||||||
|
struct plic_irqsrc {
|
||||||
|
struct intr_irqsrc isrc;
|
||||||
|
u_int irq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct plic_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct resource * intc_res;
|
||||||
|
struct plic_irqsrc isrcs[PLIC_NIRQS];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RD4(sc, reg) \
|
||||||
|
bus_read_4(sc->intc_res, (reg))
|
||||||
|
#define WR4(sc, reg, val) \
|
||||||
|
bus_write_4(sc->intc_res, (reg), (val))
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
plic_irq_dispatch(struct plic_softc *sc, u_int irq,
|
||||||
|
struct trapframe *tf)
|
||||||
|
{
|
||||||
|
struct plic_irqsrc *src;
|
||||||
|
|
||||||
|
src = &sc->isrcs[irq];
|
||||||
|
|
||||||
|
if (intr_isrc_dispatch(&src->isrc, tf) != 0)
|
||||||
|
device_printf(sc->dev, "Stray irq %u detected\n", irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plic_intr(void *arg)
|
||||||
|
{
|
||||||
|
struct plic_softc *sc;
|
||||||
|
struct trapframe *tf;
|
||||||
|
uint32_t pending;
|
||||||
|
uint32_t cpu;
|
||||||
|
|
||||||
|
sc = arg;
|
||||||
|
cpu = PCPU_GET(cpuid);
|
||||||
|
|
||||||
|
pending = RD4(sc, PLIC_CLAIM(cpu));
|
||||||
|
if (pending) {
|
||||||
|
tf = curthread->td_intr_frame;
|
||||||
|
plic_irq_dispatch(sc, pending, tf);
|
||||||
|
WR4(sc, PLIC_CLAIM(cpu), pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (FILTER_HANDLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
plic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct plic_softc *sc;
|
||||||
|
struct plic_irqsrc *src;
|
||||||
|
uint32_t reg;
|
||||||
|
uint32_t cpu;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
src = (struct plic_irqsrc *)isrc;
|
||||||
|
|
||||||
|
cpu = PCPU_GET(cpuid);
|
||||||
|
|
||||||
|
reg = RD4(sc, PLIC_ENABLE(src->irq, cpu));
|
||||||
|
reg &= ~(1 << (src->irq % 32));
|
||||||
|
WR4(sc, PLIC_ENABLE(src->irq, cpu), reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
plic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||||
|
{
|
||||||
|
struct plic_softc *sc;
|
||||||
|
struct plic_irqsrc *src;
|
||||||
|
uint32_t reg;
|
||||||
|
uint32_t cpu;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
src = (struct plic_irqsrc *)isrc;
|
||||||
|
|
||||||
|
WR4(sc, PLIC_PRIORITY(src->irq), 1);
|
||||||
|
|
||||||
|
cpu = PCPU_GET(cpuid);
|
||||||
|
|
||||||
|
reg = RD4(sc, PLIC_ENABLE(src->irq, cpu));
|
||||||
|
reg |= (1 << (src->irq % 32));
|
||||||
|
WR4(sc, PLIC_ENABLE(src->irq, cpu), reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plic_map_intr(device_t dev, struct intr_map_data *data,
|
||||||
|
struct intr_irqsrc **isrcp)
|
||||||
|
{
|
||||||
|
struct intr_map_data_fdt *daf;
|
||||||
|
struct plic_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
if (data->type != INTR_MAP_DATA_FDT)
|
||||||
|
return (ENOTSUP);
|
||||||
|
|
||||||
|
daf = (struct intr_map_data_fdt *)data;
|
||||||
|
if (daf->ncells != 1 || daf->cells[0] >= PLIC_NIRQS)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
*isrcp = &sc->isrcs[daf->cells[0]].isrc;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plic_probe(device_t dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ofw_bus_status_okay(dev))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (!ofw_bus_is_compatible(dev, "riscv,plic0"))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
device_set_desc(dev, "RISC-V PLIC");
|
||||||
|
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plic_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct plic_irqsrc *isrcs;
|
||||||
|
struct plic_softc *sc;
|
||||||
|
struct intr_pic *pic;
|
||||||
|
uint32_t irq;
|
||||||
|
const char *name;
|
||||||
|
phandle_t xref;
|
||||||
|
uint32_t cpu;
|
||||||
|
int error;
|
||||||
|
int rid;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
sc->dev = dev;
|
||||||
|
|
||||||
|
/* Request memory resources */
|
||||||
|
rid = 0;
|
||||||
|
sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||||
|
RF_ACTIVE);
|
||||||
|
if (sc->intc_res == NULL) {
|
||||||
|
device_printf(dev,
|
||||||
|
"Error: could not allocate memory resources\n");
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
isrcs = sc->isrcs;
|
||||||
|
name = device_get_nameunit(sc->dev);
|
||||||
|
cpu = PCPU_GET(cpuid);
|
||||||
|
for (irq = 0; irq < PLIC_NIRQS; irq++) {
|
||||||
|
isrcs[irq].irq = irq;
|
||||||
|
error = intr_isrc_register(&isrcs[irq].isrc, sc->dev,
|
||||||
|
0, "%s,%u", name, irq);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
WR4(sc, PLIC_ENABLE(irq, cpu), 0);
|
||||||
|
}
|
||||||
|
WR4(sc, PLIC_THRESHOLD(cpu), 0);
|
||||||
|
|
||||||
|
xref = OF_xref_from_node(ofw_bus_get_node(sc->dev));
|
||||||
|
pic = intr_pic_register(sc->dev, xref);
|
||||||
|
if (pic == NULL)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
csr_set(sie, SIE_SEIE);
|
||||||
|
|
||||||
|
return (intr_pic_claim_root(sc->dev, xref, plic_intr, sc, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_method_t plic_methods[] = {
|
||||||
|
DEVMETHOD(device_probe, plic_probe),
|
||||||
|
DEVMETHOD(device_attach, plic_attach),
|
||||||
|
|
||||||
|
DEVMETHOD(pic_disable_intr, plic_disable_intr),
|
||||||
|
DEVMETHOD(pic_enable_intr, plic_enable_intr),
|
||||||
|
DEVMETHOD(pic_map_intr, plic_map_intr),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t plic_driver = {
|
||||||
|
"plic",
|
||||||
|
plic_methods,
|
||||||
|
sizeof(struct plic_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t plic_devclass;
|
||||||
|
|
||||||
|
EARLY_DRIVER_MODULE(plic, simplebus, plic_driver, plic_devclass,
|
||||||
|
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
|
||||||
|
|
@ -70,8 +70,6 @@ struct riscv_timer_softc {
|
||||||
void *ih;
|
void *ih;
|
||||||
uint32_t clkfreq;
|
uint32_t clkfreq;
|
||||||
struct eventtimer et;
|
struct eventtimer et;
|
||||||
int intr_rid;
|
|
||||||
struct resource *intr_res;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct riscv_timer_softc *riscv_timer_sc = NULL;
|
static struct riscv_timer_softc *riscv_timer_sc = NULL;
|
||||||
|
|
@ -188,18 +186,9 @@ riscv_timer_attach(device_t dev)
|
||||||
|
|
||||||
riscv_timer_sc = sc;
|
riscv_timer_sc = sc;
|
||||||
|
|
||||||
sc->intr_rid = 0;
|
|
||||||
sc->intr_res = bus_alloc_resource(dev,
|
|
||||||
SYS_RES_IRQ, &sc->intr_rid, IRQ_TIMER_SUPERVISOR,
|
|
||||||
IRQ_TIMER_SUPERVISOR, 1, RF_ACTIVE);
|
|
||||||
if (sc->intr_res == NULL) {
|
|
||||||
device_printf(dev, "failed to allocate irq\n");
|
|
||||||
return (ENXIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup IRQs handler */
|
/* Setup IRQs handler */
|
||||||
error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
|
error = riscv_setup_intr(device_get_nameunit(dev), riscv_timer_intr,
|
||||||
riscv_timer_intr, NULL, sc, &sc->ih);
|
NULL, sc, IRQ_TIMER_SUPERVISOR, INTR_TYPE_CLK, &sc->ih);
|
||||||
if (error) {
|
if (error) {
|
||||||
device_printf(dev, "Unable to alloc int resource.\n");
|
device_printf(dev, "Unable to alloc int resource.\n");
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue