diff options
-rw-r--r-- | bsps/include/bsp/fatal.h | 4 | ||||
-rw-r--r-- | bsps/riscv/riscv/clock/clockdrv.c | 10 | ||||
-rw-r--r-- | bsps/riscv/riscv/include/bsp/riscv.h | 12 | ||||
-rw-r--r-- | bsps/riscv/riscv/irq/irq.c | 56 | ||||
-rw-r--r-- | bsps/riscv/riscv/start/bspsmp.c | 77 | ||||
-rw-r--r-- | bsps/riscv/riscv/start/bspstart.c | 91 | ||||
-rw-r--r-- | bsps/riscv/riscv/start/start.S | 75 | ||||
-rw-r--r-- | c/src/lib/libbsp/riscv/riscv/Makefile.am | 2 |
8 files changed, 299 insertions, 28 deletions
diff --git a/bsps/include/bsp/fatal.h b/bsps/include/bsp/fatal.h index 71edcb0afc..2679af1c5a 100644 --- a/bsps/include/bsp/fatal.h +++ b/bsps/include/bsp/fatal.h @@ -145,7 +145,9 @@ typedef enum { RISCV_FATAL_NO_NS16550_CLOCK_FREQUENCY_IN_DEVICE_TREE, RISCV_FATAL_UNEXPECTED_INTERRUPT_EXCEPTION, RISCV_FATAL_CLOCK_IRQ_INSTALL, - RISCV_FATAL_NO_CLINT_REG_IN_DEVICE_TREE + RISCV_FATAL_NO_CLINT_REG_IN_DEVICE_TREE, + RISCV_FATAL_INVALID_HART_REG_IN_DEVICE_TREE, + RISCV_FATAL_INVALID_CLINT_IRQS_EXTENDED_IN_DEVICE_TREE } bsp_fatal_code; RTEMS_NO_RETURN static inline void diff --git a/bsps/riscv/riscv/clock/clockdrv.c b/bsps/riscv/riscv/clock/clockdrv.c index 677823c4c8..4220952ae3 100644 --- a/bsps/riscv/riscv/clock/clockdrv.c +++ b/bsps/riscv/riscv/clock/clockdrv.c @@ -119,19 +119,13 @@ static void riscv_clock_initialize(void) { const char *fdt; riscv_timecounter *tc; - int node; uint32_t tb_freq; uint64_t us_per_tick; fdt = bsp_fdt_get(); - tc = &riscv_clock_tc; - - node = fdt_node_offset_by_compatible(fdt, -1, "riscv,clint0"); - tc->clint = riscv_fdt_get_address(fdt, node); - if (tc->clint == NULL) { - bsp_fatal(RISCV_FATAL_NO_CLINT_REG_IN_DEVICE_TREE); - } + tc = &riscv_clock_tc; + tc->clint = riscv_clint; tb_freq = riscv_clock_get_timebase_frequency(fdt); us_per_tick = rtems_configuration_get_microseconds_per_tick(); diff --git a/bsps/riscv/riscv/include/bsp/riscv.h b/bsps/riscv/riscv/include/bsp/riscv.h index b85b250526..6701bb6cc6 100644 --- a/bsps/riscv/riscv/include/bsp/riscv.h +++ b/bsps/riscv/riscv/include/bsp/riscv.h @@ -28,12 +28,24 @@ #include <bsp.h> +#include <rtems/score/cpuimpl.h> + #ifdef __cplusplus extern "C" { #endif +extern volatile RISCV_CLINT_regs *riscv_clint; + void *riscv_fdt_get_address(const void *fdt, int node); +#ifdef RTEMS_SMP +extern uint32_t riscv_hart_count; + +extern uint32_t riscv_hart_phandles[CPU_MAXIMUM_PROCESSORS]; + +uint32_t riscv_get_hart_index_by_phandle(uint32_t phandle); +#endif + #if RISCV_ENABLE_HTIF_SUPPORT != 0 void htif_poweroff(void); #endif diff --git a/bsps/riscv/riscv/irq/irq.c b/bsps/riscv/riscv/irq/irq.c index 61cf13153b..a3a17f5a2e 100644 --- a/bsps/riscv/riscv/irq/irq.c +++ b/bsps/riscv/riscv/irq/irq.c @@ -36,9 +36,17 @@ #include <bsp/irq.h> #include <bsp/fatal.h> +#include <bsp/fdt.h> #include <bsp/irq-generic.h> +#include <bsp/riscv.h> #include <rtems/score/percpu.h> +#include <rtems/score/riscv-utility.h> +#include <rtems/score/smpimpl.h> + +#include <libfdt.h> + +volatile RISCV_CLINT_regs *riscv_clint; void _RISCV_Interrupt_dispatch(uintptr_t mcause, Per_CPU_Control *cpu_self) { @@ -53,14 +61,62 @@ void _RISCV_Interrupt_dispatch(uintptr_t mcause, Per_CPU_Control *cpu_self) } else if (mcause == (RISCV_INTERRUPT_EXTERNAL_MACHINE << 1)) { /* TODO: Handle PLIC interrupt */ } else if (mcause == (RISCV_INTERRUPT_SOFTWARE_MACHINE << 1)) { +#ifdef RTEMS_SMP + clear_csr(mip, MIP_MSIP); + _SMP_Inter_processor_interrupt_handler(cpu_self); +#else bsp_interrupt_handler_dispatch(RISCV_INTERRUPT_VECTOR_SOFTWARE); +#endif } else { bsp_fatal(RISCV_FATAL_UNEXPECTED_INTERRUPT_EXCEPTION); } } +static void riscv_clint_init(const void *fdt) +{ + volatile RISCV_CLINT_regs *clint; + int node; +#ifdef RTEMS_SMP + const uint32_t *val; + int len; + int i; +#endif + + node = fdt_node_offset_by_compatible(fdt, -1, "riscv,clint0"); + + clint = riscv_fdt_get_address(fdt, node); + if (clint == NULL) { + bsp_fatal(RISCV_FATAL_NO_CLINT_REG_IN_DEVICE_TREE); + } + + riscv_clint = clint; + +#ifdef RTEMS_SMP + val = fdt_getprop(fdt, node, "interrupts-extended", &len); + + for (i = 0; i < len; i += 16) { + uint32_t hart_index; + Per_CPU_Control *cpu; + + hart_index = riscv_get_hart_index_by_phandle(fdt32_to_cpu(val[i / 4])); + if (hart_index >= rtems_configuration_get_maximum_processors()) { + continue; + } + + cpu = _Per_CPU_Get_by_index(hart_index); + cpu->cpu_per_cpu.clint_msip = &clint->msip[i / 16]; + cpu->cpu_per_cpu.clint_mtimecmp = &clint->mtimecmp[i / 16]; + } +#endif +} + rtems_status_code bsp_interrupt_facility_initialize(void) { + const void *fdt; + + fdt = bsp_fdt_get(); + riscv_clint_init(fdt); + return RTEMS_SUCCESSFUL; } diff --git a/bsps/riscv/riscv/start/bspsmp.c b/bsps/riscv/riscv/start/bspsmp.c new file mode 100644 index 0000000000..8e5540d132 --- /dev/null +++ b/bsps/riscv/riscv/start/bspsmp.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 embedded brains GmbH + * + * 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 <bsp/bootcard.h> +#include <bsp/irq.h> +#include <bsp/riscv.h> + +#include <rtems/score/riscv-utility.h> +#include <rtems/score/smpimpl.h> + +void bsp_start_on_secondary_processor(Per_CPU_Control *cpu_self) +{ + uint32_t cpu_index_self; + + cpu_index_self = _Per_CPU_Get_index(cpu_self); + + if ( + cpu_index_self < rtems_configuration_get_maximum_processors() + && _SMP_Should_start_processor(cpu_index_self) + ) { + set_csr(mie, MIP_MSIP); + _SMP_Start_multitasking_on_secondary_processor(cpu_self); + } else { + _CPU_Thread_Idle_body(0); + } +} + +uint32_t _CPU_SMP_Initialize(void) +{ + return riscv_hart_count; +} + +bool _CPU_SMP_Start_processor(uint32_t cpu_index) +{ + return true; +} + +void _CPU_SMP_Finalize_initialization(uint32_t cpu_count) +{ + (void) cpu_count; + set_csr(mie, MIP_MSIP); +} + +void _CPU_SMP_Prepare_start_multitasking(void) +{ + /* Do nothing */ +} + +void _CPU_SMP_Send_interrupt(uint32_t target_processor_index) +{ + Per_CPU_Control *cpu; + + cpu = _Per_CPU_Get_by_index(target_processor_index); + *cpu->cpu_per_cpu.clint_msip = 0x1; +} diff --git a/bsps/riscv/riscv/start/bspstart.c b/bsps/riscv/riscv/start/bspstart.c index 6b5797786a..2cb453f125 100644 --- a/bsps/riscv/riscv/start/bspstart.c +++ b/bsps/riscv/riscv/start/bspstart.c @@ -24,6 +24,8 @@ */ #include <bsp/bootcard.h> +#include <bsp/fatal.h> +#include <bsp/fdt.h> #include <bsp/irq-generic.h> #include <bsp/riscv.h> @@ -69,7 +71,96 @@ void *riscv_fdt_get_address(const void *fdt, int node) return (void *)(uintptr_t) addr; } +#ifdef RTEMS_SMP +uint32_t riscv_hart_count; + +uint32_t riscv_hart_phandles[CPU_MAXIMUM_PROCESSORS]; + +static void riscv_find_harts(void) +{ + const void *fdt; + int node; + uint32_t max_hart_index; + + fdt = bsp_fdt_get(); + max_hart_index = 0; + node = -1; + + while ((node = fdt_node_offset_by_compatible(fdt, node, "riscv")) >= 0) { + int subnode; + const uint32_t *val; + int len; + uint32_t phandle; + uint32_t hart_index; + + val = fdt_getprop(fdt, node, "reg", &len); + if (val == NULL || len != 4) { + bsp_fatal(RISCV_FATAL_INVALID_HART_REG_IN_DEVICE_TREE); + } + + hart_index = fdt32_to_cpu(val[0]); + + if (hart_index >= CPU_MAXIMUM_PROCESSORS) { + continue; + } + + if (hart_index > max_hart_index) { + max_hart_index = hart_index; + } + + phandle = 0; + + fdt_for_each_subnode(subnode, fdt, node) { + int propoff; + bool interrupt_controller; + uint32_t potential_phandle; + + interrupt_controller = false; + potential_phandle = 0; + + fdt_for_each_property_offset(propoff, fdt, subnode) { + const char *name; + + val = fdt_getprop_by_offset(fdt, propoff, &name, &len); + if (val != NULL) { + if (strcmp(name, "interrupt-controller") == 0) { + interrupt_controller = true; + } else if (len == 4 && strcmp(name, "phandle") == 0) { + potential_phandle = fdt32_to_cpu(val[0]); + } + } + } + + if (interrupt_controller) { + phandle = potential_phandle; + break; + } + } + + riscv_hart_phandles[hart_index] = phandle; + } + + riscv_hart_count = max_hart_index + 1; +} + +uint32_t riscv_get_hart_index_by_phandle(uint32_t phandle) +{ + uint32_t hart_index; + + for (hart_index = 0; hart_index < riscv_hart_count; ++hart_index) { + if (riscv_hart_phandles[hart_index] == phandle) { + return hart_index; + } + } + + return UINT32_MAX; +} +#endif + void bsp_start(void) { +#ifdef RTEMS_SMP + riscv_find_harts(); +#endif bsp_interrupt_initialize(); } diff --git a/bsps/riscv/riscv/start/start.S b/bsps/riscv/riscv/start/start.S index 83926a9272..290c95a166 100644 --- a/bsps/riscv/riscv/start/start.S +++ b/bsps/riscv/riscv/start/start.S @@ -48,26 +48,34 @@ SYM(_start): LADDR gp, __global_pointer$ .option pop + /* Init FPU unit if it's there */ + li t0, MSTATUS_FS + csrs mstatus, t0 + + /* Set exception handler */ + LADDR t0, _RISCV_Exception_handler + csrw mtvec, t0 + + /* Load stack pointer and branch to secondary processor start if necessary */ #ifdef RTEMS_SMP + LADDR sp, _Configuration_Interrupt_stack_area_begin + LADDR t2, _Configuration_Interrupt_stack_size csrr s0, mhartid LADDR t0, _Per_CPU_Information slli t1, s0, PER_CPU_CONTROL_SIZE_LOG2 - add t0, t0, t1 - csrw mscratch, t0 - bnez s0, .Lwait_for_go -#endif - - /* load stack and frame pointers */ + add s1, t0, t1 + csrw mscratch, s1 + bnez s0, .Lstart_on_secondary_processor + add sp, sp, t2 +#else LADDR sp, _Configuration_Interrupt_stack_area_end +#endif #ifdef BSP_START_COPY_FDT_FROM_U_BOOT mv a0, a1 call bsp_fdt_copy #endif - LADDR t0, _RISCV_Exception_handler - csrw mtvec, t0 - /* Clear .bss */ LADDR a0, bsp_section_bss_begin li a1, 0 @@ -81,24 +89,55 @@ SYM(_start): amoswap.w zero, zero, 0(t0) #endif - /* Init FPU unit if it's there */ - li t0, MSTATUS_FS - csrs mstatus, t0 - j boot_card #ifdef RTEMS_SMP + +.Lstart_on_secondary_processor: + + /* Adjust stack pointer */ +#ifdef __riscv_mul + addi t0, s0, 1 + mul t2, t2, t0 +#else + mv t0, s0 + mv t3, t2 + +.Ladd_more: + + add t2, t2, t3 + addi t0, t0, -1 + bnez t0, .Ladd_more +#endif + add sp, sp, t2 + /* Wait for go issued by the boot processor (mhartid == 0) */ -.Lwait_for_go: LADDR t0, .Lsecondary_processor_go + .Lwait_for_go_again: + lw t1, 0(t0) fence iorw, iorw - sext.w t1, t1 bnez t1, .Lwait_for_go_again -.Lloop_forever: - j .Lloop_forever + + mv a0, s1 + call bsp_start_on_secondary_processor + +#if __riscv_xlen == 32 + .align 2 +#elif __riscv_xlen == 64 + .align 3 +#endif .Lsecondary_processor_go: - .word 0xdeadbeef + + /* + * These are ebreak instructions, just in case we end up here executing + * code. + */ + .word 0x00100073 +#if __riscv_xlen == 64 + .word 0x00100073 #endif + +#endif /* RTEMS_SMP */ diff --git a/c/src/lib/libbsp/riscv/riscv/Makefile.am b/c/src/lib/libbsp/riscv/riscv/Makefile.am index b9a9a639e6..23c574f35d 100644 --- a/c/src/lib/libbsp/riscv/riscv/Makefile.am +++ b/c/src/lib/libbsp/riscv/riscv/Makefile.am @@ -61,7 +61,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/riscv/riscv/console/console-conf librtemsbsp_a_SOURCES += ../../../../../../bsps/riscv/riscv/console/htif.c if HAS_SMP -librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/bspsmp-dummy.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/riscv/riscv/start/bspsmp.c endif include $(top_srcdir)/../../../../automake/local.am |