+++ /dev/null
-From 6de0b16fb7a2cea47e9a75534b4ec59f36998616 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Fri, 12 May 2017 16:01:18 -0700
-Subject: [PATCH 01/11] base: fix order of OF initialization
-
-This fixes: [ 0.010000] cpu cpu0: Error -2 creating of_node link
-... which you get for every CPU on all architectures with a OF cpu/ node.
-
-This affects riscv, nios, etc.
-
-Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
----
- drivers/base/init.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/base/init.c b/drivers/base/init.c
-index dd85b05..908e652 100644
---- a/drivers/base/init.c
-+++ b/drivers/base/init.c
-@@ -30,9 +30,9 @@ void __init driver_init(void)
- /* These are also core pieces, but must come after the
- * core core pieces.
- */
-+ of_core_init();
- platform_bus_init();
- cpu_dev_init();
- memory_dev_init();
- container_dev_init();
-- of_core_init();
- }
---
-2.1.4
-
+++ /dev/null
-From 7866ef38a00cd390596a67e19d23d8ffd6058732 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@sifive.com>
-Date: Tue, 21 Nov 2017 15:29:07 -0800
-Subject: [PATCH 02/11] dt-bindings: Correct RISC-V's timebase-frequency
-
-Someone must have read the device tree specification incorrectly,
-because we were putting timebase-frequency in the wrong place. This
-corrects the issue, moving it from
-
-/ {
- cpus {
- timebase-frequency = X;
- }
-}
-
-to
-
-/ {
- cpus {
- cpu@0 {
- timebase-frequency = X;
- }
- }
-}
-
-This is great, because the timer's frequency should really be a per-cpu
-quantity on RISC-V systems since there's a timer per CPU. This should
-lead to some cleanups in our timer driver.
-
-CC: Wesley Terpstra <wesley@sifive.com>
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- Documentation/devicetree/bindings/riscv/cpus.txt | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/Documentation/devicetree/bindings/riscv/cpus.txt b/Documentation/devicetree/bindings/riscv/cpus.txt
-index adf7b7a..b0b038d 100644
---- a/Documentation/devicetree/bindings/riscv/cpus.txt
-+++ b/Documentation/devicetree/bindings/riscv/cpus.txt
-@@ -93,9 +93,9 @@ Linux is allowed to run on.
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-- timebase-frequency = <1000000>;
- cpu@0 {
- clock-frequency = <1600000000>;
-+ timebase-frequency = <1000000>;
- compatible = "sifive,rocket0", "riscv";
- device_type = "cpu";
- i-cache-block-size = <64>;
-@@ -113,6 +113,7 @@ Linux is allowed to run on.
- };
- cpu@1 {
- clock-frequency = <1600000000>;
-+ timebase-frequency = <1000000>;
- compatible = "sifive,rocket0", "riscv";
- d-cache-block-size = <64>;
- d-cache-sets = <64>;
-@@ -145,6 +146,7 @@ Example: Spike ISA Simulator with 1 Hart
- This device tree matches the Spike ISA golden model as run with `spike -p1`.
-
- cpus {
-+ timebase-frequency = <1000000>;
- cpu@0 {
- device_type = "cpu";
- reg = <0x00000000>;
---
-2.1.4
-
+++ /dev/null
-From fd7aef2aae3b2d250f0c04224b3c85646c2e9c56 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@sifive.com>
-Date: Mon, 20 Nov 2017 11:26:36 -0800
-Subject: [PATCH 03/11] dt-bindings: Add an enable method to RISC-V
-
-RISC-V doesn't currently specify a mechanism for enabling or disabling
-CPUs. Instead, we assume that all CPUs are enabled on boot, and if
-someone wants to save power we instead put a CPU to sleep via a WFI
-loop. Future systems may have an explicit mechanism for putting a CPU
-to sleep, so we're standardizing the device tree entry for when that
-happens.
-
-We're not defining a spin-table based interface to the firmware, as the
-plan is to handle this entirely within the kernel instead.
-
-CC: Mark Rutland <mark.rutland@arm.com>
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- Documentation/devicetree/bindings/riscv/cpus.txt | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
-diff --git a/Documentation/devicetree/bindings/riscv/cpus.txt b/Documentation/devicetree/bindings/riscv/cpus.txt
-index b0b038d..6aa9cd0 100644
---- a/Documentation/devicetree/bindings/riscv/cpus.txt
-+++ b/Documentation/devicetree/bindings/riscv/cpus.txt
-@@ -82,6 +82,15 @@ described below.
- Value type: <string>
- Definition: Contains the RISC-V ISA string of this hart. These
- ISA strings are defined by the RISC-V ISA manual.
-+ - cpu-enable-method:
-+ Usage: optional
-+ Value type: <stringlist>
-+ Definition: When absent, default is either "always-disabled"
-+ "always-enabled", depending on the current state
-+ of the CPU.
-+ Must be one of:
-+ * "always-disabled": This CPU cannot be enabled.
-+ * "always-enabled": This CPU cannot be disabled.
-
- Example: SiFive Freedom U540G Development Kit
- ---------------------------------------------
---
-2.1.4
-
+++ /dev/null
-From 577949829e04d23f58ef4ad5c448689c2ed70a49 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@dabbelt.com>
-Date: Fri, 8 Dec 2017 15:10:35 -0800
-Subject: [PATCH 04/11] RISC-V: Add early printk support via the SBI console
-
-This code lives entirely within the RISC-V arch code. I've left it
-within an "#ifdef CONFIG_EARLY_PRINTK" despite always having
-EARLY_PRINTK support on RISC-V just in case someone wants to remove
-it.
-
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- arch/riscv/kernel/setup.c | 27 +++++++++++++++++++++++++++
- 1 file changed, 27 insertions(+)
-
-diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
-index f0d2070..2e56af3 100644
---- a/arch/riscv/kernel/setup.c
-+++ b/arch/riscv/kernel/setup.c
-@@ -39,6 +39,27 @@
- #include <asm/tlbflush.h>
- #include <asm/thread_info.h>
-
-+#ifdef CONFIG_EARLY_PRINTK
-+static void sbi_console_write(struct console *co, const char *buf,
-+ unsigned int n)
-+{
-+ int i;
-+
-+ for (i = 0; i < n; ++i) {
-+ if (buf[i] == '\n')
-+ sbi_console_putchar('\r');
-+ sbi_console_putchar(buf[i]);
-+ }
-+}
-+
-+struct console riscv_sbi_early_console_dev __initdata = {
-+ .name = "early",
-+ .write = sbi_console_write,
-+ .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
-+ .index = -1
-+};
-+#endif
-+
- #ifdef CONFIG_DUMMY_CONSOLE
- struct screen_info screen_info = {
- .orig_video_lines = 30,
-@@ -195,6 +216,12 @@ static void __init setup_bootmem(void)
-
- void __init setup_arch(char **cmdline_p)
- {
-+#ifdef CONFIG_EARLY_PRINTK
-+ if (likely(!early_console)) {
-+ early_console = &riscv_sbi_early_console_dev;
-+ register_console(early_console);
-+ }
-+#endif
- *cmdline_p = boot_command_line;
-
- parse_early_param();
---
-2.1.4
-
+++ /dev/null
-From b3b48cbc8a19fc3e3abd3ae9b5d271c12a1a0b87 Mon Sep 17 00:00:00 2001
-From: Christoph Hellwig <hch@lst.de>
-Date: Wed, 25 Jul 2018 08:11:13 +0200
-Subject: [PATCH 05/11] RISC-V: simplify software interrupt / IPI code
-
-Rename handle_ipi to riscv_software_interrupt, drop the unused return
-value and provide a stub for the !SMP build. This allows simplifying
-the upcoming interrupt controller driver by not providing a wrapper
-for it.
-
-Signed-off-by: Christoph Hellwig <hch@lst.de>
----
- arch/riscv/include/asm/smp.h | 13 +++++++++++--
- arch/riscv/kernel/smp.c | 6 ++----
- 2 files changed, 13 insertions(+), 6 deletions(-)
-
-diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
-index 85e4220..80ecb95 100644
---- a/arch/riscv/include/asm/smp.h
-+++ b/arch/riscv/include/asm/smp.h
-@@ -44,8 +44,17 @@ void arch_send_call_function_single_ipi(int cpu);
- */
- #define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU)))
-
--/* Interprocessor interrupt handler */
--irqreturn_t handle_ipi(void);
-+/* Software interrupt handler */
-+void riscv_software_interrupt(void);
-+
-+#else /* CONFIG_SMP */
-+
-+/*
-+ * We currently only use software interrupts to pass inter-processor
-+ * interrupts, so if a non-SMP system gets a software interrupt then we
-+ * don't know what to do.
-+ */
-+#define riscv_software_interrupt() WARN_ON()
-
- #endif /* CONFIG_SMP */
-
-diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
-index 6d39624..906fe21 100644
---- a/arch/riscv/kernel/smp.c
-+++ b/arch/riscv/kernel/smp.c
-@@ -45,7 +45,7 @@ int setup_profiling_timer(unsigned int multiplier)
- return -EINVAL;
- }
-
--irqreturn_t handle_ipi(void)
-+void riscv_software_interrupt(void)
- {
- unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
-
-@@ -60,7 +60,7 @@ irqreturn_t handle_ipi(void)
-
- ops = xchg(pending_ipis, 0);
- if (ops == 0)
-- return IRQ_HANDLED;
-+ return;
-
- if (ops & (1 << IPI_RESCHEDULE))
- scheduler_ipi();
-@@ -73,8 +73,6 @@ irqreturn_t handle_ipi(void)
- /* Order data access and bit testing. */
- mb();
- }
--
-- return IRQ_HANDLED;
- }
-
- static void
---
-2.1.4
-
+++ /dev/null
-From 422e21b7ab41a21d7342b01fea7d1c6b91d986d8 Mon Sep 17 00:00:00 2001
-From: Christoph Hellwig <hch@lst.de>
-Date: Wed, 25 Jul 2018 08:23:21 +0200
-Subject: [PATCH 06/11] RISC-V: remove INTERRUPT_CAUSE_* defines from asm/irq.h
-
-These are only of use to the local irq controller driver, so add them in
-that driver implementation instead, which will be submitted soon.
-
-Signed-off-by: Christoph Hellwig <hch@lst.de>
----
- arch/riscv/include/asm/irq.h | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h
-index 4dee9d4..93eb75e 100644
---- a/arch/riscv/include/asm/irq.h
-+++ b/arch/riscv/include/asm/irq.h
-@@ -17,10 +17,6 @@
-
- #define NR_IRQS 0
-
--#define INTERRUPT_CAUSE_SOFTWARE 1
--#define INTERRUPT_CAUSE_TIMER 5
--#define INTERRUPT_CAUSE_EXTERNAL 9
--
- void riscv_timer_interrupt(void);
-
- #include <asm-generic/irq.h>
---
-2.1.4
-
+++ /dev/null
-From e07e6be7ef8b44155aebac95dde19a39498ebd00 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@dabbelt.com>
-Date: Tue, 19 Jun 2018 17:34:53 +0200
-Subject: [PATCH 07/11] irqchip: RISC-V Local Interrupt Controller Driver
-
-This patch adds a driver that manages the local interrupts on each
-RISC-V hart, as specifiec by the RISC-V supervisor level ISA manual.
-The local interrupt controller manages software interrupts, timer
-interrupts, and hardware interrupts (which are routed via the
-platform level interrupt controller). Per-hart local interrupt
-controllers are found on all RISC-V systems.
-
-Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
-[hch: Kconfig simplifications, various cleanups]
-Signed-off-by: Christoph Hellwig <hch@lst.de>
----
- drivers/irqchip/Kconfig | 4 +
- drivers/irqchip/Makefile | 1 +
- drivers/irqchip/irq-riscv-intc.c | 197 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 202 insertions(+)
- create mode 100644 drivers/irqchip/irq-riscv-intc.c
-
-diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
-index e9233db..8460fdce 100644
---- a/drivers/irqchip/Kconfig
-+++ b/drivers/irqchip/Kconfig
-@@ -372,3 +372,7 @@ config QCOM_PDC
- IRQs for Qualcomm Technologies Inc (QTI) mobile chips.
-
- endmenu
-+
-+config RISCV_INTC
-+ def_bool y
-+ depends on RISCV
-diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
-index 15f268f..74e333c 100644
---- a/drivers/irqchip/Makefile
-+++ b/drivers/irqchip/Makefile
-@@ -87,3 +87,4 @@ obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
- obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
- obj-$(CONFIG_NDS32) += irq-ativic32.o
- obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
-+obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
-diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
-new file mode 100644
-index 0000000..883efaa
---- /dev/null
-+++ b/drivers/irqchip/irq-riscv-intc.c
-@@ -0,0 +1,197 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2012 Regents of the University of California
-+ * Copyright (C) 2017 SiFive
-+ */
-+#include <linux/irq.h>
-+#include <linux/irqchip.h>
-+#include <linux/irqdomain.h>
-+#include <linux/interrupt.h>
-+#include <linux/of.h>
-+#include <linux/smp.h>
-+#include <asm/sbi.h>
-+
-+#define NR_RISCV_IRQS (8 * sizeof(uintptr_t))
-+
-+/*
-+ * Possible interrupt causes:
-+ */
-+#define INTERRUPT_CAUSE_SOFTWARE 1
-+#define INTERRUPT_CAUSE_TIMER 5
-+#define INTERRUPT_CAUSE_EXTERNAL 9
-+
-+/*
-+ * The high order bit of the trap cause register is always set for
-+ * interrupts, which allows us to differentiate them from exceptions
-+ * quickly. The INTERRUPT_CAUSE_* macros don't contain that bit, so we
-+ * need to mask it off.
-+ */
-+#define INTERRUPT_CAUSE_MASK (1UL << (NR_RISCV_IRQS - 1))
-+
-+struct riscv_irq_data {
-+ struct irq_chip chip;
-+ struct irq_domain *domain;
-+ int hart;
-+ char name[20];
-+};
-+
-+static DEFINE_PER_CPU(struct riscv_irq_data, riscv_irq_data);
-+
-+static void riscv_intc_irq(struct pt_regs *regs)
-+{
-+ struct pt_regs *old_regs = set_irq_regs(regs);
-+ unsigned long cause = csr_read(scause);
-+ struct irq_domain *domain;
-+
-+ WARN_ON((cause & INTERRUPT_CAUSE_MASK) == 0);
-+ cause &= ~INTERRUPT_CAUSE_MASK;
-+
-+ irq_enter();
-+
-+ /*
-+ * There are three classes of interrupt: timer, software, and
-+ * external devices. We dispatch between them here. External
-+ * device interrupts use the generic IRQ mechanisms.
-+ */
-+ switch (cause) {
-+ case INTERRUPT_CAUSE_TIMER:
-+ riscv_timer_interrupt();
-+ break;
-+ case INTERRUPT_CAUSE_SOFTWARE:
-+ riscv_software_interrupt();
-+ break;
-+ default:
-+ domain = per_cpu(riscv_irq_data, smp_processor_id()).domain;
-+ generic_handle_irq(irq_find_mapping(domain, cause));
-+ break;
-+ }
-+
-+ irq_exit();
-+ set_irq_regs(old_regs);
-+}
-+
-+static int riscv_irqdomain_map(struct irq_domain *d, unsigned int irq,
-+ irq_hw_number_t hwirq)
-+{
-+ struct riscv_irq_data *data = d->host_data;
-+
-+ irq_set_chip_and_handler(irq, &data->chip, handle_simple_irq);
-+ irq_set_chip_data(irq, data);
-+ irq_set_noprobe(irq);
-+ irq_set_affinity(irq, cpumask_of(data->hart));
-+ return 0;
-+}
-+
-+static const struct irq_domain_ops riscv_irqdomain_ops = {
-+ .map = riscv_irqdomain_map,
-+ .xlate = irq_domain_xlate_onecell,
-+};
-+
-+/*
-+ * On RISC-V systems local interrupts are masked or unmasked by writing the SIE
-+ * (Supervisor Interrupt Enable) CSR. As CSRs can only be written on the local
-+ * hart, these functions can only be called on the hart that corresponds to the
-+ * IRQ chip. They are only called internally to this module, so they BUG_ON if
-+ * this condition is violated rather than attempting to handle the error by
-+ * forwarding to the target hart, as that's already expected to have been done.
-+ */
-+static void riscv_irq_mask(struct irq_data *d)
-+{
-+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
-+
-+ BUG_ON(smp_processor_id() != data->hart);
-+ csr_clear(sie, 1 << d->hwirq);
-+}
-+
-+static void riscv_irq_unmask(struct irq_data *d)
-+{
-+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
-+
-+ BUG_ON(smp_processor_id() != data->hart);
-+ csr_set(sie, 1 << d->hwirq);
-+}
-+
-+/* Callbacks for twiddling SIE on another hart. */
-+static void riscv_irq_enable_helper(void *d)
-+{
-+ riscv_irq_unmask(d);
-+}
-+
-+static void riscv_irq_disable_helper(void *d)
-+{
-+ riscv_irq_mask(d);
-+}
-+
-+static void riscv_remote_ctrl(unsigned int cpu, void (*fn)(void *d),
-+ struct irq_data *data)
-+{
-+ smp_call_function_single(cpu, fn, data, true);
-+}
-+
-+static void riscv_irq_enable(struct irq_data *d)
-+{
-+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
-+
-+ /*
-+ * It's only possible to write SIE on the current hart. This jumps
-+ * over to the target hart if it's not the current one. It's invalid
-+ * to write SIE on a hart that's not currently running.
-+ */
-+ if (data->hart == smp_processor_id())
-+ riscv_irq_unmask(d);
-+ else if (cpu_online(data->hart))
-+ riscv_remote_ctrl(data->hart, riscv_irq_enable_helper, d);
-+ else
-+ WARN_ON_ONCE(1);
-+}
-+
-+static void riscv_irq_disable(struct irq_data *d)
-+{
-+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
-+
-+ /*
-+ * It's only possible to write SIE on the current hart. This jumps
-+ * over to the target hart if it's not the current one. It's invalid
-+ * to write SIE on a hart that's not currently running.
-+ */
-+ if (data->hart == smp_processor_id())
-+ riscv_irq_mask(d);
-+ else if (cpu_online(data->hart))
-+ riscv_remote_ctrl(data->hart, riscv_irq_disable_helper, d);
-+ else
-+ WARN_ON_ONCE(1);
-+}
-+
-+static int __init riscv_intc_init(struct device_node *node,
-+ struct device_node *parent)
-+{
-+ struct riscv_irq_data *data;
-+ int hart;
-+
-+ hart = riscv_of_processor_hart(node->parent);
-+ if (hart < 0)
-+ return -EIO;
-+
-+ data = &per_cpu(riscv_irq_data, hart);
-+ snprintf(data->name, sizeof(data->name), "riscv,cpu_intc,%d", hart);
-+ data->hart = hart;
-+ data->chip.name = data->name;
-+ data->chip.irq_mask = riscv_irq_mask;
-+ data->chip.irq_unmask = riscv_irq_unmask;
-+ data->chip.irq_enable = riscv_irq_enable;
-+ data->chip.irq_disable = riscv_irq_disable;
-+ data->domain = irq_domain_add_linear(node, NR_RISCV_IRQS,
-+ &riscv_irqdomain_ops, data);
-+ if (!data->domain)
-+ goto error_add_linear;
-+
-+ set_handle_irq(&riscv_intc_irq);
-+ pr_info("%s: %lu local interrupts mapped\n", data->name, NR_RISCV_IRQS);
-+ return 0;
-+
-+error_add_linear:
-+ pr_warn("%s: unable to add IRQ domain\n", data->name);
-+ return -ENXIO;
-+}
-+
-+IRQCHIP_DECLARE(riscv, "riscv,cpu-intc", riscv_intc_init);
---
-2.1.4
-
+++ /dev/null
-From 1da2fd31207d1687f5edc6ba8f0402bbecc423f2 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@dabbelt.com>
-Date: Mon, 26 Jun 2017 22:07:50 -0700
-Subject: [PATCH 08/11] dt-bindings: interrupt-controller: RISC-V local
- interrupt controller docs
-
-This patch adds documentation on the RISC-V local interrupt controller,
-which is a per-hart interrupt controller that manages all interrupts
-entering a RISC-V hart. This interrupt controller is present on all
-RISC-V systems.
-
-Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
----
- .../interrupt-controller/riscv,cpu-intc.txt | 41 ++++++++++++++++++++++
- 1 file changed, 41 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt
-
-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 0000000..61900e2
---- /dev/null
-+++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt
-@@ -0,0 +1,41 @@
-+RISC-V Hart-Level Interrupt Controller (HLIC)
-+---------------------------------------------
-+
-+RISC-V cores include Control Status Registers (CSRs) which are local to each
-+hart and can be read or written by software. Some of these CSRs are used to
-+control local interrupts connected to the core. Every interrupt is ultimately
-+routed through a hart's HLIC before it interrupts that hart.
-+
-+The RISC-V supervisor ISA manual specifies three interrupt sources that are
-+attached to every HLIC: software interrupts, the timer interrupt, and external
-+interrupts. Software interrupts are used to send IPIs between cores. The
-+timer interrupt comes from an architecturally mandated real-time timer that is
-+controller via SBI calls and CSR reads. External interrupts connect all other
-+device interrupts to the HLIC, which are routed via the platform-level
-+interrupt controller (PLIC).
-+
-+All RISC-V systems that conform to the supervisor ISA specification are
-+required to have a HLIC with these three interrupt sources present. Since the
-+interrupt map is defined by the ISA it's not listed in the HLIC's device tree
-+entry, though external interrupt controllers (like the PLIC, for example) will
-+need to define how their interrupts map to the relevant HLICs.
-+
-+Required properties:
-+- compatible : "riscv,cpu-intc"
-+- #interrupt-cells : should be <1>
-+- interrupt-controller : Identifies the node as an interrupt controller
-+
-+Furthermore, this interrupt-controller MUST be embedded inside the cpu
-+definition of the hart whose CSRs control these local interrupts.
-+
-+An example device tree entry for a HLIC is show below.
-+
-+ cpu1: cpu@1 {
-+ compatible = "riscv";
-+ ...
-+ cpu1-intc: interrupt-controller {
-+ #interrupt-cells = <1>;
-+ compatible = "riscv,cpu-intc";
-+ interrupt-controller;
-+ };
-+ };
---
-2.1.4
-
+++ /dev/null
-From 8e3e7dfba04d314cfbade03237a3ec16f436b779 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@dabbelt.com>
-Date: Tue, 19 Jun 2018 18:10:08 +0200
-Subject: [PATCH 09/11] irqchip: New RISC-V PLIC Driver
-
-This patch adds a driver for the Platform Level Interrupt Controller
-(PLIC) specified as part of the RISC-V supervisor level ISA manual.
-The PLIC connects global interrupt sources to the local interrupt
-controller on each hart.
-
-Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
-[hch: various cleanups, fixed typos, added SPDX tag]
-Signed-off-by: Christoph Hellwig <hch@lst.de>
----
- drivers/irqchip/Kconfig | 13 ++
- drivers/irqchip/Makefile | 1 +
- drivers/irqchip/irq-riscv-plic.c | 295 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 309 insertions(+)
- create mode 100644 drivers/irqchip/irq-riscv-plic.c
-
-diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
-index 8460fdce..d1afac8 100644
---- a/drivers/irqchip/Kconfig
-+++ b/drivers/irqchip/Kconfig
-@@ -376,3 +376,16 @@ endmenu
- config RISCV_INTC
- def_bool y
- depends on RISCV
-+
-+config RISCV_PLIC
-+ bool "Platform-Level Interrupt Controller"
-+ depends on RISCV
-+ default y
-+ help
-+ This enables support for the PLIC chip found in standard RISC-V
-+ systems. The PLIC controls devices interrupts and connects them to
-+ each core's local interrupt controller. Aside from timer and
-+ software interrupts, all other interrupt sources (MSI, GPIO, etc)
-+ are subordinate to the PLIC.
-+
-+ If you don't know what to do here, say Y.
-diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
-index 74e333c..7954f4c 100644
---- a/drivers/irqchip/Makefile
-+++ b/drivers/irqchip/Makefile
-@@ -88,3 +88,4 @@ obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
- obj-$(CONFIG_NDS32) += irq-ativic32.o
- obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
- obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
-+obj-$(CONFIG_RISCV_PLIC) += irq-riscv-plic.o
-diff --git a/drivers/irqchip/irq-riscv-plic.c b/drivers/irqchip/irq-riscv-plic.c
-new file mode 100644
-index 0000000..7b80b73
---- /dev/null
-+++ b/drivers/irqchip/irq-riscv-plic.c
-@@ -0,0 +1,295 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2017 SiFive
-+ */
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/irq.h>
-+#include <linux/irqchip.h>
-+#include <linux/irqchip/chained_irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/platform_device.h>
-+#include <linux/spinlock.h>
-+
-+/*
-+ * From the RISC-V Priviledged Spec v1.10:
-+ *
-+ * Global interrupt sources are assigned small unsigned integer identifiers,
-+ * beginning at the value 1. An interrupt ID of 0 is reserved to mean "no
-+ * interrupt". Interrupt identifiers are also used to break ties when two or
-+ * more interrupt sources have the same assigned priority. Smaller values of
-+ * interrupt ID take precedence over larger values of interrupt ID.
-+ *
-+ * While the RISC-V supervisor spec doesn't define the maximum number of
-+ * devices supported by the PLIC, the largest number supported by devices
-+ * marked as 'riscv,plic0' (which is the only device type this driver supports,
-+ * and is the only extant PLIC as of now) is 1024. As mentioned above, device
-+ * 0 is defined to be non-existent so this device really only supports 1023
-+ * devices.
-+ */
-+#define MAX_DEVICES 1024
-+#define MAX_CONTEXTS 15872
-+
-+struct plic_handler {
-+ bool present;
-+ int contextid;
-+ struct plic_data *data;
-+};
-+
-+/*
-+ * PLIC devices are named like 'riscv,plic0,%llx', this is enough space to
-+ * store that name.
-+ */
-+#define PLIC_DATA_NAME_SIZE 30
-+
-+struct plic_data {
-+ struct irq_chip chip;
-+ struct irq_domain *domain;
-+ u32 ndev;
-+ void __iomem *reg;
-+ int handlers;
-+ struct plic_handler *handler;
-+ char name[PLIC_DATA_NAME_SIZE];
-+ spinlock_t lock;
-+};
-+
-+/*
-+ * Each interrupt source has a priority register associated with it.
-+ * We always hardwire it to one in Linux.
-+ */
-+static inline u32 __iomem *plic_priority(struct plic_data *data, int hwirq)
-+{
-+ return data->reg + hwirq * 0x04;
-+}
-+
-+/*
-+ * Each hart context has a vector of interrupt enable bits associated with it.
-+ * There is one bit for each interrupt source.
-+ */
-+static inline u32 __iomem *plic_enable_vector(struct plic_data *data,
-+ int contextid)
-+{
-+ return data->reg + (1 << 13) + contextid * 0x80;
-+}
-+
-+/*
-+ * Each hart context has a set of control registers associated with it. Right
-+ * now there's only two: a source priority threshold over which the hart will
-+ * take an interrupt, and a register to claim interrupts.
-+ */
-+#define CONTEXT_THRESHOLD 0
-+#define CONTEXT_CLAIM 4
-+
-+static inline u32 __iomem *plic_hart_data(struct plic_data *data,
-+ int contextid)
-+{
-+ return data->reg + (1 << 21) + contextid * 0x1000;
-+}
-+
-+/* Explicit interrupt masking. */
-+static void plic_disable(struct plic_data *data, int contextid, int hwirq)
-+{
-+ u32 __iomem *reg = plic_enable_vector(data, contextid) + (hwirq / 32);
-+ u32 mask = ~(1 << (hwirq % 32));
-+
-+ spin_lock(&data->lock);
-+ writel(readl(reg) & mask, reg);
-+ spin_unlock(&data->lock);
-+}
-+
-+static void plic_enable(struct plic_data *data, int contextid, int hwirq)
-+{
-+ u32 __iomem *reg = plic_enable_vector(data, contextid) + (hwirq / 32);
-+ u32 bit = 1 << (hwirq % 32);
-+
-+ spin_lock(&data->lock);
-+ writel(readl(reg) | bit, reg);
-+ spin_unlock(&data->lock);
-+}
-+
-+/*
-+ * There is no need to mask/unmask PLIC interrupts
-+ * They are "masked" by reading claim and "unmasked" when writing it back.
-+ */
-+static void plic_irq_mask(struct irq_data *d)
-+{
-+}
-+
-+static void plic_irq_unmask(struct irq_data *d)
-+{
-+}
-+
-+static void plic_irq_enable(struct irq_data *d)
-+{
-+ struct plic_data *data = irq_data_get_irq_chip_data(d);
-+ int i;
-+
-+ writel(1, plic_priority(data, d->hwirq));
-+ for (i = 0; i < data->handlers; ++i)
-+ if (data->handler[i].present)
-+ plic_enable(data, i, d->hwirq);
-+}
-+
-+static void plic_irq_disable(struct irq_data *d)
-+{
-+ struct plic_data *data = irq_data_get_irq_chip_data(d);
-+ int i;
-+
-+ writel(0, plic_priority(data, d->hwirq));
-+ for (i = 0; i < data->handlers; ++i)
-+ if (data->handler[i].present)
-+ plic_disable(data, i, d->hwirq);
-+}
-+
-+static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
-+ irq_hw_number_t hwirq)
-+{
-+ struct plic_data *data = d->host_data;
-+
-+ irq_set_chip_and_handler(irq, &data->chip, handle_simple_irq);
-+ irq_set_chip_data(irq, data);
-+ irq_set_noprobe(irq);
-+ return 0;
-+}
-+
-+static const struct irq_domain_ops plic_irqdomain_ops = {
-+ .map = plic_irqdomain_map,
-+ .xlate = irq_domain_xlate_onecell,
-+};
-+
-+/*
-+ * Handling an interrupt is a two-step process: first you claim the interrupt
-+ * by reading the claim register, then you complete the interrupt by writing
-+ * that source ID back to the same claim register. This automatically enables
-+ * and disables the interrupt, so there's nothing else to do.
-+ */
-+static void plic_chained_handle_irq(struct irq_desc *desc)
-+{
-+ struct plic_handler *handler = irq_desc_get_handler_data(desc);
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct irq_domain *domain = handler->data->domain;
-+ void __iomem *ph = plic_hart_data(handler->data, handler->contextid);
-+ u32 what;
-+
-+ chained_irq_enter(chip, desc);
-+ while ((what = readl(ph + CONTEXT_CLAIM))) {
-+ int irq = irq_find_mapping(domain, what);
-+
-+ if (irq > 0)
-+ generic_handle_irq(irq);
-+ else
-+ handle_bad_irq(desc);
-+ writel(what, ph + CONTEXT_CLAIM);
-+ }
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static int plic_init(struct device_node *node, struct device_node *parent)
-+{
-+ struct plic_data *data;
-+ struct resource resource;
-+ int i, ok = 0;
-+ int out = -1;
-+
-+ data = kzalloc(sizeof(*data), GFP_KERNEL);
-+ if (WARN_ON(!data))
-+ return -ENOMEM;
-+
-+ spin_lock_init(&data->lock);
-+
-+ data->reg = of_iomap(node, 0);
-+ if (WARN_ON(!data->reg)) {
-+ out = -EIO;
-+ goto free_data;
-+ }
-+
-+ of_property_read_u32(node, "riscv,ndev", &data->ndev);
-+ if (WARN_ON(!data->ndev)) {
-+ out = -EINVAL;
-+ goto free_reg;
-+ }
-+
-+ data->handlers = of_irq_count(node);
-+ if (WARN_ON(!data->handlers)) {
-+ out = -EINVAL;
-+ goto free_reg;
-+ }
-+
-+ data->handler =
-+ kcalloc(data->handlers, sizeof(*data->handler), GFP_KERNEL);
-+ if (WARN_ON(!data->handler)) {
-+ out = -ENOMEM;
-+ goto free_reg;
-+ }
-+
-+ data->domain = irq_domain_add_linear(node, data->ndev + 1,
-+ &plic_irqdomain_ops, data);
-+ if (WARN_ON(!data->domain)) {
-+ out = -ENOMEM;
-+ goto free_handler;
-+ }
-+
-+ of_address_to_resource(node, 0, &resource);
-+ snprintf(data->name, sizeof(data->name),
-+ "riscv,plic0,%llx", resource.start);
-+ data->chip.name = data->name;
-+ data->chip.irq_mask = plic_irq_mask;
-+ data->chip.irq_unmask = plic_irq_unmask;
-+ data->chip.irq_enable = plic_irq_enable;
-+ data->chip.irq_disable = plic_irq_disable;
-+
-+ for (i = 0; i < data->handlers; ++i) {
-+ struct plic_handler *handler = &data->handler[i];
-+ struct of_phandle_args parent;
-+ int parent_irq, hwirq;
-+
-+ handler->present = false;
-+
-+ if (of_irq_parse_one(node, i, &parent))
-+ continue;
-+ /* skip context holes */
-+ if (parent.args[0] == -1)
-+ continue;
-+
-+ /* skip any contexts that lead to inactive harts */
-+ if (of_device_is_compatible(parent.np, "riscv,cpu-intc") &&
-+ parent.np->parent &&
-+ riscv_of_processor_hart(parent.np->parent) < 0)
-+ continue;
-+
-+ parent_irq = irq_create_of_mapping(&parent);
-+ if (!parent_irq)
-+ continue;
-+
-+ handler->present = true;
-+ handler->contextid = i;
-+ handler->data = data;
-+ /* hwirq prio must be > this to trigger an interrupt */
-+ writel(0, plic_hart_data(data, i) + CONTEXT_THRESHOLD);
-+
-+ for (hwirq = 1; hwirq <= data->ndev; ++hwirq)
-+ plic_disable(data, i, hwirq);
-+ irq_set_chained_handler_and_data(parent_irq,
-+ plic_chained_handle_irq, handler);
-+ ++ok;
-+ }
-+
-+ pr_info("%s: mapped %d interrupts to %d/%d handlers\n",
-+ data->name, data->ndev, ok, data->handlers);
-+ WARN_ON(!ok);
-+ return 0;
-+
-+free_handler:
-+ kfree(data->handler);
-+free_reg:
-+ iounmap(data->reg);
-+free_data:
-+ kfree(data);
-+ return out;
-+}
-+
-+IRQCHIP_DECLARE(plic0, "riscv,plic0", plic_init);
---
-2.1.4
-
+++ /dev/null
-From 634a87822bc9939c99068e72612e3c5df40bff18 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@dabbelt.com>
-Date: Mon, 26 Jun 2017 22:09:07 -0700
-Subject: [PATCH 10/11] dt-bindings: interrupt-controller: RISC-V PLIC
- documentation
-
-This patch adds documentation for the platform-level interrupt
-controller (PLIC) found in all RISC-V systems. This interrupt
-controller routes interrupts from all the devices in the system to each
-hart-local interrupt controller.
-
-Note: the DTS bindings for the PLIC aren't set in stone yet, as we might
-want to change how we're specifying holes in the hart list.
-
-Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
----
- .../bindings/interrupt-controller/riscv,plic0.txt | 55 ++++++++++++++++++++++
- 1 file changed, 55 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt
-
-diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt b/Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt
-new file mode 100644
-index 0000000..99cd359
---- /dev/null
-+++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt
-@@ -0,0 +1,55 @@
-+RISC-V Platform-Level Interrupt Controller (PLIC)
-+-------------------------------------------------
-+
-+The RISC-V supervisor ISA specification allows for the presence of a
-+platform-level interrupt controller (PLIC). The PLIC connects all external
-+interrupts in the system to all hart contexts in the system, via the external
-+interrupt source in each hart's hart-local interrupt controller (HLIC). A hart
-+context is a privilege mode in a hardware execution thread. For example, in
-+an 4 core system with 2-way SMT, you have 8 harts and probably at least two
-+privilege modes per hart; machine mode and supervisor mode.
-+
-+Each interrupt can be enabled on per-context basis. Any context can claim
-+a pending enabled interrupt and then release it once it has been handled.
-+
-+Each interrupt has a configurable priority. Higher priority interrupts are
-+serviced firs. Each context can specify a priority threshold. Interrupts
-+with priority below this threshold will not cause the PLIC to raise its
-+interrupt line leading to the context.
-+
-+While the PLIC supports both edge-triggered and level-triggered interrupts,
-+interrupt handlers are oblivious to this distinction and therefor it is not
-+specific in the PLIC device-tree binding.
-+
-+While the RISC-V ISA doesn't specify a memory layout for the PLIC, the
-+"riscv,plic0" device is a concrete implementation of the PLIC that contains a
-+specific memory layout. More details about the memory layout of the
-+"riscv,plic0" device can be found as a comment in the device driver, or as part
-+of the SiFive U5 Coreplex Series Manual (page 22 of the PDF of version 1.0)
-+<https://www.sifive.com/documentation/coreplex/u5-coreplex-series-manual/>
-+
-+Required properties:
-+- compatible : "riscv,plic0"
-+- #address-cells : should be <0>
-+- #interrupt-cells : should be <1>
-+- interrupt-controller : Identifies the node as an interrupt controller
-+- reg : Should contain 1 register range (address and length)
-+- interrupts-extended : Specifies which contexts are connected to the PLIC,
-+ with "-1" specifying that a context is not present.
-+
-+Example:
-+
-+ plic: interrupt-controller@c000000 {
-+ #address-cells = <0>;
-+ #interrupt-cells = <1>;
-+ compatible = "riscv,plic0";
-+ interrupt-controller;
-+ interrupts-extended = <
-+ &cpu0-intc 11
-+ &cpu1-intc 11 &cpu1-intc 9
-+ &cpu2-intc 11 &cpu2-intc 9
-+ &cpu3-intc 11 &cpu3-intc 9
-+ &cpu4-intc 11 &cpu4-intc 9>;
-+ reg = <0xc000000 0x4000000>;
-+ riscv,ndev = <10>;
-+ };
---
-2.1.4
-
+++ /dev/null
-From 406087706427cdd610ce2dc3fbffa655064944d3 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@dabbelt.com>
-Date: Tue, 19 Jun 2018 17:36:28 +0200
-Subject: [PATCH 11/11] clocksource: new RISC-V SBI timer driver
-
-The RISC-V ISA defines a per-hart real-time clock and timer, which is
-present on all systems. The clock is accessed via the 'rdtime'
-pseudo-instruction (which reads a CSR), and the timer is set via an SBI
-call.
-
-Signed-off-by: Dmitriy Cherkasov <dmitriy@oss-tech.org>
-Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
-[hch: remove dead code, add SPDX tags, minor cleanups]
-Signed-off-by: Christoph Hellwig <hch@lst.de>
----
- arch/riscv/include/asm/timer.h | 7 +++
- arch/riscv/kernel/time.c | 9 +---
- drivers/clocksource/Kconfig | 10 ++++
- drivers/clocksource/Makefile | 1 +
- drivers/clocksource/riscv_timer.c | 97 +++++++++++++++++++++++++++++++++++++++
- 5 files changed, 116 insertions(+), 8 deletions(-)
- create mode 100644 arch/riscv/include/asm/timer.h
- create mode 100644 drivers/clocksource/riscv_timer.c
-
-diff --git a/arch/riscv/include/asm/timer.h b/arch/riscv/include/asm/timer.h
-new file mode 100644
-index 0000000..ae20dd9
---- /dev/null
-+++ b/arch/riscv/include/asm/timer.h
-@@ -0,0 +1,7 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+#ifndef _ASM_RISCV_TIMER_H
-+#define _ASM_RISCV_TIMER_H
-+
-+DECLARE_PER_CPU(struct clock_event_device, riscv_clock_event);
-+
-+#endif /* _ASM_RISCV_TIMER_H */
-diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
-index 2463fcc..bba28fc 100644
---- a/arch/riscv/kernel/time.c
-+++ b/arch/riscv/kernel/time.c
-@@ -16,19 +16,13 @@
- #include <linux/clockchips.h>
- #include <linux/delay.h>
-
--#ifdef CONFIG_RISCV_TIMER
--#include <linux/timer_riscv.h>
--#endif
--
- #include <asm/sbi.h>
-+#include <asm/timer.h>
-
- unsigned long riscv_timebase;
-
--DECLARE_PER_CPU(struct clock_event_device, riscv_clock_event);
--
- void riscv_timer_interrupt(void)
- {
--#ifdef CONFIG_RISCV_TIMER
- /*
- * FIXME: This needs to be cleaned up along with the rest of the IRQ
- * handling cleanup. See irq.c for more details.
-@@ -36,7 +30,6 @@ void riscv_timer_interrupt(void)
- struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event);
-
- evdev->event_handler(evdev);
--#endif
- }
-
- void __init init_clockevent(void)
-diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
-index dec0dd8..a57083e 100644
---- a/drivers/clocksource/Kconfig
-+++ b/drivers/clocksource/Kconfig
-@@ -609,4 +609,14 @@ config ATCPIT100_TIMER
- help
- This option enables support for the Andestech ATCPIT100 timers.
-
-+config RISCV_TIMER
-+ bool "Timer for the RISC-V platform"
-+ depends on RISCV || COMPILE_TEST
-+ select TIMER_PROBE
-+ select TIMER_OF
-+ help
-+ This enables the per-hart timer built into all RISC-V systems, which
-+ is accessed via both the SBI and the rdcycle instruction. This is
-+ required for all RISC-V systems.
-+
- endmenu
-diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
-index 00caf37..ded31f7 100644
---- a/drivers/clocksource/Makefile
-+++ b/drivers/clocksource/Makefile
-@@ -78,3 +78,4 @@ obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
- obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
- obj-$(CONFIG_X86_NUMACHIP) += numachip.o
- obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
-+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 0000000..48196b2
---- /dev/null
-+++ b/drivers/clocksource/riscv_timer.c
-@@ -0,0 +1,97 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2012 Regents of the University of California
-+ * Copyright (C) 2017 SiFive
-+ */
-+#include <linux/clocksource.h>
-+#include <linux/clockchips.h>
-+#include <linux/delay.h>
-+#include <asm/sbi.h>
-+#include <asm/timer.h>
-+
-+#define MINDELTA 100
-+#define MAXDELTA 0x7fffffff
-+
-+/*
-+ * All RISC-V systems have a timer attached to every hart. These timers can be
-+ * read by the 'rdcycle' pseudo instruction, and can use the SBI to setup
-+ * events. In order to abstract the architecture-specific timer reading and
-+ * setting functions away from the clock event insertion code, we provide
-+ * function pointers to the clockevent subsystem that perform two basic
-+ * operations: rdtime() reads the timer on the current CPU, and
-+ * next_event(delta) sets the next timer event to 'delta' cycles in the future.
-+ * As the timers are inherently a per-cpu resource, these callbacks perform
-+ * operations on the current hart. There is guaranteed to be exactly one timer
-+ * per hart on all RISC-V systems.
-+ */
-+//DECLARE_PER_CPU(struct clocksource, riscv_clocksource);
-+
-+static int next_event(unsigned long delta, struct clock_event_device *ce)
-+{
-+ /*
-+ * time_init() allocates a timer for each CPU. Since we're writing the
-+ * timer comparison register here we can't allow the timers to cross
-+ * harts.
-+ */
-+ BUG_ON(ce != this_cpu_ptr(&riscv_clock_event));
-+ sbi_set_timer(get_cycles64() + delta);
-+ return 0;
-+}
-+
-+DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
-+ .name = "riscv_timer_clockevent",
-+ .features = CLOCK_EVT_FEAT_ONESHOT,
-+ .rating = 100,
-+ .set_next_event = next_event,
-+};
-+
-+/*
-+ * It is guarnteed that all the timers across all the harts are synchronized
-+ * within one tick of each other, so while this could technically go
-+ * backwards when hopping between CPUs, practically it won't happen.
-+ */
-+static unsigned long long rdtime(struct clocksource *cs)
-+{
-+ return get_cycles64();
-+}
-+
-+DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
-+ .name = "riscv_clocksource",
-+ .rating = 300,
-+ .mask = CLOCKSOURCE_MASK(BITS_PER_LONG),
-+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-+ .read = rdtime,
-+};
-+
-+static int hart_of_timer(struct device_node *dev)
-+{
-+ u32 hart;
-+
-+ if (!dev)
-+ return -1;
-+ if (!of_device_is_compatible(dev, "riscv"))
-+ return -1;
-+ if (of_property_read_u32(dev, "reg", &hart))
-+ return -1;
-+
-+ return hart;
-+}
-+
-+static int timer_riscv_init_dt(struct device_node *n)
-+{
-+ int cpu_id = hart_of_timer(n);
-+ struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu_id);
-+ struct clocksource *cs = per_cpu_ptr(&riscv_clocksource, cpu_id);
-+
-+ if (cpu_id == smp_processor_id()) {
-+ clocksource_register_hz(cs, riscv_timebase);
-+
-+ ce->cpumask = cpumask_of(cpu_id);
-+ clockevents_config_and_register(ce, riscv_timebase,
-+ MINDELTA, MAXDELTA);
-+ }
-+
-+ return 0;
-+}
-+
-+TIMER_OF_DECLARE(riscv_timer, "riscv", timer_riscv_init_dt);
---
-2.1.4
-