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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'riscv-for-linus-5.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

Pull RISC-V fixes from Palmer Dabbelt:

- The CLINT driver has been split in two: one to handle the M-mode
CLINT (memory mapped and used on NOMMU systems) and one to handle the
S-mode CLINT (via SBI).

- The addition of SiFive's drivers to rv32_defconfig

* tag 'riscv-for-linus-5.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
riscv: Add SiFive drivers to rv32_defconfig
dt-bindings: timer: Add CLINT bindings
RISC-V: Remove CLINT related code from timer and arch
clocksource/drivers: Add CLINT timer driver
RISC-V: Add mechanism to provide custom IPI operations

+376 -153
+60
Documentation/devicetree/bindings/timer/sifive,clint.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/timer/sifive,clint.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: SiFive Core Local Interruptor 8 + 9 + maintainers: 10 + - Palmer Dabbelt <palmer@dabbelt.com> 11 + - Anup Patel <anup.patel@wdc.com> 12 + 13 + description: 14 + SiFive (and other RISC-V) SOCs include an implementation of the SiFive 15 + Core Local Interruptor (CLINT) for M-mode timer and M-mode inter-processor 16 + interrupts. It directly connects to the timer and inter-processor interrupt 17 + lines of various HARTs (or CPUs) so RISC-V per-HART (or per-CPU) local 18 + interrupt controller is the parent interrupt controller for CLINT device. 19 + The clock frequency of CLINT is specified via "timebase-frequency" DT 20 + property of "/cpus" DT node. The "timebase-frequency" DT property is 21 + described in Documentation/devicetree/bindings/riscv/cpus.yaml 22 + 23 + properties: 24 + compatible: 25 + items: 26 + - const: sifive,fu540-c000-clint 27 + - const: sifive,clint0 28 + 29 + description: 30 + Should be "sifive,<chip>-clint" and "sifive,clint<version>". 31 + Supported compatible strings are - 32 + "sifive,fu540-c000-clint" for the SiFive CLINT v0 as integrated 33 + onto the SiFive FU540 chip, and "sifive,clint0" for the SiFive 34 + CLINT v0 IP block with no chip integration tweaks. 35 + Please refer to sifive-blocks-ip-versioning.txt for details 36 + 37 + reg: 38 + maxItems: 1 39 + 40 + interrupts-extended: 41 + minItems: 1 42 + 43 + additionalProperties: false 44 + 45 + required: 46 + - compatible 47 + - reg 48 + - interrupts-extended 49 + 50 + examples: 51 + - | 52 + timer@2000000 { 53 + compatible = "sifive,fu540-c000-clint", "sifive,clint0"; 54 + interrupts-extended = <&cpu1intc 3 &cpu1intc 7 55 + &cpu2intc 3 &cpu2intc 7 56 + &cpu3intc 3 &cpu3intc 7 57 + &cpu4intc 3 &cpu4intc 7>; 58 + reg = <0x2000000 0x10000>; 59 + }; 60 + ...
+1 -1
arch/riscv/Kconfig
··· 81 81 select PCI_DOMAINS_GENERIC if PCI 82 82 select PCI_MSI if PCI 83 83 select RISCV_INTC 84 - select RISCV_TIMER 84 + select RISCV_TIMER if RISCV_SBI 85 85 select SPARSEMEM_STATIC if 32BIT 86 86 select SPARSE_IRQ 87 87 select SYSCTL_EXCEPTION_TRACE
+2
arch/riscv/Kconfig.socs
··· 12 12 13 13 config SOC_VIRT 14 14 bool "QEMU Virt Machine" 15 + select CLINT_TIMER if RISCV_M_MODE 15 16 select POWER_RESET 16 17 select POWER_RESET_SYSCON 17 18 select POWER_RESET_SYSCON_POWEROFF ··· 25 24 config SOC_KENDRYTE 26 25 bool "Kendryte K210 SoC" 27 26 depends on !MMU 27 + select CLINT_TIMER if RISCV_M_MODE 28 28 select SERIAL_SIFIVE if TTY 29 29 select SERIAL_SIFIVE_CONSOLE if TTY 30 30 select SIFIVE_PLIC
+2 -5
arch/riscv/configs/nommu_virt_defconfig
··· 26 26 CONFIG_SLOB=y 27 27 # CONFIG_SLAB_MERGE_DEFAULT is not set 28 28 # CONFIG_MMU is not set 29 + CONFIG_SOC_VIRT=y 29 30 CONFIG_MAXPHYSMEM_2GB=y 30 31 CONFIG_SMP=y 31 32 CONFIG_CMDLINE="root=/dev/vda rw earlycon=uart8250,mmio,0x10000000,115200n8 console=ttyS0" ··· 50 49 # CONFIG_SERIO is not set 51 50 # CONFIG_LEGACY_PTYS is not set 52 51 # CONFIG_LDISC_AUTOLOAD is not set 53 - # CONFIG_DEVMEM is not set 54 52 CONFIG_SERIAL_8250=y 55 53 # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set 56 54 CONFIG_SERIAL_8250_CONSOLE=y ··· 57 57 CONFIG_SERIAL_8250_RUNTIME_UARTS=1 58 58 CONFIG_SERIAL_OF_PLATFORM=y 59 59 # CONFIG_HW_RANDOM is not set 60 + # CONFIG_DEVMEM is not set 60 61 # CONFIG_HWMON is not set 61 - # CONFIG_LCD_CLASS_DEVICE is not set 62 - # CONFIG_BACKLIGHT_CLASS_DEVICE is not set 63 62 # CONFIG_VGA_CONSOLE is not set 64 63 # CONFIG_HID is not set 65 64 # CONFIG_USB_SUPPORT is not set 66 65 CONFIG_VIRTIO_MMIO=y 67 66 CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y 68 - CONFIG_SIFIVE_PLIC=y 69 - # CONFIG_VALIDATE_FS_PARSER is not set 70 67 CONFIG_EXT2_FS=y 71 68 # CONFIG_DNOTIFY is not set 72 69 # CONFIG_INOTIFY_USER is not set
+5
arch/riscv/configs/rv32_defconfig
··· 14 14 CONFIG_BLK_DEV_INITRD=y 15 15 CONFIG_EXPERT=y 16 16 CONFIG_BPF_SYSCALL=y 17 + CONFIG_SOC_SIFIVE=y 17 18 CONFIG_SOC_VIRT=y 18 19 CONFIG_ARCH_RV32I=y 19 20 CONFIG_SMP=y ··· 63 62 CONFIG_VIRTIO_CONSOLE=y 64 63 CONFIG_HW_RANDOM=y 65 64 CONFIG_HW_RANDOM_VIRTIO=y 65 + CONFIG_SPI=y 66 + CONFIG_SPI_SIFIVE=y 66 67 # CONFIG_PTP_1588_CLOCK is not set 67 68 CONFIG_POWER_RESET=y 68 69 CONFIG_DRM=y ··· 80 77 CONFIG_USB_OHCI_HCD_PLATFORM=y 81 78 CONFIG_USB_STORAGE=y 82 79 CONFIG_USB_UAS=y 80 + CONFIG_MMC=y 81 + CONFIG_MMC_SPI=y 83 82 CONFIG_RTC_CLASS=y 84 83 CONFIG_VIRTIO_PCI=y 85 84 CONFIG_VIRTIO_BALLOON=y
-39
arch/riscv/include/asm/clint.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef _ASM_RISCV_CLINT_H 3 - #define _ASM_RISCV_CLINT_H 1 4 - 5 - #include <linux/io.h> 6 - #include <linux/smp.h> 7 - 8 - #ifdef CONFIG_RISCV_M_MODE 9 - extern u32 __iomem *clint_ipi_base; 10 - 11 - void clint_init_boot_cpu(void); 12 - 13 - static inline void clint_send_ipi_single(unsigned long hartid) 14 - { 15 - writel(1, clint_ipi_base + hartid); 16 - } 17 - 18 - static inline void clint_send_ipi_mask(const struct cpumask *mask) 19 - { 20 - int cpu; 21 - 22 - for_each_cpu(cpu, mask) 23 - clint_send_ipi_single(cpuid_to_hartid_map(cpu)); 24 - } 25 - 26 - static inline void clint_clear_ipi(unsigned long hartid) 27 - { 28 - writel(0, clint_ipi_base + hartid); 29 - } 30 - #else /* CONFIG_RISCV_M_MODE */ 31 - #define clint_init_boot_cpu() do { } while (0) 32 - 33 - /* stubs to for code is only reachable under IS_ENABLED(CONFIG_RISCV_M_MODE): */ 34 - void clint_send_ipi_single(unsigned long hartid); 35 - void clint_send_ipi_mask(const struct cpumask *hartid_mask); 36 - void clint_clear_ipi(unsigned long hartid); 37 - #endif /* CONFIG_RISCV_M_MODE */ 38 - 39 - #endif /* _ASM_RISCV_CLINT_H */
+19
arch/riscv/include/asm/smp.h
··· 15 15 struct seq_file; 16 16 extern unsigned long boot_cpu_hartid; 17 17 18 + struct riscv_ipi_ops { 19 + void (*ipi_inject)(const struct cpumask *target); 20 + void (*ipi_clear)(void); 21 + }; 22 + 18 23 #ifdef CONFIG_SMP 19 24 /* 20 25 * Mapping between linux logical cpu index and hartid. ··· 44 39 45 40 int riscv_hartid_to_cpuid(int hartid); 46 41 void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out); 42 + 43 + /* Set custom IPI operations */ 44 + void riscv_set_ipi_ops(struct riscv_ipi_ops *ops); 45 + 46 + /* Clear IPI for current CPU */ 47 + void riscv_clear_ipi(void); 47 48 48 49 /* Secondary hart entry */ 49 50 asmlinkage void smp_callin(void); ··· 90 79 { 91 80 cpumask_clear(out); 92 81 cpumask_set_cpu(boot_cpu_hartid, out); 82 + } 83 + 84 + static inline void riscv_set_ipi_ops(struct riscv_ipi_ops *ops) 85 + { 86 + } 87 + 88 + static inline void riscv_clear_ipi(void) 89 + { 93 90 } 94 91 95 92 #endif /* CONFIG_SMP */
+7 -21
arch/riscv/include/asm/timex.h
··· 7 7 #define _ASM_RISCV_TIMEX_H 8 8 9 9 #include <asm/csr.h> 10 - #include <asm/mmio.h> 11 10 12 11 typedef unsigned long cycles_t; 13 12 14 - extern u64 __iomem *riscv_time_val; 15 - extern u64 __iomem *riscv_time_cmp; 16 - 17 - #ifdef CONFIG_64BIT 18 - #define mmio_get_cycles() readq_relaxed(riscv_time_val) 19 - #else 20 - #define mmio_get_cycles() readl_relaxed(riscv_time_val) 21 - #define mmio_get_cycles_hi() readl_relaxed(((u32 *)riscv_time_val) + 1) 22 - #endif 23 - 24 13 static inline cycles_t get_cycles(void) 25 14 { 26 - if (IS_ENABLED(CONFIG_RISCV_SBI)) 27 - return csr_read(CSR_TIME); 28 - return mmio_get_cycles(); 15 + return csr_read(CSR_TIME); 29 16 } 30 17 #define get_cycles get_cycles 18 + 19 + static inline u32 get_cycles_hi(void) 20 + { 21 + return csr_read(CSR_TIMEH); 22 + } 23 + #define get_cycles_hi get_cycles_hi 31 24 32 25 #ifdef CONFIG_64BIT 33 26 static inline u64 get_cycles64(void) ··· 28 35 return get_cycles(); 29 36 } 30 37 #else /* CONFIG_64BIT */ 31 - static inline u32 get_cycles_hi(void) 32 - { 33 - if (IS_ENABLED(CONFIG_RISCV_SBI)) 34 - return csr_read(CSR_TIMEH); 35 - return mmio_get_cycles_hi(); 36 - } 37 - 38 38 static inline u64 get_cycles64(void) 39 39 { 40 40 u32 hi, lo;
+1 -1
arch/riscv/kernel/Makefile
··· 31 31 obj-y += patch.o 32 32 obj-$(CONFIG_MMU) += vdso.o vdso/ 33 33 34 - obj-$(CONFIG_RISCV_M_MODE) += clint.o traps_misaligned.o 34 + obj-$(CONFIG_RISCV_M_MODE) += traps_misaligned.o 35 35 obj-$(CONFIG_FPU) += fpu.o 36 36 obj-$(CONFIG_SMP) += smpboot.o 37 37 obj-$(CONFIG_SMP) += smp.o
-44
arch/riscv/kernel/clint.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (c) 2019 Christoph Hellwig. 4 - */ 5 - 6 - #include <linux/io.h> 7 - #include <linux/of_address.h> 8 - #include <linux/types.h> 9 - #include <asm/clint.h> 10 - #include <asm/csr.h> 11 - #include <asm/timex.h> 12 - #include <asm/smp.h> 13 - 14 - /* 15 - * This is the layout used by the SiFive clint, which is also shared by the qemu 16 - * virt platform, and the Kendryte KD210 at least. 17 - */ 18 - #define CLINT_IPI_OFF 0 19 - #define CLINT_TIME_CMP_OFF 0x4000 20 - #define CLINT_TIME_VAL_OFF 0xbff8 21 - 22 - u32 __iomem *clint_ipi_base; 23 - 24 - void clint_init_boot_cpu(void) 25 - { 26 - struct device_node *np; 27 - void __iomem *base; 28 - 29 - np = of_find_compatible_node(NULL, NULL, "riscv,clint0"); 30 - if (!np) { 31 - panic("clint not found"); 32 - return; 33 - } 34 - 35 - base = of_iomap(np, 0); 36 - if (!base) 37 - panic("could not map CLINT"); 38 - 39 - clint_ipi_base = base + CLINT_IPI_OFF; 40 - riscv_time_cmp = base + CLINT_TIME_CMP_OFF; 41 - riscv_time_val = base + CLINT_TIME_VAL_OFF; 42 - 43 - clint_clear_ipi(boot_cpu_hartid); 44 - }
+14
arch/riscv/kernel/sbi.c
··· 547 547 return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION); 548 548 } 549 549 550 + static void sbi_send_cpumask_ipi(const struct cpumask *target) 551 + { 552 + struct cpumask hartid_mask; 553 + 554 + riscv_cpuid_to_hartid_mask(target, &hartid_mask); 555 + 556 + sbi_send_ipi(cpumask_bits(&hartid_mask)); 557 + } 558 + 559 + static struct riscv_ipi_ops sbi_ipi_ops = { 560 + .ipi_inject = sbi_send_cpumask_ipi 561 + }; 550 562 551 563 int __init sbi_init(void) 552 564 { ··· 598 586 __sbi_send_ipi = __sbi_send_ipi_v01; 599 587 __sbi_rfence = __sbi_rfence_v01; 600 588 } 589 + 590 + riscv_set_ipi_ops(&sbi_ipi_ops); 601 591 602 592 return 0; 603 593 }
-2
arch/riscv/kernel/setup.c
··· 18 18 #include <linux/swiotlb.h> 19 19 #include <linux/smp.h> 20 20 21 - #include <asm/clint.h> 22 21 #include <asm/cpu_ops.h> 23 22 #include <asm/setup.h> 24 23 #include <asm/sections.h> ··· 78 79 #else 79 80 unflatten_device_tree(); 80 81 #endif 81 - clint_init_boot_cpu(); 82 82 83 83 #ifdef CONFIG_SWIOTLB 84 84 swiotlb_init(1);
+24 -20
arch/riscv/kernel/smp.c
··· 18 18 #include <linux/delay.h> 19 19 #include <linux/irq_work.h> 20 20 21 - #include <asm/clint.h> 22 21 #include <asm/sbi.h> 23 22 #include <asm/tlbflush.h> 24 23 #include <asm/cacheflush.h> ··· 85 86 wait_for_interrupt(); 86 87 } 87 88 89 + static struct riscv_ipi_ops *ipi_ops; 90 + 91 + void riscv_set_ipi_ops(struct riscv_ipi_ops *ops) 92 + { 93 + ipi_ops = ops; 94 + } 95 + EXPORT_SYMBOL_GPL(riscv_set_ipi_ops); 96 + 97 + void riscv_clear_ipi(void) 98 + { 99 + if (ipi_ops && ipi_ops->ipi_clear) 100 + ipi_ops->ipi_clear(); 101 + 102 + csr_clear(CSR_IP, IE_SIE); 103 + } 104 + EXPORT_SYMBOL_GPL(riscv_clear_ipi); 105 + 88 106 static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op) 89 107 { 90 - struct cpumask hartid_mask; 91 108 int cpu; 92 109 93 110 smp_mb__before_atomic(); ··· 111 96 set_bit(op, &ipi_data[cpu].bits); 112 97 smp_mb__after_atomic(); 113 98 114 - riscv_cpuid_to_hartid_mask(mask, &hartid_mask); 115 - if (IS_ENABLED(CONFIG_RISCV_SBI)) 116 - sbi_send_ipi(cpumask_bits(&hartid_mask)); 99 + if (ipi_ops && ipi_ops->ipi_inject) 100 + ipi_ops->ipi_inject(mask); 117 101 else 118 - clint_send_ipi_mask(mask); 102 + pr_warn("SMP: IPI inject method not available\n"); 119 103 } 120 104 121 105 static void send_ipi_single(int cpu, enum ipi_message_type op) 122 106 { 123 - int hartid = cpuid_to_hartid_map(cpu); 124 - 125 107 smp_mb__before_atomic(); 126 108 set_bit(op, &ipi_data[cpu].bits); 127 109 smp_mb__after_atomic(); 128 110 129 - if (IS_ENABLED(CONFIG_RISCV_SBI)) 130 - sbi_send_ipi(cpumask_bits(cpumask_of(hartid))); 111 + if (ipi_ops && ipi_ops->ipi_inject) 112 + ipi_ops->ipi_inject(cpumask_of(cpu)); 131 113 else 132 - clint_send_ipi_single(hartid); 133 - } 134 - 135 - static inline void clear_ipi(void) 136 - { 137 - if (IS_ENABLED(CONFIG_RISCV_SBI)) 138 - csr_clear(CSR_IP, IE_SIE); 139 - else 140 - clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id())); 114 + pr_warn("SMP: IPI inject method not available\n"); 141 115 } 142 116 143 117 #ifdef CONFIG_IRQ_WORK ··· 144 140 145 141 irq_enter(); 146 142 147 - clear_ipi(); 143 + riscv_clear_ipi(); 148 144 149 145 while (true) { 150 146 unsigned long ops;
+1 -3
arch/riscv/kernel/smpboot.c
··· 24 24 #include <linux/of.h> 25 25 #include <linux/sched/task_stack.h> 26 26 #include <linux/sched/mm.h> 27 - #include <asm/clint.h> 28 27 #include <asm/cpu_ops.h> 29 28 #include <asm/irq.h> 30 29 #include <asm/mmu_context.h> ··· 146 147 struct mm_struct *mm = &init_mm; 147 148 unsigned int curr_cpuid = smp_processor_id(); 148 149 149 - if (!IS_ENABLED(CONFIG_RISCV_SBI)) 150 - clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id())); 150 + riscv_clear_ipi(); 151 151 152 152 /* All kernel threads share the same mm context. */ 153 153 mmgrab(mm);
+10 -2
drivers/clocksource/Kconfig
··· 653 653 This option enables support for the Andestech ATCPIT100 timers. 654 654 655 655 config RISCV_TIMER 656 - bool "Timer for the RISC-V platform" 656 + bool "Timer for the RISC-V platform" if COMPILE_TEST 657 657 depends on GENERIC_SCHED_CLOCK && RISCV 658 - default y 659 658 select TIMER_PROBE 660 659 select TIMER_OF 661 660 help 662 661 This enables the per-hart timer built into all RISC-V systems, which 663 662 is accessed via both the SBI and the rdcycle instruction. This is 664 663 required for all RISC-V systems. 664 + 665 + config CLINT_TIMER 666 + bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST 667 + depends on GENERIC_SCHED_CLOCK && RISCV 668 + select TIMER_PROBE 669 + select TIMER_OF 670 + help 671 + This option enables the CLINT timer for RISC-V systems. The CLINT 672 + driver is usually used for NoMMU RISC-V systems. 665 673 666 674 config CSKY_MP_TIMER 667 675 bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
+1
drivers/clocksource/Makefile
··· 89 89 obj-$(CONFIG_X86_NUMACHIP) += numachip.o 90 90 obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o 91 91 obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o 92 + obj-$(CONFIG_CLINT_TIMER) += timer-clint.o 92 93 obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o 93 94 obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o 94 95 obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
+226
drivers/clocksource/timer-clint.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020 Western Digital Corporation or its affiliates. 4 + * 5 + * Most of the M-mode (i.e. NoMMU) RISC-V systems usually have a 6 + * CLINT MMIO timer device. 7 + */ 8 + 9 + #define pr_fmt(fmt) "clint: " fmt 10 + #include <linux/bitops.h> 11 + #include <linux/clocksource.h> 12 + #include <linux/clockchips.h> 13 + #include <linux/cpu.h> 14 + #include <linux/delay.h> 15 + #include <linux/module.h> 16 + #include <linux/of_address.h> 17 + #include <linux/sched_clock.h> 18 + #include <linux/io-64-nonatomic-lo-hi.h> 19 + #include <linux/interrupt.h> 20 + #include <linux/of_irq.h> 21 + #include <linux/smp.h> 22 + 23 + #define CLINT_IPI_OFF 0 24 + #define CLINT_TIMER_CMP_OFF 0x4000 25 + #define CLINT_TIMER_VAL_OFF 0xbff8 26 + 27 + /* CLINT manages IPI and Timer for RISC-V M-mode */ 28 + static u32 __iomem *clint_ipi_base; 29 + static u64 __iomem *clint_timer_cmp; 30 + static u64 __iomem *clint_timer_val; 31 + static unsigned long clint_timer_freq; 32 + static unsigned int clint_timer_irq; 33 + 34 + static void clint_send_ipi(const struct cpumask *target) 35 + { 36 + unsigned int cpu; 37 + 38 + for_each_cpu(cpu, target) 39 + writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu)); 40 + } 41 + 42 + static void clint_clear_ipi(void) 43 + { 44 + writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id())); 45 + } 46 + 47 + static struct riscv_ipi_ops clint_ipi_ops = { 48 + .ipi_inject = clint_send_ipi, 49 + .ipi_clear = clint_clear_ipi, 50 + }; 51 + 52 + #ifdef CONFIG_64BIT 53 + #define clint_get_cycles() readq_relaxed(clint_timer_val) 54 + #else 55 + #define clint_get_cycles() readl_relaxed(clint_timer_val) 56 + #define clint_get_cycles_hi() readl_relaxed(((u32 *)clint_timer_val) + 1) 57 + #endif 58 + 59 + #ifdef CONFIG_64BIT 60 + static u64 notrace clint_get_cycles64(void) 61 + { 62 + return clint_get_cycles(); 63 + } 64 + #else /* CONFIG_64BIT */ 65 + static u64 notrace clint_get_cycles64(void) 66 + { 67 + u32 hi, lo; 68 + 69 + do { 70 + hi = clint_get_cycles_hi(); 71 + lo = clint_get_cycles(); 72 + } while (hi != clint_get_cycles_hi()); 73 + 74 + return ((u64)hi << 32) | lo; 75 + } 76 + #endif /* CONFIG_64BIT */ 77 + 78 + static u64 clint_rdtime(struct clocksource *cs) 79 + { 80 + return clint_get_cycles64(); 81 + } 82 + 83 + static struct clocksource clint_clocksource = { 84 + .name = "clint_clocksource", 85 + .rating = 300, 86 + .mask = CLOCKSOURCE_MASK(64), 87 + .flags = CLOCK_SOURCE_IS_CONTINUOUS, 88 + .read = clint_rdtime, 89 + }; 90 + 91 + static int clint_clock_next_event(unsigned long delta, 92 + struct clock_event_device *ce) 93 + { 94 + void __iomem *r = clint_timer_cmp + 95 + cpuid_to_hartid_map(smp_processor_id()); 96 + 97 + csr_set(CSR_IE, IE_TIE); 98 + writeq_relaxed(clint_get_cycles64() + delta, r); 99 + return 0; 100 + } 101 + 102 + static DEFINE_PER_CPU(struct clock_event_device, clint_clock_event) = { 103 + .name = "clint_clockevent", 104 + .features = CLOCK_EVT_FEAT_ONESHOT, 105 + .rating = 100, 106 + .set_next_event = clint_clock_next_event, 107 + }; 108 + 109 + static int clint_timer_starting_cpu(unsigned int cpu) 110 + { 111 + struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu); 112 + 113 + ce->cpumask = cpumask_of(cpu); 114 + clockevents_config_and_register(ce, clint_timer_freq, 100, 0x7fffffff); 115 + 116 + enable_percpu_irq(clint_timer_irq, 117 + irq_get_trigger_type(clint_timer_irq)); 118 + return 0; 119 + } 120 + 121 + static int clint_timer_dying_cpu(unsigned int cpu) 122 + { 123 + disable_percpu_irq(clint_timer_irq); 124 + return 0; 125 + } 126 + 127 + static irqreturn_t clint_timer_interrupt(int irq, void *dev_id) 128 + { 129 + struct clock_event_device *evdev = this_cpu_ptr(&clint_clock_event); 130 + 131 + csr_clear(CSR_IE, IE_TIE); 132 + evdev->event_handler(evdev); 133 + 134 + return IRQ_HANDLED; 135 + } 136 + 137 + static int __init clint_timer_init_dt(struct device_node *np) 138 + { 139 + int rc; 140 + u32 i, nr_irqs; 141 + void __iomem *base; 142 + struct of_phandle_args oirq; 143 + 144 + /* 145 + * Ensure that CLINT device interrupts are either RV_IRQ_TIMER or 146 + * RV_IRQ_SOFT. If it's anything else then we ignore the device. 147 + */ 148 + nr_irqs = of_irq_count(np); 149 + for (i = 0; i < nr_irqs; i++) { 150 + if (of_irq_parse_one(np, i, &oirq)) { 151 + pr_err("%pOFP: failed to parse irq %d.\n", np, i); 152 + continue; 153 + } 154 + 155 + if ((oirq.args_count != 1) || 156 + (oirq.args[0] != RV_IRQ_TIMER && 157 + oirq.args[0] != RV_IRQ_SOFT)) { 158 + pr_err("%pOFP: invalid irq %d (hwirq %d)\n", 159 + np, i, oirq.args[0]); 160 + return -ENODEV; 161 + } 162 + 163 + /* Find parent irq domain and map timer irq */ 164 + if (!clint_timer_irq && 165 + oirq.args[0] == RV_IRQ_TIMER && 166 + irq_find_host(oirq.np)) 167 + clint_timer_irq = irq_of_parse_and_map(np, i); 168 + } 169 + 170 + /* If CLINT timer irq not found then fail */ 171 + if (!clint_timer_irq) { 172 + pr_err("%pOFP: timer irq not found\n", np); 173 + return -ENODEV; 174 + } 175 + 176 + base = of_iomap(np, 0); 177 + if (!base) { 178 + pr_err("%pOFP: could not map registers\n", np); 179 + return -ENODEV; 180 + } 181 + 182 + clint_ipi_base = base + CLINT_IPI_OFF; 183 + clint_timer_cmp = base + CLINT_TIMER_CMP_OFF; 184 + clint_timer_val = base + CLINT_TIMER_VAL_OFF; 185 + clint_timer_freq = riscv_timebase; 186 + 187 + pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq); 188 + 189 + rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq); 190 + if (rc) { 191 + pr_err("%pOFP: clocksource register failed [%d]\n", np, rc); 192 + goto fail_iounmap; 193 + } 194 + 195 + sched_clock_register(clint_get_cycles64, 64, clint_timer_freq); 196 + 197 + rc = request_percpu_irq(clint_timer_irq, clint_timer_interrupt, 198 + "clint-timer", &clint_clock_event); 199 + if (rc) { 200 + pr_err("registering percpu irq failed [%d]\n", rc); 201 + goto fail_iounmap; 202 + } 203 + 204 + rc = cpuhp_setup_state(CPUHP_AP_CLINT_TIMER_STARTING, 205 + "clockevents/clint/timer:starting", 206 + clint_timer_starting_cpu, 207 + clint_timer_dying_cpu); 208 + if (rc) { 209 + pr_err("%pOFP: cpuhp setup state failed [%d]\n", np, rc); 210 + goto fail_free_irq; 211 + } 212 + 213 + riscv_set_ipi_ops(&clint_ipi_ops); 214 + clint_clear_ipi(); 215 + 216 + return 0; 217 + 218 + fail_free_irq: 219 + free_irq(clint_timer_irq, &clint_clock_event); 220 + fail_iounmap: 221 + iounmap(base); 222 + return rc; 223 + } 224 + 225 + TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt); 226 + TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt);
+2 -15
drivers/clocksource/timer-riscv.c
··· 19 19 #include <linux/of_irq.h> 20 20 #include <asm/smp.h> 21 21 #include <asm/sbi.h> 22 - 23 - u64 __iomem *riscv_time_cmp; 24 - u64 __iomem *riscv_time_val; 25 - 26 - static inline void mmio_set_timer(u64 val) 27 - { 28 - void __iomem *r; 29 - 30 - r = riscv_time_cmp + cpuid_to_hartid_map(smp_processor_id()); 31 - writeq_relaxed(val, r); 32 - } 22 + #include <asm/timex.h> 33 23 34 24 static int riscv_clock_next_event(unsigned long delta, 35 25 struct clock_event_device *ce) 36 26 { 37 27 csr_set(CSR_IE, IE_TIE); 38 - if (IS_ENABLED(CONFIG_RISCV_SBI)) 39 - sbi_set_timer(get_cycles64() + delta); 40 - else 41 - mmio_set_timer(get_cycles64() + delta); 28 + sbi_set_timer(get_cycles64() + delta); 42 29 return 0; 43 30 } 44 31
+1
include/linux/cpuhotplug.h
··· 132 132 CPUHP_AP_MIPS_GIC_TIMER_STARTING, 133 133 CPUHP_AP_ARC_TIMER_STARTING, 134 134 CPUHP_AP_RISCV_TIMER_STARTING, 135 + CPUHP_AP_CLINT_TIMER_STARTING, 135 136 CPUHP_AP_CSKY_TIMER_STARTING, 136 137 CPUHP_AP_HYPERV_TIMER_STARTING, 137 138 CPUHP_AP_KVM_STARTING,