diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-19 12:56:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-19 12:56:38 -0400 |
commit | 1009aa1205c2c5e9101437dcadfa195708d863bf (patch) | |
tree | 49e76c84522866fae25ba37372aef241b8713c3f | |
parent | 1d0926e99de7b486321e3db924b445531eea5e18 (diff) | |
parent | 627672cf431b0379c07cc8d146f907cda6797222 (diff) |
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
27 files changed, 625 insertions, 59 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt new file mode 100644 index 000000000000..b0a8af51c388 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt | |||
@@ -0,0 +1,44 @@ | |||
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 | }; | ||
diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.txt b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.txt new file mode 100644 index 000000000000..6adf7a6e8825 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.txt | |||
@@ -0,0 +1,58 @@ | |||
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 | }; | ||
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 2627e4813edf..9ddd88bb30b7 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile | |||
@@ -25,6 +25,9 @@ ifeq ($(CONFIG_ARCH_RV64I),y) | |||
25 | 25 | ||
26 | KBUILD_CFLAGS += -mabi=lp64 | 26 | KBUILD_CFLAGS += -mabi=lp64 |
27 | KBUILD_AFLAGS += -mabi=lp64 | 27 | KBUILD_AFLAGS += -mabi=lp64 |
28 | |||
29 | KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0500, -DCONFIG_ARCH_SUPPORTS_INT128) | ||
30 | |||
28 | KBUILD_MARCH = rv64im | 31 | KBUILD_MARCH = rv64im |
29 | LDFLAGS += -melf64lriscv | 32 | LDFLAGS += -melf64lriscv |
30 | else | 33 | else |
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index 07326466871b..36473d7dbaac 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig | |||
@@ -76,3 +76,4 @@ CONFIG_ROOT_NFS=y | |||
76 | CONFIG_CRYPTO_USER_API_HASH=y | 76 | CONFIG_CRYPTO_USER_API_HASH=y |
77 | CONFIG_MODULES=y | 77 | CONFIG_MODULES=y |
78 | CONFIG_MODULE_UNLOAD=y | 78 | CONFIG_MODULE_UNLOAD=y |
79 | CONFIG_SIFIVE_PLIC=y | ||
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 421fa3585798..28a0d1cb374c 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h | |||
@@ -54,6 +54,7 @@ | |||
54 | /* Interrupt Enable and Interrupt Pending flags */ | 54 | /* Interrupt Enable and Interrupt Pending flags */ |
55 | #define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */ | 55 | #define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */ |
56 | #define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */ | 56 | #define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */ |
57 | #define SIE_SEIE _AC(0x00000200, UL) /* External Interrupt Enable */ | ||
57 | 58 | ||
58 | #define EXC_INST_MISALIGNED 0 | 59 | #define EXC_INST_MISALIGNED 0 |
59 | #define EXC_INST_ACCESS 1 | 60 | #define EXC_INST_ACCESS 1 |
diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h index 4dee9d4c13c0..996b6fbe17a6 100644 --- a/arch/riscv/include/asm/irq.h +++ b/arch/riscv/include/asm/irq.h | |||
@@ -17,11 +17,8 @@ | |||
17 | 17 | ||
18 | #define NR_IRQS 0 | 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 | void riscv_timer_interrupt(void); | 20 | void riscv_timer_interrupt(void); |
21 | void riscv_software_interrupt(void); | ||
25 | 22 | ||
26 | #include <asm-generic/irq.h> | 23 | #include <asm-generic/irq.h> |
27 | 24 | ||
diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index 0e638a0c3feb..aefbfaa6a781 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/perf_event.h> | 11 | #include <linux/perf_event.h> |
12 | #include <linux/ptrace.h> | 12 | #include <linux/ptrace.h> |
13 | #include <linux/interrupt.h> | ||
13 | 14 | ||
14 | #define RISCV_BASE_COUNTERS 2 | 15 | #define RISCV_BASE_COUNTERS 2 |
15 | 16 | ||
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h index 85e4220839b0..36016845461d 100644 --- a/arch/riscv/include/asm/smp.h +++ b/arch/riscv/include/asm/smp.h | |||
@@ -25,9 +25,6 @@ | |||
25 | #ifdef CONFIG_SMP | 25 | #ifdef CONFIG_SMP |
26 | 26 | ||
27 | /* SMP initialization hook for setup_arch */ | 27 | /* SMP initialization hook for setup_arch */ |
28 | void __init init_clockevent(void); | ||
29 | |||
30 | /* SMP initialization hook for setup_arch */ | ||
31 | void __init setup_smp(void); | 28 | void __init setup_smp(void); |
32 | 29 | ||
33 | /* Hook for the generic smp_call_function_many() routine. */ | 30 | /* Hook for the generic smp_call_function_many() routine. */ |
@@ -44,9 +41,6 @@ void arch_send_call_function_single_ipi(int cpu); | |||
44 | */ | 41 | */ |
45 | #define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU))) | 42 | #define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU))) |
46 | 43 | ||
47 | /* Interprocessor interrupt handler */ | ||
48 | irqreturn_t handle_ipi(void); | ||
49 | |||
50 | #endif /* CONFIG_SMP */ | 44 | #endif /* CONFIG_SMP */ |
51 | 45 | ||
52 | #endif /* _ASM_RISCV_SMP_H */ | 46 | #endif /* _ASM_RISCV_SMP_H */ |
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 9aaf6c986771..fa2c08e3c05e 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S | |||
@@ -168,8 +168,8 @@ ENTRY(handle_exception) | |||
168 | 168 | ||
169 | /* Handle interrupts */ | 169 | /* Handle interrupts */ |
170 | move a0, sp /* pt_regs */ | 170 | move a0, sp /* pt_regs */ |
171 | REG_L a1, handle_arch_irq | 171 | move a1, s4 /* scause */ |
172 | jr a1 | 172 | tail do_IRQ |
173 | 1: | 173 | 1: |
174 | /* Exceptions run with interrupts enabled */ | 174 | /* Exceptions run with interrupts enabled */ |
175 | csrs sstatus, SR_SIE | 175 | csrs sstatus, SR_SIE |
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 6e07ed37bbff..c4d2c63f9a29 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S | |||
@@ -94,6 +94,7 @@ relocate: | |||
94 | or a0, a0, a1 | 94 | or a0, a0, a1 |
95 | sfence.vma | 95 | sfence.vma |
96 | csrw sptbr, a0 | 96 | csrw sptbr, a0 |
97 | .align 2 | ||
97 | 1: | 98 | 1: |
98 | /* Set trap vector to spin forever to help debug */ | 99 | /* Set trap vector to spin forever to help debug */ |
99 | la a0, .Lsecondary_park | 100 | la a0, .Lsecondary_park |
@@ -143,6 +144,7 @@ relocate: | |||
143 | tail smp_callin | 144 | tail smp_callin |
144 | #endif | 145 | #endif |
145 | 146 | ||
147 | .align 2 | ||
146 | .Lsecondary_park: | 148 | .Lsecondary_park: |
147 | /* We lack SMP support or have too many harts, so park this hart */ | 149 | /* We lack SMP support or have too many harts, so park this hart */ |
148 | wfi | 150 | wfi |
diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c index 7bcdaed15703..0cfac48a1272 100644 --- a/arch/riscv/kernel/irq.c +++ b/arch/riscv/kernel/irq.c | |||
@@ -1,21 +1,58 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright (C) 2012 Regents of the University of California | 3 | * Copyright (C) 2012 Regents of the University of California |
3 | * Copyright (C) 2017 SiFive | 4 | * Copyright (C) 2017 SiFive |
4 | * | 5 | * Copyright (C) 2018 Christoph Hellwig |
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. | ||
13 | */ | 6 | */ |
14 | 7 | ||
15 | #include <linux/interrupt.h> | 8 | #include <linux/interrupt.h> |
16 | #include <linux/irqchip.h> | 9 | #include <linux/irqchip.h> |
17 | #include <linux/irqdomain.h> | 10 | #include <linux/irqdomain.h> |
18 | 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 | } | ||
55 | |||
19 | void __init init_IRQ(void) | 56 | void __init init_IRQ(void) |
20 | { | 57 | { |
21 | irqchip_init(); | 58 | irqchip_init(); |
diff --git a/arch/riscv/kernel/perf_event.c b/arch/riscv/kernel/perf_event.c index b0e10c4e9f77..a243fae1c1db 100644 --- a/arch/riscv/kernel/perf_event.c +++ b/arch/riscv/kernel/perf_event.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/bitmap.h> | 28 | #include <linux/bitmap.h> |
29 | #include <linux/irq.h> | 29 | #include <linux/irq.h> |
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/perf_event.h> | 30 | #include <linux/perf_event.h> |
32 | #include <linux/atomic.h> | 31 | #include <linux/atomic.h> |
33 | #include <linux/of.h> | 32 | #include <linux/of.h> |
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index f0d2070866d4..db20dc630e7e 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c | |||
@@ -39,6 +39,27 @@ | |||
39 | #include <asm/tlbflush.h> | 39 | #include <asm/tlbflush.h> |
40 | #include <asm/thread_info.h> | 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 | #ifdef CONFIG_DUMMY_CONSOLE | 63 | #ifdef CONFIG_DUMMY_CONSOLE |
43 | struct screen_info screen_info = { | 64 | struct screen_info screen_info = { |
44 | .orig_video_lines = 30, | 65 | .orig_video_lines = 30, |
@@ -195,6 +216,12 @@ static void __init setup_bootmem(void) | |||
195 | 216 | ||
196 | void __init setup_arch(char **cmdline_p) | 217 | void __init setup_arch(char **cmdline_p) |
197 | { | 218 | { |
219 | #if defined(CONFIG_EARLY_PRINTK) | ||
220 | if (likely(early_console == NULL)) { | ||
221 | early_console = &riscv_sbi_early_console_dev; | ||
222 | register_console(early_console); | ||
223 | } | ||
224 | #endif | ||
198 | *cmdline_p = boot_command_line; | 225 | *cmdline_p = boot_command_line; |
199 | 226 | ||
200 | parse_early_param(); | 227 | parse_early_param(); |
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 6d3962435720..906fe21ea21b 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c | |||
@@ -45,7 +45,7 @@ int setup_profiling_timer(unsigned int multiplier) | |||
45 | return -EINVAL; | 45 | return -EINVAL; |
46 | } | 46 | } |
47 | 47 | ||
48 | irqreturn_t handle_ipi(void) | 48 | void riscv_software_interrupt(void) |
49 | { | 49 | { |
50 | unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; | 50 | unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; |
51 | 51 | ||
@@ -60,7 +60,7 @@ irqreturn_t handle_ipi(void) | |||
60 | 60 | ||
61 | ops = xchg(pending_ipis, 0); | 61 | ops = xchg(pending_ipis, 0); |
62 | if (ops == 0) | 62 | if (ops == 0) |
63 | return IRQ_HANDLED; | 63 | return; |
64 | 64 | ||
65 | if (ops & (1 << IPI_RESCHEDULE)) | 65 | if (ops & (1 << IPI_RESCHEDULE)) |
66 | scheduler_ipi(); | 66 | scheduler_ipi(); |
@@ -73,8 +73,6 @@ irqreturn_t handle_ipi(void) | |||
73 | /* Order data access and bit testing. */ | 73 | /* Order data access and bit testing. */ |
74 | mb(); | 74 | mb(); |
75 | } | 75 | } |
76 | |||
77 | return IRQ_HANDLED; | ||
78 | } | 76 | } |
79 | 77 | ||
80 | static void | 78 | static void |
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index f741458c5a3f..56abab6a9812 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c | |||
@@ -104,7 +104,6 @@ asmlinkage void __init smp_callin(void) | |||
104 | current->active_mm = mm; | 104 | current->active_mm = mm; |
105 | 105 | ||
106 | trap_init(); | 106 | trap_init(); |
107 | init_clockevent(); | ||
108 | notify_cpu_starting(smp_processor_id()); | 107 | notify_cpu_starting(smp_processor_id()); |
109 | set_cpu_online(smp_processor_id(), 1); | 108 | set_cpu_online(smp_processor_id(), 1); |
110 | local_flush_tlb_all(); | 109 | local_flush_tlb_all(); |
diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c index 2463fcca719e..1911c8f6b8a6 100644 --- a/arch/riscv/kernel/time.c +++ b/arch/riscv/kernel/time.c | |||
@@ -13,38 +13,11 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
16 | #include <linux/clockchips.h> | ||
17 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
18 | |||
19 | #ifdef CONFIG_RISCV_TIMER | ||
20 | #include <linux/timer_riscv.h> | ||
21 | #endif | ||
22 | |||
23 | #include <asm/sbi.h> | 17 | #include <asm/sbi.h> |
24 | 18 | ||
25 | unsigned long riscv_timebase; | 19 | unsigned long riscv_timebase; |
26 | 20 | ||
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 | |||
48 | void __init time_init(void) | 21 | void __init time_init(void) |
49 | { | 22 | { |
50 | struct device_node *cpu; | 23 | struct device_node *cpu; |
@@ -56,6 +29,5 @@ void __init time_init(void) | |||
56 | riscv_timebase = prop; | 29 | riscv_timebase = prop; |
57 | 30 | ||
58 | lpj_fine = riscv_timebase / HZ; | 31 | lpj_fine = riscv_timebase / HZ; |
59 | 32 | timer_probe(); | |
60 | init_clockevent(); | ||
61 | } | 33 | } |
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 81a1952015a6..24a9333dda2c 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c | |||
@@ -138,7 +138,6 @@ asmlinkage void do_trap_break(struct pt_regs *regs) | |||
138 | #endif /* CONFIG_GENERIC_BUG */ | 138 | #endif /* CONFIG_GENERIC_BUG */ |
139 | 139 | ||
140 | force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)(regs->sepc), current); | 140 | force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)(regs->sepc), current); |
141 | regs->sepc += 0x4; | ||
142 | } | 141 | } |
143 | 142 | ||
144 | #ifdef CONFIG_GENERIC_BUG | 143 | #ifdef CONFIG_GENERIC_BUG |
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index f6561b783b61..eed1c137f618 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile | |||
@@ -52,8 +52,8 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE | |||
52 | # Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions. | 52 | # Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions. |
53 | # Make sure only to export the intended __vdso_xxx symbol offsets. | 53 | # Make sure only to export the intended __vdso_xxx symbol offsets. |
54 | quiet_cmd_vdsold = VDSOLD $@ | 54 | quiet_cmd_vdsold = VDSOLD $@ |
55 | cmd_vdsold = $(CC) $(KCFLAGS) $(call cc-option, -no-pie) -nostdlib $(SYSCFLAGS_$(@F)) \ | 55 | cmd_vdsold = $(CC) $(KBUILD_CFLAGS) $(call cc-option, -no-pie) -nostdlib -nostartfiles $(SYSCFLAGS_$(@F)) \ |
56 | -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \ | 56 | -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp && \ |
57 | $(CROSS_COMPILE)objcopy \ | 57 | $(CROSS_COMPILE)objcopy \ |
58 | $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ | 58 | $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ |
59 | 59 | ||
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 596c2ca40d63..445ec84f9a47 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile | |||
@@ -2,5 +2,6 @@ lib-y += delay.o | |||
2 | lib-y += memcpy.o | 2 | lib-y += memcpy.o |
3 | lib-y += memset.o | 3 | lib-y += memset.o |
4 | lib-y += uaccess.o | 4 | lib-y += uaccess.o |
5 | lib-y += tishift.o | ||
5 | 6 | ||
6 | lib-$(CONFIG_32BIT) += udivdi3.o | 7 | lib-$(CONFIG_32BIT) += udivdi3.o |
diff --git a/arch/riscv/lib/tishift.S b/arch/riscv/lib/tishift.S new file mode 100644 index 000000000000..69abb1277234 --- /dev/null +++ b/arch/riscv/lib/tishift.S | |||
@@ -0,0 +1,42 @@ | |||
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 | ||
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index dec0dd88ec15..a11f4ba98b05 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -609,4 +609,15 @@ config ATCPIT100_TIMER | |||
609 | help | 609 | help |
610 | This option enables support for the Andestech ATCPIT100 timers. | 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 | endmenu | 623 | endmenu |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index c070cc7992e9..db51b2427e8a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -78,3 +78,4 @@ obj-$(CONFIG_H8300_TPU) += h8300_tpu.o | |||
78 | obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o | 78 | obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o |
79 | obj-$(CONFIG_X86_NUMACHIP) += numachip.o | 79 | obj-$(CONFIG_X86_NUMACHIP) += numachip.o |
80 | obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o | 80 | obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o |
81 | obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o | ||
diff --git a/drivers/clocksource/riscv_timer.c b/drivers/clocksource/riscv_timer.c new file mode 100644 index 000000000000..4e8b347e43e2 --- /dev/null +++ b/drivers/clocksource/riscv_timer.c | |||
@@ -0,0 +1,105 @@ | |||
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); | ||
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d564d21245c5..383e7b70221d 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -372,3 +372,15 @@ config QCOM_PDC | |||
372 | IRQs for Qualcomm Technologies Inc (QTI) mobile chips. | 372 | IRQs for Qualcomm Technologies Inc (QTI) mobile chips. |
373 | 373 | ||
374 | endmenu | 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. | ||
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 15f268f646bf..fbd1ec8070ef 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -87,3 +87,4 @@ obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o | |||
87 | obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o | 87 | obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o |
88 | obj-$(CONFIG_NDS32) += irq-ativic32.o | 88 | obj-$(CONFIG_NDS32) += irq-ativic32.o |
89 | obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o | 89 | obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o |
90 | obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o | ||
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c new file mode 100644 index 000000000000..532e9d68c704 --- /dev/null +++ b/drivers/irqchip/irq-sifive-plic.c | |||
@@ -0,0 +1,260 @@ | |||
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 */ | ||
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 4cf06a64bc02..c49843c4d031 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h | |||
@@ -125,6 +125,7 @@ enum cpuhp_state { | |||
125 | CPUHP_AP_MARCO_TIMER_STARTING, | 125 | CPUHP_AP_MARCO_TIMER_STARTING, |
126 | CPUHP_AP_MIPS_GIC_TIMER_STARTING, | 126 | CPUHP_AP_MIPS_GIC_TIMER_STARTING, |
127 | CPUHP_AP_ARC_TIMER_STARTING, | 127 | CPUHP_AP_ARC_TIMER_STARTING, |
128 | CPUHP_AP_RISCV_TIMER_STARTING, | ||
128 | CPUHP_AP_KVM_STARTING, | 129 | CPUHP_AP_KVM_STARTING, |
129 | CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, | 130 | CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, |
130 | CPUHP_AP_KVM_ARM_VGIC_STARTING, | 131 | CPUHP_AP_KVM_ARM_VGIC_STARTING, |