Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'riscv-for-linus-4.19-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux

Pull RISC-V updates from Palmer Dabbelt:
"This contains some major improvements to the RISC-V port, including
the necessary interrupt controller and timer support to actually make
it to userspace. Support for three devices has been added:

- the ISA-mandated timers on RISC-V systems.

- the ISA-mandated first-level interrupt controller on RISC-V
systems, which is handled as part of our core arch code because
it's very small and tightly tied to the ISA.

- SiFive's platform-level interrupt controller, which talks to the
actual devices.

In addition to these new devices, there are a handful of cleanups all
over the RISC-V tree:

- build fixes for various configurations:
* A fix to the vDSO build's makefile so it respects CFLAGS.
* The addition of __lshrti3, a libgcc derived function necessary
for some 32-bit configurations.
* !SMP && PERF_EVENTS

- Cleanups to the arch code to remove the remnants of old versions of
the drivers that were just properly submitted.
* Some dead code from the timer driver, most of which wasn't ever
even compiled.
* Cleanups of some interrupt #defines, which are now local to the
interrupt handling code.

- Fixes to ptrace(), which while not being sufficient to fully make
GDB work are at least sufficient to get simple GDB tasks to work.

- Early printk support via RISC-V's architecturally mandated SBI
console device.

- A fix to our early debug trap handler to ensure it's always
aligned.

These patches have all been through a fairly extensive review process,
but as this enables a whole pile of functionality (ie, userspace) I'm
confident we'll need to submit a few more patches. The only concrete
issues I know about are the sys_riscv_flush_icache patches, but as I
managed to screw those up on Friday I figured it'd be best to let them
bake another week.

This tag boots a Fedora root filesystem on QEMU's master branch for
me, and before this morning's rebase (from 4.18-rc8 to 4.18) it booted
on the HiFive Unleashed.

Thanks to Christoph Hellwig and the other guys at WD for getting the
new drivers in shape!"

* tag 'riscv-for-linus-4.19-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux:
dt-bindings: interrupt-controller: SiFive Plaform Level Interrupt Controller
dt-bindings: interrupt-controller: RISC-V local interrupt controller
RISC-V: Fix !CONFIG_SMP compilation error
irqchip: add a SiFive PLIC driver
RISC-V: Add the directive for alignment of stvec's value
clocksource: new RISC-V SBI timer driver
RISC-V: implement low-level interrupt handling
RISC-V: add a definition for the SIE SEIE bit
RISC-V: remove INTERRUPT_CAUSE_* defines from asm/irq.h
RISC-V: simplify software interrupt / IPI code
RISC-V: remove timer leftovers
RISC-V: Add early printk support via the SBI console
RISC-V: Don't increment sepc after breakpoint.
RISC-V: implement __lshrti3.
RISC-V: Use KBUILD_CFLAGS instead of KCFLAGS when building the vDSO

+625 -59
+44
Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt
··· 1 + RISC-V Hart-Level Interrupt Controller (HLIC) 2 + --------------------------------------------- 3 + 4 + RISC-V cores include Control Status Registers (CSRs) which are local to each 5 + CPU core (HART in RISC-V terminology) and can be read or written by software. 6 + Some of these CSRs are used to control local interrupts connected to the core. 7 + Every interrupt is ultimately routed through a hart's HLIC before it 8 + interrupts that hart. 9 + 10 + The RISC-V supervisor ISA manual specifies three interrupt sources that are 11 + attached to every HLIC: software interrupts, the timer interrupt, and external 12 + interrupts. Software interrupts are used to send IPIs between cores. The 13 + timer interrupt comes from an architecturally mandated real-time timer that is 14 + controller via Supervisor Binary Interface (SBI) calls and CSR reads. External 15 + interrupts connect all other device interrupts to the HLIC, which are routed 16 + via the platform-level interrupt controller (PLIC). 17 + 18 + All RISC-V systems that conform to the supervisor ISA specification are 19 + required to have a HLIC with these three interrupt sources present. Since the 20 + interrupt map is defined by the ISA it's not listed in the HLIC's device tree 21 + entry, though external interrupt controllers (like the PLIC, for example) will 22 + need to define how their interrupts map to the relevant HLICs. This means 23 + a PLIC interrupt property will typically list the HLICs for all present HARTs 24 + in the system. 25 + 26 + Required properties: 27 + - compatible : "riscv,cpu-intc" 28 + - #interrupt-cells : should be <1> 29 + - interrupt-controller : Identifies the node as an interrupt controller 30 + 31 + Furthermore, this interrupt-controller MUST be embedded inside the cpu 32 + definition of the hart whose CSRs control these local interrupts. 33 + 34 + An example device tree entry for a HLIC is show below. 35 + 36 + cpu1: cpu@1 { 37 + compatible = "riscv"; 38 + ... 39 + cpu1-intc: interrupt-controller { 40 + #interrupt-cells = <1>; 41 + compatible = "riscv,cpu-intc", "sifive,fu540-c000-cpu-intc"; 42 + interrupt-controller; 43 + }; 44 + };
+58
Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.txt
··· 1 + SiFive Platform-Level Interrupt Controller (PLIC) 2 + ------------------------------------------------- 3 + 4 + SiFive SOCs include an implementation of the Platform-Level Interrupt Controller 5 + (PLIC) high-level specification in the RISC-V Privileged Architecture 6 + specification. The PLIC connects all external interrupts in the system to all 7 + hart contexts in the system, via the external interrupt source in each hart. 8 + 9 + A hart context is a privilege mode in a hardware execution thread. For example, 10 + in an 4 core system with 2-way SMT, you have 8 harts and probably at least two 11 + privilege modes per hart; machine mode and supervisor mode. 12 + 13 + Each interrupt can be enabled on per-context basis. Any context can claim 14 + a pending enabled interrupt and then release it once it has been handled. 15 + 16 + Each interrupt has a configurable priority. Higher priority interrupts are 17 + serviced first. Each context can specify a priority threshold. Interrupts 18 + with priority below this threshold will not cause the PLIC to raise its 19 + interrupt line leading to the context. 20 + 21 + While the PLIC supports both edge-triggered and level-triggered interrupts, 22 + interrupt handlers are oblivious to this distinction and therefore it is not 23 + specified in the PLIC device-tree binding. 24 + 25 + While the RISC-V ISA doesn't specify a memory layout for the PLIC, the 26 + "sifive,plic-1.0.0" device is a concrete implementation of the PLIC that 27 + contains a specific memory layout, which is documented in chapter 8 of the 28 + SiFive U5 Coreplex Series Manual <https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf>. 29 + 30 + Required properties: 31 + - compatible : "sifive,plic-1.0.0" and a string identifying the actual 32 + detailed implementation in case that specific bugs need to be worked around. 33 + - #address-cells : should be <0> or more. 34 + - #interrupt-cells : should be <1> or more. 35 + - interrupt-controller : Identifies the node as an interrupt controller. 36 + - reg : Should contain 1 register range (address and length). 37 + - interrupts-extended : Specifies which contexts are connected to the PLIC, 38 + with "-1" specifying that a context is not present. Each node pointed 39 + to should be a riscv,cpu-intc node, which has a riscv node as parent. 40 + - riscv,ndev: Specifies how many external interrupts are supported by 41 + this controller. 42 + 43 + Example: 44 + 45 + plic: interrupt-controller@c000000 { 46 + #address-cells = <0>; 47 + #interrupt-cells = <1>; 48 + compatible = "sifive,plic-1.0.0", "sifive,fu540-c000-plic"; 49 + interrupt-controller; 50 + interrupts-extended = < 51 + &cpu0-intc 11 52 + &cpu1-intc 11 &cpu1-intc 9 53 + &cpu2-intc 11 &cpu2-intc 9 54 + &cpu3-intc 11 &cpu3-intc 9 55 + &cpu4-intc 11 &cpu4-intc 9>; 56 + reg = <0xc000000 0x4000000>; 57 + riscv,ndev = <10>; 58 + };
+3
arch/riscv/Makefile
··· 25 25 26 26 KBUILD_CFLAGS += -mabi=lp64 27 27 KBUILD_AFLAGS += -mabi=lp64 28 + 29 + KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0500, -DCONFIG_ARCH_SUPPORTS_INT128) 30 + 28 31 KBUILD_MARCH = rv64im 29 32 LDFLAGS += -melf64lriscv 30 33 else
+1
arch/riscv/configs/defconfig
··· 76 76 CONFIG_CRYPTO_USER_API_HASH=y 77 77 CONFIG_MODULES=y 78 78 CONFIG_MODULE_UNLOAD=y 79 + CONFIG_SIFIVE_PLIC=y
+1
arch/riscv/include/asm/csr.h
··· 54 54 /* Interrupt Enable and Interrupt Pending flags */ 55 55 #define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */ 56 56 #define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */ 57 + #define SIE_SEIE _AC(0x00000200, UL) /* External Interrupt Enable */ 57 58 58 59 #define EXC_INST_MISALIGNED 0 59 60 #define EXC_INST_ACCESS 1
+1 -4
arch/riscv/include/asm/irq.h
··· 17 17 18 18 #define NR_IRQS 0 19 19 20 - #define INTERRUPT_CAUSE_SOFTWARE 1 21 - #define INTERRUPT_CAUSE_TIMER 5 22 - #define INTERRUPT_CAUSE_EXTERNAL 9 23 - 24 20 void riscv_timer_interrupt(void); 21 + void riscv_software_interrupt(void); 25 22 26 23 #include <asm-generic/irq.h> 27 24
+1
arch/riscv/include/asm/perf_event.h
··· 10 10 11 11 #include <linux/perf_event.h> 12 12 #include <linux/ptrace.h> 13 + #include <linux/interrupt.h> 13 14 14 15 #define RISCV_BASE_COUNTERS 2 15 16
-6
arch/riscv/include/asm/smp.h
··· 25 25 #ifdef CONFIG_SMP 26 26 27 27 /* SMP initialization hook for setup_arch */ 28 - void __init init_clockevent(void); 29 - 30 - /* SMP initialization hook for setup_arch */ 31 28 void __init setup_smp(void); 32 29 33 30 /* Hook for the generic smp_call_function_many() routine. */ ··· 40 43 * ID. 41 44 */ 42 45 #define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU))) 43 - 44 - /* Interprocessor interrupt handler */ 45 - irqreturn_t handle_ipi(void); 46 46 47 47 #endif /* CONFIG_SMP */ 48 48
+2 -2
arch/riscv/kernel/entry.S
··· 168 168 169 169 /* Handle interrupts */ 170 170 move a0, sp /* pt_regs */ 171 - REG_L a1, handle_arch_irq 172 - jr a1 171 + move a1, s4 /* scause */ 172 + tail do_IRQ 173 173 1: 174 174 /* Exceptions run with interrupts enabled */ 175 175 csrs sstatus, SR_SIE
+2
arch/riscv/kernel/head.S
··· 94 94 or a0, a0, a1 95 95 sfence.vma 96 96 csrw sptbr, a0 97 + .align 2 97 98 1: 98 99 /* Set trap vector to spin forever to help debug */ 99 100 la a0, .Lsecondary_park ··· 144 143 tail smp_callin 145 144 #endif 146 145 146 + .align 2 147 147 .Lsecondary_park: 148 148 /* We lack SMP support or have too many harts, so park this hart */ 149 149 wfi
+46 -9
arch/riscv/kernel/irq.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 1 2 /* 2 3 * Copyright (C) 2012 Regents of the University of California 3 4 * Copyright (C) 2017 SiFive 4 - * 5 - * This program is free software; you can redistribute it and/or 6 - * modify it under the terms of the GNU General Public License 7 - * as published by the Free Software Foundation, version 2. 8 - * 9 - * This program is distributed in the hope that it will be useful, 10 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 - * GNU General Public License for more details. 5 + * Copyright (C) 2018 Christoph Hellwig 13 6 */ 14 7 15 8 #include <linux/interrupt.h> 16 9 #include <linux/irqchip.h> 17 10 #include <linux/irqdomain.h> 11 + 12 + /* 13 + * Possible interrupt causes: 14 + */ 15 + #define INTERRUPT_CAUSE_SOFTWARE 1 16 + #define INTERRUPT_CAUSE_TIMER 5 17 + #define INTERRUPT_CAUSE_EXTERNAL 9 18 + 19 + /* 20 + * The high order bit of the trap cause register is always set for 21 + * interrupts, which allows us to differentiate them from exceptions 22 + * quickly. The INTERRUPT_CAUSE_* macros don't contain that bit, so we 23 + * need to mask it off. 24 + */ 25 + #define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) 26 + 27 + asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs, unsigned long cause) 28 + { 29 + struct pt_regs *old_regs = set_irq_regs(regs); 30 + 31 + irq_enter(); 32 + switch (cause & ~INTERRUPT_CAUSE_FLAG) { 33 + case INTERRUPT_CAUSE_TIMER: 34 + riscv_timer_interrupt(); 35 + break; 36 + #ifdef CONFIG_SMP 37 + case INTERRUPT_CAUSE_SOFTWARE: 38 + /* 39 + * We only use software interrupts to pass IPIs, so if a non-SMP 40 + * system gets one, then we don't know what to do. 41 + */ 42 + riscv_software_interrupt(); 43 + break; 44 + #endif 45 + case INTERRUPT_CAUSE_EXTERNAL: 46 + handle_arch_irq(regs); 47 + break; 48 + default: 49 + panic("unexpected interrupt cause"); 50 + } 51 + irq_exit(); 52 + 53 + set_irq_regs(old_regs); 54 + } 18 55 19 56 void __init init_IRQ(void) 20 57 {
-1
arch/riscv/kernel/perf_event.c
··· 27 27 #include <linux/mutex.h> 28 28 #include <linux/bitmap.h> 29 29 #include <linux/irq.h> 30 - #include <linux/interrupt.h> 31 30 #include <linux/perf_event.h> 32 31 #include <linux/atomic.h> 33 32 #include <linux/of.h>
+27
arch/riscv/kernel/setup.c
··· 39 39 #include <asm/tlbflush.h> 40 40 #include <asm/thread_info.h> 41 41 42 + #ifdef CONFIG_EARLY_PRINTK 43 + static void sbi_console_write(struct console *co, const char *buf, 44 + unsigned int n) 45 + { 46 + int i; 47 + 48 + for (i = 0; i < n; ++i) { 49 + if (buf[i] == '\n') 50 + sbi_console_putchar('\r'); 51 + sbi_console_putchar(buf[i]); 52 + } 53 + } 54 + 55 + struct console riscv_sbi_early_console_dev __initdata = { 56 + .name = "early", 57 + .write = sbi_console_write, 58 + .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, 59 + .index = -1 60 + }; 61 + #endif 62 + 42 63 #ifdef CONFIG_DUMMY_CONSOLE 43 64 struct screen_info screen_info = { 44 65 .orig_video_lines = 30, ··· 216 195 217 196 void __init setup_arch(char **cmdline_p) 218 197 { 198 + #if defined(CONFIG_EARLY_PRINTK) 199 + if (likely(early_console == NULL)) { 200 + early_console = &riscv_sbi_early_console_dev; 201 + register_console(early_console); 202 + } 203 + #endif 219 204 *cmdline_p = boot_command_line; 220 205 221 206 parse_early_param();
+2 -4
arch/riscv/kernel/smp.c
··· 45 45 return -EINVAL; 46 46 } 47 47 48 - irqreturn_t handle_ipi(void) 48 + void riscv_software_interrupt(void) 49 49 { 50 50 unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; 51 51 ··· 60 60 61 61 ops = xchg(pending_ipis, 0); 62 62 if (ops == 0) 63 - return IRQ_HANDLED; 63 + return; 64 64 65 65 if (ops & (1 << IPI_RESCHEDULE)) 66 66 scheduler_ipi(); ··· 73 73 /* Order data access and bit testing. */ 74 74 mb(); 75 75 } 76 - 77 - return IRQ_HANDLED; 78 76 } 79 77 80 78 static void
-1
arch/riscv/kernel/smpboot.c
··· 104 104 current->active_mm = mm; 105 105 106 106 trap_init(); 107 - init_clockevent(); 108 107 notify_cpu_starting(smp_processor_id()); 109 108 set_cpu_online(smp_processor_id(), 1); 110 109 local_flush_tlb_all();
+1 -29
arch/riscv/kernel/time.c
··· 13 13 */ 14 14 15 15 #include <linux/clocksource.h> 16 - #include <linux/clockchips.h> 17 16 #include <linux/delay.h> 18 - 19 - #ifdef CONFIG_RISCV_TIMER 20 - #include <linux/timer_riscv.h> 21 - #endif 22 - 23 17 #include <asm/sbi.h> 24 18 25 19 unsigned long riscv_timebase; 26 - 27 - DECLARE_PER_CPU(struct clock_event_device, riscv_clock_event); 28 - 29 - void riscv_timer_interrupt(void) 30 - { 31 - #ifdef CONFIG_RISCV_TIMER 32 - /* 33 - * FIXME: This needs to be cleaned up along with the rest of the IRQ 34 - * handling cleanup. See irq.c for more details. 35 - */ 36 - struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event); 37 - 38 - evdev->event_handler(evdev); 39 - #endif 40 - } 41 - 42 - void __init init_clockevent(void) 43 - { 44 - timer_probe(); 45 - csr_set(sie, SIE_STIE); 46 - } 47 20 48 21 void __init time_init(void) 49 22 { ··· 29 56 riscv_timebase = prop; 30 57 31 58 lpj_fine = riscv_timebase / HZ; 32 - 33 - init_clockevent(); 59 + timer_probe(); 34 60 }
-1
arch/riscv/kernel/traps.c
··· 138 138 #endif /* CONFIG_GENERIC_BUG */ 139 139 140 140 force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)(regs->sepc), current); 141 - regs->sepc += 0x4; 142 141 } 143 142 144 143 #ifdef CONFIG_GENERIC_BUG
+2 -2
arch/riscv/kernel/vdso/Makefile
··· 52 52 # Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions. 53 53 # Make sure only to export the intended __vdso_xxx symbol offsets. 54 54 quiet_cmd_vdsold = VDSOLD $@ 55 - cmd_vdsold = $(CC) $(KCFLAGS) $(call cc-option, -no-pie) -nostdlib $(SYSCFLAGS_$(@F)) \ 56 - -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \ 55 + cmd_vdsold = $(CC) $(KBUILD_CFLAGS) $(call cc-option, -no-pie) -nostdlib -nostartfiles $(SYSCFLAGS_$(@F)) \ 56 + -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp && \ 57 57 $(CROSS_COMPILE)objcopy \ 58 58 $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ 59 59
+1
arch/riscv/lib/Makefile
··· 2 2 lib-y += memcpy.o 3 3 lib-y += memset.o 4 4 lib-y += uaccess.o 5 + lib-y += tishift.o 5 6 6 7 lib-$(CONFIG_32BIT) += udivdi3.o
+42
arch/riscv/lib/tishift.S
··· 1 + /* 2 + * Copyright (C) 2018 Free Software Foundation, Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + .globl __lshrti3 14 + __lshrti3: 15 + beqz a2, .L1 16 + li a5,64 17 + sub a5,a5,a2 18 + addi sp,sp,-16 19 + sext.w a4,a5 20 + blez a5, .L2 21 + sext.w a2,a2 22 + sll a4,a1,a4 23 + srl a0,a0,a2 24 + srl a1,a1,a2 25 + or a0,a0,a4 26 + sd a1,8(sp) 27 + sd a0,0(sp) 28 + ld a0,0(sp) 29 + ld a1,8(sp) 30 + addi sp,sp,16 31 + ret 32 + .L1: 33 + ret 34 + .L2: 35 + negw a4,a4 36 + srl a1,a1,a4 37 + sd a1,0(sp) 38 + sd zero,8(sp) 39 + ld a0,0(sp) 40 + ld a1,8(sp) 41 + addi sp,sp,16 42 + ret
+11
drivers/clocksource/Kconfig
··· 609 609 help 610 610 This option enables support for the Andestech ATCPIT100 timers. 611 611 612 + config RISCV_TIMER 613 + bool "Timer for the RISC-V platform" 614 + depends on RISCV 615 + default y 616 + select TIMER_PROBE 617 + select TIMER_OF 618 + help 619 + This enables the per-hart timer built into all RISC-V systems, which 620 + is accessed via both the SBI and the rdcycle instruction. This is 621 + required for all RISC-V systems. 622 + 612 623 endmenu
+1
drivers/clocksource/Makefile
··· 78 78 obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o 79 79 obj-$(CONFIG_X86_NUMACHIP) += numachip.o 80 80 obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o 81 + obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
+105
drivers/clocksource/riscv_timer.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2012 Regents of the University of California 4 + * Copyright (C) 2017 SiFive 5 + */ 6 + #include <linux/clocksource.h> 7 + #include <linux/clockchips.h> 8 + #include <linux/cpu.h> 9 + #include <linux/delay.h> 10 + #include <linux/irq.h> 11 + #include <asm/sbi.h> 12 + 13 + /* 14 + * All RISC-V systems have a timer attached to every hart. These timers can be 15 + * read by the 'rdcycle' pseudo instruction, and can use the SBI to setup 16 + * events. In order to abstract the architecture-specific timer reading and 17 + * setting functions away from the clock event insertion code, we provide 18 + * function pointers to the clockevent subsystem that perform two basic 19 + * operations: rdtime() reads the timer on the current CPU, and 20 + * next_event(delta) sets the next timer event to 'delta' cycles in the future. 21 + * As the timers are inherently a per-cpu resource, these callbacks perform 22 + * operations on the current hart. There is guaranteed to be exactly one timer 23 + * per hart on all RISC-V systems. 24 + */ 25 + 26 + static int riscv_clock_next_event(unsigned long delta, 27 + struct clock_event_device *ce) 28 + { 29 + csr_set(sie, SIE_STIE); 30 + sbi_set_timer(get_cycles64() + delta); 31 + return 0; 32 + } 33 + 34 + static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = { 35 + .name = "riscv_timer_clockevent", 36 + .features = CLOCK_EVT_FEAT_ONESHOT, 37 + .rating = 100, 38 + .set_next_event = riscv_clock_next_event, 39 + }; 40 + 41 + /* 42 + * It is guaranteed that all the timers across all the harts are synchronized 43 + * within one tick of each other, so while this could technically go 44 + * backwards when hopping between CPUs, practically it won't happen. 45 + */ 46 + static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs) 47 + { 48 + return get_cycles64(); 49 + } 50 + 51 + static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = { 52 + .name = "riscv_clocksource", 53 + .rating = 300, 54 + .mask = CLOCKSOURCE_MASK(BITS_PER_LONG), 55 + .flags = CLOCK_SOURCE_IS_CONTINUOUS, 56 + .read = riscv_clocksource_rdtime, 57 + }; 58 + 59 + static int riscv_timer_starting_cpu(unsigned int cpu) 60 + { 61 + struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu); 62 + 63 + ce->cpumask = cpumask_of(cpu); 64 + clockevents_config_and_register(ce, riscv_timebase, 100, 0x7fffffff); 65 + 66 + csr_set(sie, SIE_STIE); 67 + return 0; 68 + } 69 + 70 + static int riscv_timer_dying_cpu(unsigned int cpu) 71 + { 72 + csr_clear(sie, SIE_STIE); 73 + return 0; 74 + } 75 + 76 + /* called directly from the low-level interrupt handler */ 77 + void riscv_timer_interrupt(void) 78 + { 79 + struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event); 80 + 81 + csr_clear(sie, SIE_STIE); 82 + evdev->event_handler(evdev); 83 + } 84 + 85 + static int __init riscv_timer_init_dt(struct device_node *n) 86 + { 87 + int cpu_id = riscv_of_processor_hart(n), error; 88 + struct clocksource *cs; 89 + 90 + if (cpu_id != smp_processor_id()) 91 + return 0; 92 + 93 + cs = per_cpu_ptr(&riscv_clocksource, cpu_id); 94 + clocksource_register_hz(cs, riscv_timebase); 95 + 96 + error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING, 97 + "clockevents/riscv/timer:starting", 98 + riscv_timer_starting_cpu, riscv_timer_dying_cpu); 99 + if (error) 100 + pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", 101 + error, cpu_id); 102 + return error; 103 + } 104 + 105 + TIMER_OF_DECLARE(riscv_timer, "riscv", riscv_timer_init_dt);
+12
drivers/irqchip/Kconfig
··· 372 372 IRQs for Qualcomm Technologies Inc (QTI) mobile chips. 373 373 374 374 endmenu 375 + 376 + config SIFIVE_PLIC 377 + bool "SiFive Platform-Level Interrupt Controller" 378 + depends on RISCV 379 + help 380 + This enables support for the PLIC chip found in SiFive (and 381 + potentially other) RISC-V systems. The PLIC controls devices 382 + interrupts and connects them to each core's local interrupt 383 + controller. Aside from timer and software interrupts, all other 384 + interrupt sources are subordinate to the PLIC. 385 + 386 + If you don't know what to do here, say Y.
+1
drivers/irqchip/Makefile
··· 87 87 obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o 88 88 obj-$(CONFIG_NDS32) += irq-ativic32.o 89 89 obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o 90 + obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
+260
drivers/irqchip/irq-sifive-plic.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2017 SiFive 4 + * Copyright (C) 2018 Christoph Hellwig 5 + */ 6 + #define pr_fmt(fmt) "plic: " fmt 7 + #include <linux/interrupt.h> 8 + #include <linux/io.h> 9 + #include <linux/irq.h> 10 + #include <linux/irqchip.h> 11 + #include <linux/irqdomain.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/of_address.h> 15 + #include <linux/of_irq.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/spinlock.h> 18 + 19 + /* 20 + * This driver implements a version of the RISC-V PLIC with the actual layout 21 + * specified in chapter 8 of the SiFive U5 Coreplex Series Manual: 22 + * 23 + * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf 24 + * 25 + * The largest number supported by devices marked as 'sifive,plic-1.0.0', is 26 + * 1024, of which device 0 is defined as non-existent by the RISC-V Privileged 27 + * Spec. 28 + */ 29 + 30 + #define MAX_DEVICES 1024 31 + #define MAX_CONTEXTS 15872 32 + 33 + /* 34 + * Each interrupt source has a priority register associated with it. 35 + * We always hardwire it to one in Linux. 36 + */ 37 + #define PRIORITY_BASE 0 38 + #define PRIORITY_PER_ID 4 39 + 40 + /* 41 + * Each hart context has a vector of interrupt enable bits associated with it. 42 + * There's one bit for each interrupt source. 43 + */ 44 + #define ENABLE_BASE 0x2000 45 + #define ENABLE_PER_HART 0x80 46 + 47 + /* 48 + * Each hart context has a set of control registers associated with it. Right 49 + * now there's only two: a source priority threshold over which the hart will 50 + * take an interrupt, and a register to claim interrupts. 51 + */ 52 + #define CONTEXT_BASE 0x200000 53 + #define CONTEXT_PER_HART 0x1000 54 + #define CONTEXT_THRESHOLD 0x00 55 + #define CONTEXT_CLAIM 0x04 56 + 57 + static void __iomem *plic_regs; 58 + 59 + struct plic_handler { 60 + bool present; 61 + int ctxid; 62 + }; 63 + static DEFINE_PER_CPU(struct plic_handler, plic_handlers); 64 + 65 + static inline void __iomem *plic_hart_offset(int ctxid) 66 + { 67 + return plic_regs + CONTEXT_BASE + ctxid * CONTEXT_PER_HART; 68 + } 69 + 70 + static inline u32 __iomem *plic_enable_base(int ctxid) 71 + { 72 + return plic_regs + ENABLE_BASE + ctxid * ENABLE_PER_HART; 73 + } 74 + 75 + /* 76 + * Protect mask operations on the registers given that we can't assume that 77 + * atomic memory operations work on them. 78 + */ 79 + static DEFINE_RAW_SPINLOCK(plic_toggle_lock); 80 + 81 + static inline void plic_toggle(int ctxid, int hwirq, int enable) 82 + { 83 + u32 __iomem *reg = plic_enable_base(ctxid) + (hwirq / 32); 84 + u32 hwirq_mask = 1 << (hwirq % 32); 85 + 86 + raw_spin_lock(&plic_toggle_lock); 87 + if (enable) 88 + writel(readl(reg) | hwirq_mask, reg); 89 + else 90 + writel(readl(reg) & ~hwirq_mask, reg); 91 + raw_spin_unlock(&plic_toggle_lock); 92 + } 93 + 94 + static inline void plic_irq_toggle(struct irq_data *d, int enable) 95 + { 96 + int cpu; 97 + 98 + writel(enable, plic_regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); 99 + for_each_cpu(cpu, irq_data_get_affinity_mask(d)) { 100 + struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); 101 + 102 + if (handler->present) 103 + plic_toggle(handler->ctxid, d->hwirq, enable); 104 + } 105 + } 106 + 107 + static void plic_irq_enable(struct irq_data *d) 108 + { 109 + plic_irq_toggle(d, 1); 110 + } 111 + 112 + static void plic_irq_disable(struct irq_data *d) 113 + { 114 + plic_irq_toggle(d, 0); 115 + } 116 + 117 + static struct irq_chip plic_chip = { 118 + .name = "SiFive PLIC", 119 + /* 120 + * There is no need to mask/unmask PLIC interrupts. They are "masked" 121 + * by reading claim and "unmasked" when writing it back. 122 + */ 123 + .irq_enable = plic_irq_enable, 124 + .irq_disable = plic_irq_disable, 125 + }; 126 + 127 + static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, 128 + irq_hw_number_t hwirq) 129 + { 130 + irq_set_chip_and_handler(irq, &plic_chip, handle_simple_irq); 131 + irq_set_chip_data(irq, NULL); 132 + irq_set_noprobe(irq); 133 + return 0; 134 + } 135 + 136 + static const struct irq_domain_ops plic_irqdomain_ops = { 137 + .map = plic_irqdomain_map, 138 + .xlate = irq_domain_xlate_onecell, 139 + }; 140 + 141 + static struct irq_domain *plic_irqdomain; 142 + 143 + /* 144 + * Handling an interrupt is a two-step process: first you claim the interrupt 145 + * by reading the claim register, then you complete the interrupt by writing 146 + * that source ID back to the same claim register. This automatically enables 147 + * and disables the interrupt, so there's nothing else to do. 148 + */ 149 + static void plic_handle_irq(struct pt_regs *regs) 150 + { 151 + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); 152 + void __iomem *claim = plic_hart_offset(handler->ctxid) + CONTEXT_CLAIM; 153 + irq_hw_number_t hwirq; 154 + 155 + WARN_ON_ONCE(!handler->present); 156 + 157 + csr_clear(sie, SIE_SEIE); 158 + while ((hwirq = readl(claim))) { 159 + int irq = irq_find_mapping(plic_irqdomain, hwirq); 160 + 161 + if (unlikely(irq <= 0)) 162 + pr_warn_ratelimited("can't find mapping for hwirq %lu\n", 163 + hwirq); 164 + else 165 + generic_handle_irq(irq); 166 + writel(hwirq, claim); 167 + } 168 + csr_set(sie, SIE_SEIE); 169 + } 170 + 171 + /* 172 + * Walk up the DT tree until we find an active RISC-V core (HART) node and 173 + * extract the cpuid from it. 174 + */ 175 + static int plic_find_hart_id(struct device_node *node) 176 + { 177 + for (; node; node = node->parent) { 178 + if (of_device_is_compatible(node, "riscv")) 179 + return riscv_of_processor_hart(node); 180 + } 181 + 182 + return -1; 183 + } 184 + 185 + static int __init plic_init(struct device_node *node, 186 + struct device_node *parent) 187 + { 188 + int error = 0, nr_handlers, nr_mapped = 0, i; 189 + u32 nr_irqs; 190 + 191 + if (plic_regs) { 192 + pr_warn("PLIC already present.\n"); 193 + return -ENXIO; 194 + } 195 + 196 + plic_regs = of_iomap(node, 0); 197 + if (WARN_ON(!plic_regs)) 198 + return -EIO; 199 + 200 + error = -EINVAL; 201 + of_property_read_u32(node, "riscv,ndev", &nr_irqs); 202 + if (WARN_ON(!nr_irqs)) 203 + goto out_iounmap; 204 + 205 + nr_handlers = of_irq_count(node); 206 + if (WARN_ON(!nr_handlers)) 207 + goto out_iounmap; 208 + if (WARN_ON(nr_handlers < num_possible_cpus())) 209 + goto out_iounmap; 210 + 211 + error = -ENOMEM; 212 + plic_irqdomain = irq_domain_add_linear(node, nr_irqs + 1, 213 + &plic_irqdomain_ops, NULL); 214 + if (WARN_ON(!plic_irqdomain)) 215 + goto out_iounmap; 216 + 217 + for (i = 0; i < nr_handlers; i++) { 218 + struct of_phandle_args parent; 219 + struct plic_handler *handler; 220 + irq_hw_number_t hwirq; 221 + int cpu; 222 + 223 + if (of_irq_parse_one(node, i, &parent)) { 224 + pr_err("failed to parse parent for context %d.\n", i); 225 + continue; 226 + } 227 + 228 + /* skip context holes */ 229 + if (parent.args[0] == -1) 230 + continue; 231 + 232 + cpu = plic_find_hart_id(parent.np); 233 + if (cpu < 0) { 234 + pr_warn("failed to parse hart ID for context %d.\n", i); 235 + continue; 236 + } 237 + 238 + handler = per_cpu_ptr(&plic_handlers, cpu); 239 + handler->present = true; 240 + handler->ctxid = i; 241 + 242 + /* priority must be > threshold to trigger an interrupt */ 243 + writel(0, plic_hart_offset(i) + CONTEXT_THRESHOLD); 244 + for (hwirq = 1; hwirq <= nr_irqs; hwirq++) 245 + plic_toggle(i, hwirq, 0); 246 + nr_mapped++; 247 + } 248 + 249 + pr_info("mapped %d interrupts to %d (out of %d) handlers.\n", 250 + nr_irqs, nr_mapped, nr_handlers); 251 + set_handle_irq(plic_handle_irq); 252 + return 0; 253 + 254 + out_iounmap: 255 + iounmap(plic_regs); 256 + return error; 257 + } 258 + 259 + IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init); 260 + IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
+1
include/linux/cpuhotplug.h
··· 125 125 CPUHP_AP_MARCO_TIMER_STARTING, 126 126 CPUHP_AP_MIPS_GIC_TIMER_STARTING, 127 127 CPUHP_AP_ARC_TIMER_STARTING, 128 + CPUHP_AP_RISCV_TIMER_STARTING, 128 129 CPUHP_AP_KVM_STARTING, 129 130 CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, 130 131 CPUHP_AP_KVM_ARM_VGIC_STARTING,