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
f0d2af516b
commit
ef85338e60
@ -9,8 +9,11 @@ dev/ofw/ofw_cpu.c optional fdt
|
||||
dev/uart/uart_cpu_fdt.c optional uart fdt
|
||||
dev/xilinx/axi_quad_spi.c optional xilinx_spi
|
||||
kern/kern_clocksource.c standard
|
||||
kern/msi_if.m standard
|
||||
kern/pic_if.m standard
|
||||
kern/subr_devmap.c standard
|
||||
kern/subr_dummy_vdso_tc.c standard
|
||||
kern/subr_intr.c standard
|
||||
libkern/bcmp.c standard
|
||||
libkern/bcopy.c standard
|
||||
libkern/ffs.c standard
|
||||
@ -44,6 +47,7 @@ riscv/riscv/mp_machdep.c optional smp
|
||||
riscv/riscv/mem.c standard
|
||||
riscv/riscv/nexus.c standard
|
||||
riscv/riscv/ofw_machdep.c optional fdt
|
||||
riscv/riscv/plic.c standard
|
||||
riscv/riscv/pmap.c standard
|
||||
riscv/riscv/riscv_console.c optional rcons
|
||||
riscv/riscv/soc.c standard
|
||||
|
@ -2,3 +2,4 @@
|
||||
|
||||
RISCV 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 RCTL # Resource limits
|
||||
options SMP
|
||||
options INTRNG
|
||||
|
||||
# RISC-V SBI console
|
||||
device rcons
|
||||
|
@ -37,11 +37,19 @@
|
||||
#ifndef _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;
|
||||
|
||||
void riscv_init_interrupts(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 *,
|
||||
void *, int, int, void **);
|
||||
void riscv_cpu_intr(struct trapframe *);
|
||||
@ -69,12 +77,7 @@ enum {
|
||||
IRQ_EXTERNAL_SUPERVISOR,
|
||||
IRQ_EXTERNAL_HYPERVISOR,
|
||||
IRQ_EXTERNAL_MACHINE,
|
||||
#if 0
|
||||
/* lowRISC TODO */
|
||||
IRQ_COP, /* lowRISC only */
|
||||
IRQ_UART, /* lowRISC only */
|
||||
#endif
|
||||
NIRQS
|
||||
INTC_NIRQS
|
||||
};
|
||||
|
||||
#endif /* !_MACHINE_INTR_MACHDEP_H_ */
|
||||
|
@ -137,6 +137,8 @@
|
||||
#define SIE_SSIE (1 << 1)
|
||||
#define SIE_UTIE (1 << 4)
|
||||
#define SIE_STIE (1 << 5)
|
||||
#define SIE_UEIE (1 << 8)
|
||||
#define SIE_SEIE (1 << 9)
|
||||
|
||||
#define MIP_SEIP (1 << 9)
|
||||
|
||||
|
@ -46,6 +46,8 @@
|
||||
#define IPI_STOP_HARD (1 << 4)
|
||||
#define IPI_HARDCLOCK (1 << 5)
|
||||
|
||||
#define INTR_IPI_COUNT 1
|
||||
|
||||
void ipi_all_but_self(u_int ipi);
|
||||
void ipi_cpu(int cpu, u_int ipi);
|
||||
void ipi_selected(cpuset_t cpus, u_int ipi);
|
||||
|
@ -38,11 +38,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/smp.h>
|
||||
#include <sys/vmmeter.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
@ -50,44 +52,22 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/intr.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
|
||||
#include <machine/smp.h>
|
||||
#endif
|
||||
|
||||
u_long intrcnt[NIRQS];
|
||||
size_t sintrcnt = sizeof(intrcnt);
|
||||
void intr_irq_handler(struct trapframe *tf);
|
||||
|
||||
char intrnames[NIRQS * (MAXCOMLEN + 1) * 2];
|
||||
size_t sintrnames = sizeof(intrnames);
|
||||
struct intc_irqsrc {
|
||||
struct intr_irqsrc isrc;
|
||||
u_int irq;
|
||||
};
|
||||
|
||||
static struct intr_event *intr_events[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);
|
||||
}
|
||||
struct intc_irqsrc isrcs[INTC_NIRQS];
|
||||
|
||||
static void
|
||||
riscv_mask_irq(void *source)
|
||||
@ -102,15 +82,10 @@ riscv_mask_irq(void *source)
|
||||
break;
|
||||
case IRQ_SOFTWARE_USER:
|
||||
csr_clear(sie, SIE_USIE);
|
||||
break;
|
||||
case IRQ_SOFTWARE_SUPERVISOR:
|
||||
csr_clear(sie, SIE_SSIE);
|
||||
break;
|
||||
#if 0
|
||||
/* lowRISC TODO */
|
||||
case IRQ_UART:
|
||||
machine_command(ECALL_IO_IRQ_MASK, 0);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
panic("Unknown irq %d\n", irq);
|
||||
}
|
||||
@ -133,60 +108,37 @@ riscv_unmask_irq(void *source)
|
||||
case IRQ_SOFTWARE_SUPERVISOR:
|
||||
csr_set(sie, SIE_SSIE);
|
||||
break;
|
||||
#if 0
|
||||
/* lowRISC TODO */
|
||||
case IRQ_UART:
|
||||
machine_command(ECALL_IO_IRQ_MASK, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
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
|
||||
riscv_setup_intr(const char *name, driver_filter_t *filt,
|
||||
void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
|
||||
{
|
||||
struct intr_event *event;
|
||||
struct intr_irqsrc *isrc;
|
||||
int error;
|
||||
|
||||
if (irq < 0 || irq >= NIRQS)
|
||||
if (irq < 0 || irq >= INTC_NIRQS)
|
||||
panic("%s: unknown intr %d", __func__, irq);
|
||||
|
||||
event = intr_events[irq];
|
||||
if (event == NULL) {
|
||||
error = intr_event_create(&event, (void *)(uintptr_t)irq, 0,
|
||||
irq, riscv_mask_irq, riscv_unmask_irq,
|
||||
NULL, NULL, "int%d", irq);
|
||||
isrc = &isrcs[irq].isrc;
|
||||
if (isrc->isrc_event == NULL) {
|
||||
error = intr_event_create(&isrc->isrc_event, isrc, 0, irq,
|
||||
riscv_mask_irq, riscv_unmask_irq, NULL, NULL, "int%d", irq);
|
||||
if (error)
|
||||
return (error);
|
||||
intr_events[irq] = event;
|
||||
riscv_unmask_irq((void*)(uintptr_t)irq);
|
||||
}
|
||||
|
||||
error = intr_event_add_handler(event, name, filt, handler, arg,
|
||||
intr_priority(flags), flags, cookiep);
|
||||
error = intr_event_add_handler(isrc->isrc_event, name,
|
||||
filt, handler, arg, intr_priority(flags), flags, cookiep);
|
||||
if (error) {
|
||||
printf("Failed to setup intr: %d\n", irq);
|
||||
return (error);
|
||||
}
|
||||
|
||||
riscv_intrcnt_setname(riscv_intr_counters[irq],
|
||||
event->ie_fullname);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -199,19 +151,10 @@ riscv_teardown_intr(void *ih)
|
||||
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
|
||||
riscv_cpu_intr(struct trapframe *frame)
|
||||
{
|
||||
struct intr_event *event;
|
||||
struct intr_irqsrc *isrc;
|
||||
int active_irq;
|
||||
|
||||
critical_enter();
|
||||
@ -222,26 +165,20 @@ riscv_cpu_intr(struct trapframe *frame)
|
||||
active_irq = (frame->tf_scause & EXCP_MASK);
|
||||
|
||||
switch (active_irq) {
|
||||
#if 0
|
||||
/* lowRISC TODO */
|
||||
case IRQ_UART:
|
||||
#endif
|
||||
case IRQ_SOFTWARE_USER:
|
||||
case IRQ_SOFTWARE_SUPERVISOR:
|
||||
case IRQ_TIMER_SUPERVISOR:
|
||||
event = intr_events[active_irq];
|
||||
/* Update counters */
|
||||
atomic_add_long(riscv_intr_counters[active_irq], 1);
|
||||
VM_CNT_INC(v_intr);
|
||||
isrc = &isrcs[active_irq].isrc;
|
||||
if (intr_isrc_dispatch(isrc, frame) != 0)
|
||||
printf("stray interrupt %d\n", active_irq);
|
||||
break;
|
||||
case IRQ_EXTERNAL_SUPERVISOR:
|
||||
intr_irq_handler(frame);
|
||||
break;
|
||||
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();
|
||||
}
|
||||
|
||||
@ -320,5 +257,22 @@ ipi_selected(cpuset_t cpus, u_int ipi)
|
||||
}
|
||||
sbi_send_ipi(&mask);
|
||||
}
|
||||
|
||||
#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);
|
||||
kdb_init();
|
||||
|
||||
riscv_init_interrupts();
|
||||
|
||||
early_boot = 0;
|
||||
}
|
||||
|
||||
|
@ -256,6 +256,9 @@ init_secondary(uint64_t cpu)
|
||||
/* Enable interrupts */
|
||||
intr_enable();
|
||||
|
||||
/* Enable external (PLIC) interrupts */
|
||||
csr_set(sie, SIE_SEIE);
|
||||
|
||||
mtx_lock_spin(&ap_boot_mtx);
|
||||
|
||||
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,
|
||||
* and I/O memory address space.
|
||||
*/
|
||||
#include "opt_platform.h"
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
@ -48,22 +49,18 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/interrupt.h>
|
||||
|
||||
#include <machine/vmparam.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <machine/intr.h>
|
||||
|
||||
#include "opt_platform.h"
|
||||
|
||||
#include <dev/fdt/fdt_common.h>
|
||||
#ifdef FDT
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include "ofw_bus_if.h"
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
return (riscv_config_intr(irq, trig, pol));
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -282,8 +279,7 @@ nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = riscv_setup_intr(device_get_nameunit(child), filt, intr,
|
||||
arg, rman_get_start(res), flags, cookiep);
|
||||
error = intr_setup_irq(child, res, filt, intr, arg, flags, cookiep);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -292,7 +288,7 @@ static int
|
||||
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
|
||||
@ -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_virtual(r, (void *)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);
|
||||
}
|
||||
|
||||
@ -375,16 +378,17 @@ static int
|
||||
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
|
||||
pcell_t *intr)
|
||||
{
|
||||
int irq;
|
||||
struct intr_map_data_fdt *fdt_data;
|
||||
size_t len;
|
||||
u_int irq;
|
||||
|
||||
if (icells == 3) {
|
||||
irq = intr[1];
|
||||
if (intr[0] == 0)
|
||||
irq += 32; /* SPI */
|
||||
else
|
||||
irq += 16; /* PPI */
|
||||
} else
|
||||
irq = intr[0];
|
||||
len = sizeof(*fdt_data) + icells * sizeof(pcell_t);
|
||||
fdt_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_FDT, len, M_WAITOK | M_ZERO);
|
||||
fdt_data->iparent = iparent;
|
||||
fdt_data->ncells = icells;
|
||||
memcpy(fdt_data->cells, intr, icells * sizeof(pcell_t));
|
||||
irq = intr_map_irq(NULL, iparent, (struct intr_map_data *)fdt_data);
|
||||
|
||||
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;
|
||||
uint32_t clkfreq;
|
||||
struct eventtimer et;
|
||||
int intr_rid;
|
||||
struct resource *intr_res;
|
||||
};
|
||||
|
||||
static struct riscv_timer_softc *riscv_timer_sc = NULL;
|
||||
@ -188,18 +186,9 @@ riscv_timer_attach(device_t dev)
|
||||
|
||||
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 */
|
||||
error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
|
||||
riscv_timer_intr, NULL, sc, &sc->ih);
|
||||
error = riscv_setup_intr(device_get_nameunit(dev), riscv_timer_intr,
|
||||
NULL, sc, IRQ_TIMER_SUPERVISOR, INTR_TYPE_CLK, &sc->ih);
|
||||
if (error) {
|
||||
device_printf(dev, "Unable to alloc int resource.\n");
|
||||
return (ENXIO);
|
||||
|
Loading…
Reference in New Issue
Block a user