From: Zoltan HERPAI Date: Mon, 15 Oct 2018 14:13:43 +0000 (+0200) Subject: riscv64: drop old patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=d59e7de08987c495aad25e32e401eb7f75db3df3;p=openwrt%2Fstaging%2Fwigyori.git riscv64: drop old patches Signed-off-by: Zoltan HERPAI --- diff --git a/target/linux/riscv64/patches/0001-base-fix-order-of-OF-initialization.patch b/target/linux/riscv64/patches/0001-base-fix-order-of-OF-initialization.patch deleted file mode 100644 index 024b51ef2c..0000000000 --- a/target/linux/riscv64/patches/0001-base-fix-order-of-OF-initialization.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 6de0b16fb7a2cea47e9a75534b4ec59f36998616 Mon Sep 17 00:00:00 2001 -From: "Wesley W. Terpstra" -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 ---- - 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 - diff --git a/target/linux/riscv64/patches/0002-dt-bindings-Correct-RISC-V-s-timebase-frequency.patch b/target/linux/riscv64/patches/0002-dt-bindings-Correct-RISC-V-s-timebase-frequency.patch deleted file mode 100644 index 032738c369..0000000000 --- a/target/linux/riscv64/patches/0002-dt-bindings-Correct-RISC-V-s-timebase-frequency.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 7866ef38a00cd390596a67e19d23d8ffd6058732 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 -Signed-off-by: Palmer Dabbelt ---- - 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 - diff --git a/target/linux/riscv64/patches/0003-dt-bindings-Add-an-enable-method-to-RISC-V.patch b/target/linux/riscv64/patches/0003-dt-bindings-Add-an-enable-method-to-RISC-V.patch deleted file mode 100644 index 8c6e297352..0000000000 --- a/target/linux/riscv64/patches/0003-dt-bindings-Add-an-enable-method-to-RISC-V.patch +++ /dev/null @@ -1,44 +0,0 @@ -From fd7aef2aae3b2d250f0c04224b3c85646c2e9c56 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 -Signed-off-by: Palmer Dabbelt ---- - 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: - 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: -+ 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 - diff --git a/target/linux/riscv64/patches/0004-RISC-V-Add-early-printk-support-via-the-SBI-console.patch b/target/linux/riscv64/patches/0004-RISC-V-Add-early-printk-support-via-the-SBI-console.patch deleted file mode 100644 index 5bffed5e19..0000000000 --- a/target/linux/riscv64/patches/0004-RISC-V-Add-early-printk-support-via-the-SBI-console.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 577949829e04d23f58ef4ad5c448689c2ed70a49 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 ---- - 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 - #include - -+#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 - diff --git a/target/linux/riscv64/patches/0005-RISC-V-simplify-software-interrupt-IPI-code.patch b/target/linux/riscv64/patches/0005-RISC-V-simplify-software-interrupt-IPI-code.patch deleted file mode 100644 index 4c5fce0561..0000000000 --- a/target/linux/riscv64/patches/0005-RISC-V-simplify-software-interrupt-IPI-code.patch +++ /dev/null @@ -1,74 +0,0 @@ -From b3b48cbc8a19fc3e3abd3ae9b5d271c12a1a0b87 Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -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 ---- - 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 - diff --git a/target/linux/riscv64/patches/0006-RISC-V-remove-INTERRUPT_CAUSE_-defines-from-asm-irq..patch b/target/linux/riscv64/patches/0006-RISC-V-remove-INTERRUPT_CAUSE_-defines-from-asm-irq..patch deleted file mode 100644 index 1f22061d18..0000000000 --- a/target/linux/riscv64/patches/0006-RISC-V-remove-INTERRUPT_CAUSE_-defines-from-asm-irq..patch +++ /dev/null @@ -1,31 +0,0 @@ -From 422e21b7ab41a21d7342b01fea7d1c6b91d986d8 Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -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 ---- - 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 --- -2.1.4 - diff --git a/target/linux/riscv64/patches/0007-irqchip-RISC-V-Local-Interrupt-Controller-Driver.patch b/target/linux/riscv64/patches/0007-irqchip-RISC-V-Local-Interrupt-Controller-Driver.patch deleted file mode 100644 index 107b6b7ee9..0000000000 --- a/target/linux/riscv64/patches/0007-irqchip-RISC-V-Local-Interrupt-Controller-Driver.patch +++ /dev/null @@ -1,249 +0,0 @@ -From e07e6be7ef8b44155aebac95dde19a39498ebd00 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 -[hch: Kconfig simplifications, various cleanups] -Signed-off-by: Christoph Hellwig ---- - 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 - diff --git a/target/linux/riscv64/patches/0008-dt-bindings-interrupt-controller-RISC-V-local-interr.patch b/target/linux/riscv64/patches/0008-dt-bindings-interrupt-controller-RISC-V-local-interr.patch deleted file mode 100644 index 34379e3edb..0000000000 --- a/target/linux/riscv64/patches/0008-dt-bindings-interrupt-controller-RISC-V-local-interr.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 1da2fd31207d1687f5edc6ba8f0402bbecc423f2 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 ---- - .../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 - diff --git a/target/linux/riscv64/patches/0009-irqchip-New-RISC-V-PLIC-Driver.patch b/target/linux/riscv64/patches/0009-irqchip-New-RISC-V-PLIC-Driver.patch deleted file mode 100644 index 478f987e00..0000000000 --- a/target/linux/riscv64/patches/0009-irqchip-New-RISC-V-PLIC-Driver.patch +++ /dev/null @@ -1,354 +0,0 @@ -From 8e3e7dfba04d314cfbade03237a3ec16f436b779 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 -[hch: various cleanups, fixed typos, added SPDX tag] -Signed-off-by: Christoph Hellwig ---- - 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * 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 - diff --git a/target/linux/riscv64/patches/0010-dt-bindings-interrupt-controller-RISC-V-PLIC-documen.patch b/target/linux/riscv64/patches/0010-dt-bindings-interrupt-controller-RISC-V-PLIC-documen.patch deleted file mode 100644 index 6a05e9d336..0000000000 --- a/target/linux/riscv64/patches/0010-dt-bindings-interrupt-controller-RISC-V-PLIC-documen.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 634a87822bc9939c99068e72612e3c5df40bff18 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 ---- - .../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) -+ -+ -+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 - diff --git a/target/linux/riscv64/patches/0011-clocksource-new-RISC-V-SBI-timer-driver.patch b/target/linux/riscv64/patches/0011-clocksource-new-RISC-V-SBI-timer-driver.patch deleted file mode 100644 index bcc89d4e35..0000000000 --- a/target/linux/riscv64/patches/0011-clocksource-new-RISC-V-SBI-timer-driver.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 406087706427cdd610ce2dc3fbffa655064944d3 Mon Sep 17 00:00:00 2001 -From: Palmer Dabbelt -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 -Signed-off-by: Palmer Dabbelt -[hch: remove dead code, add SPDX tags, minor cleanups] -Signed-off-by: Christoph Hellwig ---- - 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 - #include - --#ifdef CONFIG_RISCV_TIMER --#include --#endif -- - #include -+#include - - 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 -+#include -+#include -+#include -+#include -+ -+#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 -