From c5575f7a2032499ccaeb0248ccb9e4ea220e6d94 Mon Sep 17 00:00:00 2001 From: Zoltan HERPAI Date: Wed, 15 May 2019 11:39:30 +0200 Subject: [PATCH] riscv64: backport staging patches, refresh drivers and config Signed-off-by: Zoltan HERPAI --- ...-FPU-context-operations-from-entry.S.patch | 247 ++++++ ...de-in-signal-setup-return-procedures.patch | 129 +++ .../0003-Cleanup-ISA-string-setting.patch | 65 ++ .../0004-Allow-to-disable-FPU-support.patch | 160 ++++ ...005-Auto-detect-whether-a-FPU-exists.patch | 123 +++ ...-RISC-V-Build-tishift-only-on-64-bit.patch | 30 + ...0007-RISC-V-Use-swiotlb-on-RV64-only.patch | 32 + ...and-udivmoddi4-of-GCC-library-routin.patch | 407 +++++++++ ...V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch | 28 + ...rupting-the-upper-32-bit-of-phys_add.patch | 34 + ...need-to-pass-scause-as-arg-to-do_IRQ.patch | 50 ++ ...-cacheinfo.-physical_line_partition-.patch | 40 + ...Filter-ISA-and-MMU-values-in-cpuinfo.patch | 107 +++ ...mment-on-the-TLB-flush-in-smp_callin.patch | 34 + ...reemption-before-enabling-interrupts.patch | 38 + ...ovide-a-cleaner-raw_smp_processor_id.patch | 55 ++ ...scv_of_processor_hart-to-riscv_of_pr.patch | 97 +++ ..._okay_therefore_i_am-to-found_boot_c.patch | 49 ++ .../patches-4.19/0019-RISC-V-Use-mmgrab.patch | 40 + ...-WRITE_ONCE-instead-of-direct-access.patch | 35 + ...-Add-logical-CPU-indexing-for-RISC-V.patch | 121 +++ ...-logical-CPU-number-instead-of-harti.patch | 322 +++++++ ...ID-and-Hart-ID-separately-in-proc-cp.patch | 89 ++ .../0024-RISC-V-Show-IPI-stats.patch | 178 ++++ ...the-F-extension-on-systems-without-D.patch | 43 + ...d-FP-register-ptrace-support-for-gdb.patch | 112 +++ .../0028-RISC-V-Add-futex-support.patch | 200 +++++ ...-the-unused-return_to_handler-export.patch | 29 + ...ersion-check-for-ARCH_SUPPORTS_INT12.patch | 43 + ...1-RISC-V-Cosmetic-menuconfig-changes.patch | 119 +++ ...C-V-properly-determine-hardware-caps.patch | 45 + .../0033-Move-EM_RISCV-into-elf-em.h.patch | 47 + ...V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch | 30 + ...moddi3-and-udivmoddi4-of-GCC-library.patch | 397 +++++++++ .../0036-RISC-V-refresh-defconfig.patch | 64 ++ ...V-defconfig-Enable-printk-timestamps.patch | 33 + ...-riscv-fix-spacing-in-struct-pt_regs.patch | 31 + ...iscv-add-missing-vdso_install-target.patch | 30 + ...ISC-V-lib-Fix-build-error-for-64-bit.patch | 34 + ...iscv-add-S-and-U-modes-to-ISA-string.patch | 21 + .../0101-002-clk-sifive-prci.patch} | 0 ...mplement-clock-switch-for-GEM-tx_cl.patch} | 45 +- .../0101-004-spi-sifive.patch} | 0 .../0101-005-spi-is25wp256d.patch} | 0 .../0101-006-uart-sifive-serial-driver.patch} | 0 ...-sifive-support-GPIO-on-SiFive-SoCs.patch} | 0 ...0101-008-RISC-V-Networking-fix-Hack.patch} | 0 ...five-add-a-driver-for-SiFive-SoC-PWM.patch | 339 ++++++++ ...otp-driver-for-SiFive-U500-OTP-contr.patch | 409 +++++++++ ...dded-support-for-the-Vera-board-root.patch | 804 ------------------ 50 files changed, 4562 insertions(+), 823 deletions(-) create mode 100644 target/linux/riscv64/patches-4.19/0001-Extract-FPU-context-operations-from-entry.S.patch create mode 100644 target/linux/riscv64/patches-4.19/0002-Refactor-FPU-code-in-signal-setup-return-procedures.patch create mode 100644 target/linux/riscv64/patches-4.19/0003-Cleanup-ISA-string-setting.patch create mode 100644 target/linux/riscv64/patches-4.19/0004-Allow-to-disable-FPU-support.patch create mode 100644 target/linux/riscv64/patches-4.19/0005-Auto-detect-whether-a-FPU-exists.patch create mode 100644 target/linux/riscv64/patches-4.19/0006-RISC-V-Build-tishift-only-on-64-bit.patch create mode 100644 target/linux/riscv64/patches-4.19/0007-RISC-V-Use-swiotlb-on-RV64-only.patch create mode 100644 target/linux/riscv64/patches-4.19/0008-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library-routin.patch create mode 100644 target/linux/riscv64/patches-4.19/0009-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch create mode 100644 target/linux/riscv64/patches-4.19/0010-RISC-V-Avoid-corrupting-the-upper-32-bit-of-phys_add.patch create mode 100644 target/linux/riscv64/patches-4.19/0011-RISC-V-No-need-to-pass-scause-as-arg-to-do_IRQ.patch create mode 100644 target/linux/riscv64/patches-4.19/0012-RISC-V-Don-t-set-cacheinfo.-physical_line_partition-.patch create mode 100644 target/linux/riscv64/patches-4.19/0013-RISC-V-Filter-ISA-and-MMU-values-in-cpuinfo.patch create mode 100644 target/linux/riscv64/patches-4.19/0014-RISC-V-Comment-on-the-TLB-flush-in-smp_callin.patch create mode 100644 target/linux/riscv64/patches-4.19/0015-RISC-V-Disable-preemption-before-enabling-interrupts.patch create mode 100644 target/linux/riscv64/patches-4.19/0016-RISC-V-Provide-a-cleaner-raw_smp_processor_id.patch create mode 100644 target/linux/riscv64/patches-4.19/0017-RISC-V-Rename-riscv_of_processor_hart-to-riscv_of_pr.patch create mode 100644 target/linux/riscv64/patches-4.19/0018-RISC-V-Rename-im_okay_therefore_i_am-to-found_boot_c.patch create mode 100644 target/linux/riscv64/patches-4.19/0019-RISC-V-Use-mmgrab.patch create mode 100644 target/linux/riscv64/patches-4.19/0020-RISC-V-Use-WRITE_ONCE-instead-of-direct-access.patch create mode 100644 target/linux/riscv64/patches-4.19/0021-RISC-V-Add-logical-CPU-indexing-for-RISC-V.patch create mode 100644 target/linux/riscv64/patches-4.19/0022-RISC-V-Use-Linux-logical-CPU-number-instead-of-harti.patch create mode 100644 target/linux/riscv64/patches-4.19/0023-RISC-V-Show-CPU-ID-and-Hart-ID-separately-in-proc-cp.patch create mode 100644 target/linux/riscv64/patches-4.19/0024-RISC-V-Show-IPI-stats.patch create mode 100644 target/linux/riscv64/patches-4.19/0026-RISC-V-Mask-out-the-F-extension-on-systems-without-D.patch create mode 100644 target/linux/riscv64/patches-4.19/0027-RISC-V-Add-FP-register-ptrace-support-for-gdb.patch create mode 100644 target/linux/riscv64/patches-4.19/0028-RISC-V-Add-futex-support.patch create mode 100644 target/linux/riscv64/patches-4.19/0029-RISC-V-remove-the-unused-return_to_handler-export.patch create mode 100644 target/linux/riscv64/patches-4.19/0030-riscv-move-GCC-version-check-for-ARCH_SUPPORTS_INT12.patch create mode 100644 target/linux/riscv64/patches-4.19/0031-RISC-V-Cosmetic-menuconfig-changes.patch create mode 100644 target/linux/riscv64/patches-4.19/0032-RISC-V-properly-determine-hardware-caps.patch create mode 100644 target/linux/riscv64/patches-4.19/0033-Move-EM_RISCV-into-elf-em.h.patch create mode 100644 target/linux/riscv64/patches-4.19/0034-Revert-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch create mode 100644 target/linux/riscv64/patches-4.19/0035-Revert-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library.patch create mode 100644 target/linux/riscv64/patches-4.19/0036-RISC-V-refresh-defconfig.patch create mode 100644 target/linux/riscv64/patches-4.19/0037-RISC-V-defconfig-Enable-printk-timestamps.patch create mode 100644 target/linux/riscv64/patches-4.19/0038-riscv-fix-spacing-in-struct-pt_regs.patch create mode 100644 target/linux/riscv64/patches-4.19/0039-riscv-add-missing-vdso_install-target.patch create mode 100644 target/linux/riscv64/patches-4.19/0040-RISC-V-lib-Fix-build-error-for-64-bit.patch create mode 100644 target/linux/riscv64/patches-4.19/0100-riscv-add-S-and-U-modes-to-ISA-string.patch rename target/linux/riscv64/{patches/002-clk-sifive-prci.patch => patches-4.19/0101-002-clk-sifive-prci.patch} (100%) rename target/linux/riscv64/{patches/003-clk-gemgxl.patch => patches-4.19/0101-003-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_cl.patch} (86%) rename target/linux/riscv64/{patches/004-spi-sifive.patch => patches-4.19/0101-004-spi-sifive.patch} (100%) rename target/linux/riscv64/{patches/005-spi-is25wp256d.patch => patches-4.19/0101-005-spi-is25wp256d.patch} (100%) rename target/linux/riscv64/{patches/006-uart-sifive-serial-driver.patch => patches-4.19/0101-006-uart-sifive-serial-driver.patch} (100%) rename target/linux/riscv64/{patches/007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch => patches-4.19/0101-007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch} (100%) rename target/linux/riscv64/{patches/0009-RISC-V-Networking-fix-Hack.patch => patches-4.19/0101-008-RISC-V-Networking-fix-Hack.patch} (100%) create mode 100644 target/linux/riscv64/patches-4.19/0101-010-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch create mode 100644 target/linux/riscv64/patches-4.19/0101-011-sifive-u500-otp-driver-for-SiFive-U500-OTP-contr.patch delete mode 100644 target/linux/riscv64/patches/0010-pcie-microsemi-added-support-for-the-Vera-board-root.patch diff --git a/target/linux/riscv64/patches-4.19/0001-Extract-FPU-context-operations-from-entry.S.patch b/target/linux/riscv64/patches-4.19/0001-Extract-FPU-context-operations-from-entry.S.patch new file mode 100644 index 0000000000..4a5550f213 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0001-Extract-FPU-context-operations-from-entry.S.patch @@ -0,0 +1,247 @@ +From e68ad867f77e1a839ad496ffcbd88b9c96769b5b Mon Sep 17 00:00:00 2001 +From: Alan Kao +Date: Tue, 9 Oct 2018 10:18:30 +0800 +Subject: [PATCH 01/41] Extract FPU context operations from entry.S + +We move __fstate_save and __fstate_restore to a new source +file, fpu.S. + +Signed-off-by: Alan Kao +Cc: Greentime Hu +Cc: Vincent Chen +Cc: Zong Li +Cc: Nick Hu +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/Makefile | 1 + + arch/riscv/kernel/entry.S | 87 ------------------------------------- + arch/riscv/kernel/fpu.S | 106 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 107 insertions(+), 87 deletions(-) + create mode 100644 arch/riscv/kernel/fpu.S + +diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile +index e1274fc..bd433efd 100644 +--- a/arch/riscv/kernel/Makefile ++++ b/arch/riscv/kernel/Makefile +@@ -13,6 +13,7 @@ extra-y += vmlinux.lds + obj-y += cpu.o + obj-y += cpufeature.o + obj-y += entry.o ++obj-y += fpu.o + obj-y += irq.o + obj-y += process.o + obj-y += ptrace.o +diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S +index fa2c08e..59c02e2 100644 +--- a/arch/riscv/kernel/entry.S ++++ b/arch/riscv/kernel/entry.S +@@ -357,93 +357,6 @@ ENTRY(__switch_to) + ret + ENDPROC(__switch_to) + +-ENTRY(__fstate_save) +- li a2, TASK_THREAD_F0 +- add a0, a0, a2 +- li t1, SR_FS +- csrs sstatus, t1 +- frcsr t0 +- fsd f0, TASK_THREAD_F0_F0(a0) +- fsd f1, TASK_THREAD_F1_F0(a0) +- fsd f2, TASK_THREAD_F2_F0(a0) +- fsd f3, TASK_THREAD_F3_F0(a0) +- fsd f4, TASK_THREAD_F4_F0(a0) +- fsd f5, TASK_THREAD_F5_F0(a0) +- fsd f6, TASK_THREAD_F6_F0(a0) +- fsd f7, TASK_THREAD_F7_F0(a0) +- fsd f8, TASK_THREAD_F8_F0(a0) +- fsd f9, TASK_THREAD_F9_F0(a0) +- fsd f10, TASK_THREAD_F10_F0(a0) +- fsd f11, TASK_THREAD_F11_F0(a0) +- fsd f12, TASK_THREAD_F12_F0(a0) +- fsd f13, TASK_THREAD_F13_F0(a0) +- fsd f14, TASK_THREAD_F14_F0(a0) +- fsd f15, TASK_THREAD_F15_F0(a0) +- fsd f16, TASK_THREAD_F16_F0(a0) +- fsd f17, TASK_THREAD_F17_F0(a0) +- fsd f18, TASK_THREAD_F18_F0(a0) +- fsd f19, TASK_THREAD_F19_F0(a0) +- fsd f20, TASK_THREAD_F20_F0(a0) +- fsd f21, TASK_THREAD_F21_F0(a0) +- fsd f22, TASK_THREAD_F22_F0(a0) +- fsd f23, TASK_THREAD_F23_F0(a0) +- fsd f24, TASK_THREAD_F24_F0(a0) +- fsd f25, TASK_THREAD_F25_F0(a0) +- fsd f26, TASK_THREAD_F26_F0(a0) +- fsd f27, TASK_THREAD_F27_F0(a0) +- fsd f28, TASK_THREAD_F28_F0(a0) +- fsd f29, TASK_THREAD_F29_F0(a0) +- fsd f30, TASK_THREAD_F30_F0(a0) +- fsd f31, TASK_THREAD_F31_F0(a0) +- sw t0, TASK_THREAD_FCSR_F0(a0) +- csrc sstatus, t1 +- ret +-ENDPROC(__fstate_save) +- +-ENTRY(__fstate_restore) +- li a2, TASK_THREAD_F0 +- add a0, a0, a2 +- li t1, SR_FS +- lw t0, TASK_THREAD_FCSR_F0(a0) +- csrs sstatus, t1 +- fld f0, TASK_THREAD_F0_F0(a0) +- fld f1, TASK_THREAD_F1_F0(a0) +- fld f2, TASK_THREAD_F2_F0(a0) +- fld f3, TASK_THREAD_F3_F0(a0) +- fld f4, TASK_THREAD_F4_F0(a0) +- fld f5, TASK_THREAD_F5_F0(a0) +- fld f6, TASK_THREAD_F6_F0(a0) +- fld f7, TASK_THREAD_F7_F0(a0) +- fld f8, TASK_THREAD_F8_F0(a0) +- fld f9, TASK_THREAD_F9_F0(a0) +- fld f10, TASK_THREAD_F10_F0(a0) +- fld f11, TASK_THREAD_F11_F0(a0) +- fld f12, TASK_THREAD_F12_F0(a0) +- fld f13, TASK_THREAD_F13_F0(a0) +- fld f14, TASK_THREAD_F14_F0(a0) +- fld f15, TASK_THREAD_F15_F0(a0) +- fld f16, TASK_THREAD_F16_F0(a0) +- fld f17, TASK_THREAD_F17_F0(a0) +- fld f18, TASK_THREAD_F18_F0(a0) +- fld f19, TASK_THREAD_F19_F0(a0) +- fld f20, TASK_THREAD_F20_F0(a0) +- fld f21, TASK_THREAD_F21_F0(a0) +- fld f22, TASK_THREAD_F22_F0(a0) +- fld f23, TASK_THREAD_F23_F0(a0) +- fld f24, TASK_THREAD_F24_F0(a0) +- fld f25, TASK_THREAD_F25_F0(a0) +- fld f26, TASK_THREAD_F26_F0(a0) +- fld f27, TASK_THREAD_F27_F0(a0) +- fld f28, TASK_THREAD_F28_F0(a0) +- fld f29, TASK_THREAD_F29_F0(a0) +- fld f30, TASK_THREAD_F30_F0(a0) +- fld f31, TASK_THREAD_F31_F0(a0) +- fscsr t0 +- csrc sstatus, t1 +- ret +-ENDPROC(__fstate_restore) +- +- + .section ".rodata" + /* Exception vector table */ + ENTRY(excp_vect_table) +diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S +new file mode 100644 +index 0000000..1defb06 +--- /dev/null ++++ b/arch/riscv/kernel/fpu.S +@@ -0,0 +1,106 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2012 Regents of the University of California ++ * Copyright (C) 2017 SiFive ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation, version 2. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++ENTRY(__fstate_save) ++ li a2, TASK_THREAD_F0 ++ add a0, a0, a2 ++ li t1, SR_FS ++ csrs sstatus, t1 ++ frcsr t0 ++ fsd f0, TASK_THREAD_F0_F0(a0) ++ fsd f1, TASK_THREAD_F1_F0(a0) ++ fsd f2, TASK_THREAD_F2_F0(a0) ++ fsd f3, TASK_THREAD_F3_F0(a0) ++ fsd f4, TASK_THREAD_F4_F0(a0) ++ fsd f5, TASK_THREAD_F5_F0(a0) ++ fsd f6, TASK_THREAD_F6_F0(a0) ++ fsd f7, TASK_THREAD_F7_F0(a0) ++ fsd f8, TASK_THREAD_F8_F0(a0) ++ fsd f9, TASK_THREAD_F9_F0(a0) ++ fsd f10, TASK_THREAD_F10_F0(a0) ++ fsd f11, TASK_THREAD_F11_F0(a0) ++ fsd f12, TASK_THREAD_F12_F0(a0) ++ fsd f13, TASK_THREAD_F13_F0(a0) ++ fsd f14, TASK_THREAD_F14_F0(a0) ++ fsd f15, TASK_THREAD_F15_F0(a0) ++ fsd f16, TASK_THREAD_F16_F0(a0) ++ fsd f17, TASK_THREAD_F17_F0(a0) ++ fsd f18, TASK_THREAD_F18_F0(a0) ++ fsd f19, TASK_THREAD_F19_F0(a0) ++ fsd f20, TASK_THREAD_F20_F0(a0) ++ fsd f21, TASK_THREAD_F21_F0(a0) ++ fsd f22, TASK_THREAD_F22_F0(a0) ++ fsd f23, TASK_THREAD_F23_F0(a0) ++ fsd f24, TASK_THREAD_F24_F0(a0) ++ fsd f25, TASK_THREAD_F25_F0(a0) ++ fsd f26, TASK_THREAD_F26_F0(a0) ++ fsd f27, TASK_THREAD_F27_F0(a0) ++ fsd f28, TASK_THREAD_F28_F0(a0) ++ fsd f29, TASK_THREAD_F29_F0(a0) ++ fsd f30, TASK_THREAD_F30_F0(a0) ++ fsd f31, TASK_THREAD_F31_F0(a0) ++ sw t0, TASK_THREAD_FCSR_F0(a0) ++ csrc sstatus, t1 ++ ret ++ENDPROC(__fstate_save) ++ ++ENTRY(__fstate_restore) ++ li a2, TASK_THREAD_F0 ++ add a0, a0, a2 ++ li t1, SR_FS ++ lw t0, TASK_THREAD_FCSR_F0(a0) ++ csrs sstatus, t1 ++ fld f0, TASK_THREAD_F0_F0(a0) ++ fld f1, TASK_THREAD_F1_F0(a0) ++ fld f2, TASK_THREAD_F2_F0(a0) ++ fld f3, TASK_THREAD_F3_F0(a0) ++ fld f4, TASK_THREAD_F4_F0(a0) ++ fld f5, TASK_THREAD_F5_F0(a0) ++ fld f6, TASK_THREAD_F6_F0(a0) ++ fld f7, TASK_THREAD_F7_F0(a0) ++ fld f8, TASK_THREAD_F8_F0(a0) ++ fld f9, TASK_THREAD_F9_F0(a0) ++ fld f10, TASK_THREAD_F10_F0(a0) ++ fld f11, TASK_THREAD_F11_F0(a0) ++ fld f12, TASK_THREAD_F12_F0(a0) ++ fld f13, TASK_THREAD_F13_F0(a0) ++ fld f14, TASK_THREAD_F14_F0(a0) ++ fld f15, TASK_THREAD_F15_F0(a0) ++ fld f16, TASK_THREAD_F16_F0(a0) ++ fld f17, TASK_THREAD_F17_F0(a0) ++ fld f18, TASK_THREAD_F18_F0(a0) ++ fld f19, TASK_THREAD_F19_F0(a0) ++ fld f20, TASK_THREAD_F20_F0(a0) ++ fld f21, TASK_THREAD_F21_F0(a0) ++ fld f22, TASK_THREAD_F22_F0(a0) ++ fld f23, TASK_THREAD_F23_F0(a0) ++ fld f24, TASK_THREAD_F24_F0(a0) ++ fld f25, TASK_THREAD_F25_F0(a0) ++ fld f26, TASK_THREAD_F26_F0(a0) ++ fld f27, TASK_THREAD_F27_F0(a0) ++ fld f28, TASK_THREAD_F28_F0(a0) ++ fld f29, TASK_THREAD_F29_F0(a0) ++ fld f30, TASK_THREAD_F30_F0(a0) ++ fld f31, TASK_THREAD_F31_F0(a0) ++ fscsr t0 ++ csrc sstatus, t1 ++ ret ++ENDPROC(__fstate_restore) +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0002-Refactor-FPU-code-in-signal-setup-return-procedures.patch b/target/linux/riscv64/patches-4.19/0002-Refactor-FPU-code-in-signal-setup-return-procedures.patch new file mode 100644 index 0000000000..942af4d049 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0002-Refactor-FPU-code-in-signal-setup-return-procedures.patch @@ -0,0 +1,129 @@ +From 007f5c35895786fdc797f13313b9493fe5d5e655 Mon Sep 17 00:00:00 2001 +From: Alan Kao +Date: Tue, 9 Oct 2018 10:18:31 +0800 +Subject: [PATCH 02/41] Refactor FPU code in signal setup/return procedures + +FPU-related logic is separated from normal signal handling path in +this patch. Kernel can easily be configured to exclude those procedures +for no-FPU systems. + +Signed-off-by: Alan Kao +Cc: Greentime Hu +Cc: Vincent Chen +Cc: Zong Li +Cc: Nick Hu +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/signal.c | 68 ++++++++++++++++++++++++++++------------------ + 1 file changed, 41 insertions(+), 27 deletions(-) + +diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c +index 718d0c9..6a18b98 100644 +--- a/arch/riscv/kernel/signal.c ++++ b/arch/riscv/kernel/signal.c +@@ -37,45 +37,63 @@ struct rt_sigframe { + struct ucontext uc; + }; + +-static long restore_d_state(struct pt_regs *regs, +- struct __riscv_d_ext_state __user *state) ++static long restore_fp_state(struct pt_regs *regs, ++ union __riscv_fp_state *sc_fpregs) + { + long err; ++ struct __riscv_d_ext_state __user *state = &sc_fpregs->d; ++ size_t i; ++ + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); +- if (likely(!err)) +- fstate_restore(current, regs); ++ if (unlikely(err)) ++ return err; ++ ++ fstate_restore(current, regs); ++ ++ /* We support no other extension state at this time. */ ++ for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { ++ u32 value; ++ ++ err = __get_user(value, &sc_fpregs->q.reserved[i]); ++ if (unlikely(err)) ++ break; ++ if (value != 0) ++ return -EINVAL; ++ } ++ + return err; + } + +-static long save_d_state(struct pt_regs *regs, +- struct __riscv_d_ext_state __user *state) ++static long save_fp_state(struct pt_regs *regs, ++ union __riscv_fp_state *sc_fpregs) + { ++ long err; ++ struct __riscv_d_ext_state __user *state = &sc_fpregs->d; ++ size_t i; ++ + fstate_save(current, regs); +- return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); ++ err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); ++ if (unlikely(err)) ++ return err; ++ ++ /* We support no other extension state at this time. */ ++ for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { ++ err = __put_user(0, &sc_fpregs->q.reserved[i]); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; + } + + static long restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc) + { + long err; +- size_t i; + /* sc_regs is structured the same as the start of pt_regs */ + err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); +- if (unlikely(err)) +- return err; + /* Restore the floating-point state. */ +- err = restore_d_state(regs, &sc->sc_fpregs.d); +- if (unlikely(err)) +- return err; +- /* We support no other extension state at this time. */ +- for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { +- u32 value; +- err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); +- if (unlikely(err)) +- break; +- if (value != 0) +- return -EINVAL; +- } ++ err |= restore_fp_state(regs, &sc->sc_fpregs); + return err; + } + +@@ -124,14 +142,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, + { + struct sigcontext __user *sc = &frame->uc.uc_mcontext; + long err; +- size_t i; + /* sc_regs is structured the same as the start of pt_regs */ + err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); + /* Save the floating-point state. */ +- err |= save_d_state(regs, &sc->sc_fpregs.d); +- /* We support no other extension state at this time. */ +- for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) +- err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); ++ err |= save_fp_state(regs, &sc->sc_fpregs); + return err; + } + +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0003-Cleanup-ISA-string-setting.patch b/target/linux/riscv64/patches-4.19/0003-Cleanup-ISA-string-setting.patch new file mode 100644 index 0000000000..ef452aa382 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0003-Cleanup-ISA-string-setting.patch @@ -0,0 +1,65 @@ +From e8be5302330281bd9f77834600f63e8cc4560d3d Mon Sep 17 00:00:00 2001 +From: Alan Kao +Date: Tue, 9 Oct 2018 10:18:32 +0800 +Subject: [PATCH 03/41] Cleanup ISA string setting + +This patch cleanup the MARCH string passing to both compiler and +assembler. Note that the CFLAGS should not contain "fd" before we +have mechnisms like kernel_fpu_begin/end in other architectures. + +Signed-off-by: Alan Kao +Cc: Greentime Hu +Cc: Vincent Chen +Cc: Zong Li +Cc: Nick Hu +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Makefile | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index 61ec424..01393e1 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -28,7 +28,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) + + KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0500, -DCONFIG_ARCH_SUPPORTS_INT128) + +- KBUILD_MARCH = rv64im + KBUILD_LDFLAGS += -melf64lriscv + else + BITS := 32 +@@ -36,22 +35,20 @@ else + + KBUILD_CFLAGS += -mabi=ilp32 + KBUILD_AFLAGS += -mabi=ilp32 +- KBUILD_MARCH = rv32im + KBUILD_LDFLAGS += -melf32lriscv + endif + + KBUILD_CFLAGS += -Wall + +-ifeq ($(CONFIG_RISCV_ISA_A),y) +- KBUILD_ARCH_A = a +-endif +-ifeq ($(CONFIG_RISCV_ISA_C),y) +- KBUILD_ARCH_C = c +-endif +- +-KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) ++# ISA string setting ++riscv-march-$(CONFIG_ARCH_RV32I) := rv32im ++riscv-march-$(CONFIG_ARCH_RV64I) := rv64im ++riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a ++riscv-march-y := $(riscv-march-y)fd ++riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c ++KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) ++KBUILD_AFLAGS += -march=$(riscv-march-y) + +-KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) + KBUILD_CFLAGS += -mno-save-restore + KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) + +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0004-Allow-to-disable-FPU-support.patch b/target/linux/riscv64/patches-4.19/0004-Allow-to-disable-FPU-support.patch new file mode 100644 index 0000000000..e4bf664637 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0004-Allow-to-disable-FPU-support.patch @@ -0,0 +1,160 @@ +From 9671f7061433e2c58b9894093eada1898595b85d Mon Sep 17 00:00:00 2001 +From: Alan Kao +Date: Tue, 9 Oct 2018 10:18:33 +0800 +Subject: [PATCH 04/41] Allow to disable FPU support + +FPU codes have been separated from common part in previous patches. +This patch add the CONFIG_FPU option and some stubs, so that a no-FPU +configuration is allowed. + +Signed-off-by: Alan Kao +Cc: Greentime Hu +Cc: Vincent Chen +Cc: Zong Li +Cc: Nick Hu +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Kconfig | 9 +++++++++ + arch/riscv/Makefile | 2 +- + arch/riscv/include/asm/switch_to.h | 10 ++++++++++ + arch/riscv/kernel/Makefile | 2 +- + arch/riscv/kernel/process.c | 4 +++- + arch/riscv/kernel/signal.c | 5 +++++ + 6 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index a344980..a63f9db 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -208,6 +208,15 @@ config RISCV_BASE_PMU + + endmenu + ++config FPU ++ bool "FPU support" ++ default y ++ help ++ Say N here if you want to disable all floating-point related procedure ++ in the kernel. ++ ++ If you don't know what to do here, say Y. ++ + endmenu + + menu "Kernel type" +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index 01393e1..901770f 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -44,7 +44,7 @@ KBUILD_CFLAGS += -Wall + riscv-march-$(CONFIG_ARCH_RV32I) := rv32im + riscv-march-$(CONFIG_ARCH_RV64I) := rv64im + riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +-riscv-march-y := $(riscv-march-y)fd ++riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd + riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c + KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) + KBUILD_AFLAGS += -march=$(riscv-march-y) +diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h +index dd6b05b..093050b 100644 +--- a/arch/riscv/include/asm/switch_to.h ++++ b/arch/riscv/include/asm/switch_to.h +@@ -18,6 +18,7 @@ + #include + #include + ++#ifdef CONFIG_FPU + extern void __fstate_save(struct task_struct *save_to); + extern void __fstate_restore(struct task_struct *restore_from); + +@@ -55,6 +56,15 @@ static inline void __switch_to_aux(struct task_struct *prev, + fstate_restore(next, task_pt_regs(next)); + } + ++#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) ++ ++#else ++#define fstate_save(task, regs) do { } while (0) ++#define fstate_restore(task, regs) do { } while (0) ++#define __switch_to_aux(__prev, __next) do { } while (0) ++#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) ++#endif ++ + extern struct task_struct *__switch_to(struct task_struct *, + struct task_struct *); + +diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile +index bd433efd..f13f7f2 100644 +--- a/arch/riscv/kernel/Makefile ++++ b/arch/riscv/kernel/Makefile +@@ -13,7 +13,6 @@ extra-y += vmlinux.lds + obj-y += cpu.o + obj-y += cpufeature.o + obj-y += entry.o +-obj-y += fpu.o + obj-y += irq.o + obj-y += process.o + obj-y += ptrace.o +@@ -32,6 +31,7 @@ obj-y += vdso/ + + CFLAGS_setup.o := -mcmodel=medany + ++obj-$(CONFIG_FPU) += fpu.o + obj-$(CONFIG_SMP) += smpboot.o + obj-$(CONFIG_SMP) += smp.o + obj-$(CONFIG_MODULES) += module.o +diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c +index d7c6ca7..07d5156 100644 +--- a/arch/riscv/kernel/process.c ++++ b/arch/riscv/kernel/process.c +@@ -76,7 +76,7 @@ void show_regs(struct pt_regs *regs) + void start_thread(struct pt_regs *regs, unsigned long pc, + unsigned long sp) + { +- regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; ++ regs->sstatus = DEFAULT_SSTATUS; + regs->sepc = pc; + regs->sp = sp; + set_fs(USER_DS); +@@ -84,12 +84,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, + + void flush_thread(void) + { ++#ifdef CONFIG_FPU + /* + * Reset FPU context + * frm: round to nearest, ties to even (IEEE default) + * fflags: accrued exceptions cleared + */ + memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate)); ++#endif + } + + int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) +diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c +index 6a18b98..2450b82 100644 +--- a/arch/riscv/kernel/signal.c ++++ b/arch/riscv/kernel/signal.c +@@ -37,6 +37,7 @@ struct rt_sigframe { + struct ucontext uc; + }; + ++#ifdef CONFIG_FPU + static long restore_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) + { +@@ -85,6 +86,10 @@ static long save_fp_state(struct pt_regs *regs, + + return err; + } ++#else ++#define save_fp_state(task, regs) (0) ++#define restore_fp_state(task, regs) (0) ++#endif + + static long restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc) +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0005-Auto-detect-whether-a-FPU-exists.patch b/target/linux/riscv64/patches-4.19/0005-Auto-detect-whether-a-FPU-exists.patch new file mode 100644 index 0000000000..98709b56c1 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0005-Auto-detect-whether-a-FPU-exists.patch @@ -0,0 +1,123 @@ +From 9411ec60c23d868124d9c1b1d491937aebe07afa Mon Sep 17 00:00:00 2001 +From: Alan Kao +Date: Tue, 9 Oct 2018 10:18:34 +0800 +Subject: [PATCH 05/41] Auto-detect whether a FPU exists + +We expect that a kernel with CONFIG_FPU=y can still support no-FPU +machines. To do so, the kernel should first examine the existence of a +FPU, then do nothing if a FPU does exist; otherwise, it should +disable/bypass all FPU-related functions. + +In this patch, a new global variable, has_fpu, is created and determined +when parsing the hardware capability from device tree during booting. +This variable is used in those FPU-related functions. + +Signed-off-by: Alan Kao +Cc: Greentime Hu +Cc: Vincent Chen +Cc: Zong Li +Cc: Nick Hu +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/switch_to.h | 8 ++++---- + arch/riscv/kernel/cpufeature.c | 8 ++++++++ + arch/riscv/kernel/process.c | 4 +++- + arch/riscv/kernel/signal.c | 6 ++++-- + 4 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h +index 093050b..7335590 100644 +--- a/arch/riscv/include/asm/switch_to.h ++++ b/arch/riscv/include/asm/switch_to.h +@@ -56,13 +56,12 @@ static inline void __switch_to_aux(struct task_struct *prev, + fstate_restore(next, task_pt_regs(next)); + } + +-#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) +- ++extern bool has_fpu; + #else ++#define has_fpu false + #define fstate_save(task, regs) do { } while (0) + #define fstate_restore(task, regs) do { } while (0) + #define __switch_to_aux(__prev, __next) do { } while (0) +-#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) + #endif + + extern struct task_struct *__switch_to(struct task_struct *, +@@ -72,7 +71,8 @@ extern struct task_struct *__switch_to(struct task_struct *, + do { \ + struct task_struct *__prev = (prev); \ + struct task_struct *__next = (next); \ +- __switch_to_aux(__prev, __next); \ ++ if (has_fpu) \ ++ __switch_to_aux(__prev, __next); \ + ((last) = __switch_to(__prev, __next)); \ + } while (0) + +diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c +index 17011a8..46942e6 100644 +--- a/arch/riscv/kernel/cpufeature.c ++++ b/arch/riscv/kernel/cpufeature.c +@@ -22,6 +22,9 @@ + #include + + unsigned long elf_hwcap __read_mostly; ++#ifdef CONFIG_FPU ++bool has_fpu __read_mostly; ++#endif + + void riscv_fill_hwcap(void) + { +@@ -58,4 +61,9 @@ void riscv_fill_hwcap(void) + elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; + + pr_info("elf_hwcap is 0x%lx", elf_hwcap); ++ ++#ifdef CONFIG_FPU ++ if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) ++ has_fpu = true; ++#endif + } +diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c +index 07d5156..bef1999 100644 +--- a/arch/riscv/kernel/process.c ++++ b/arch/riscv/kernel/process.c +@@ -76,7 +76,9 @@ void show_regs(struct pt_regs *regs) + void start_thread(struct pt_regs *regs, unsigned long pc, + unsigned long sp) + { +- regs->sstatus = DEFAULT_SSTATUS; ++ regs->sstatus = SR_SPIE; ++ if (has_fpu) ++ regs->sstatus |= SR_FS_INITIAL; + regs->sepc = pc; + regs->sp = sp; + set_fs(USER_DS); +diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c +index 2450b82..f9b5e7e 100644 +--- a/arch/riscv/kernel/signal.c ++++ b/arch/riscv/kernel/signal.c +@@ -98,7 +98,8 @@ static long restore_sigcontext(struct pt_regs *regs, + /* sc_regs is structured the same as the start of pt_regs */ + err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); + /* Restore the floating-point state. */ +- err |= restore_fp_state(regs, &sc->sc_fpregs); ++ if (has_fpu) ++ err |= restore_fp_state(regs, &sc->sc_fpregs); + return err; + } + +@@ -150,7 +151,8 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, + /* sc_regs is structured the same as the start of pt_regs */ + err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); + /* Save the floating-point state. */ +- err |= save_fp_state(regs, &sc->sc_fpregs); ++ if (has_fpu) ++ err |= save_fp_state(regs, &sc->sc_fpregs); + return err; + } + +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0006-RISC-V-Build-tishift-only-on-64-bit.patch b/target/linux/riscv64/patches-4.19/0006-RISC-V-Build-tishift-only-on-64-bit.patch new file mode 100644 index 0000000000..8b64199691 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0006-RISC-V-Build-tishift-only-on-64-bit.patch @@ -0,0 +1,30 @@ +From 7f47c73b355f300cf162f3a664e43d557d2cb30d Mon Sep 17 00:00:00 2001 +From: Zong Li +Date: Tue, 2 Oct 2018 16:52:27 +0800 +Subject: [PATCH 06/41] RISC-V: Build tishift only on 64-bit + +Only RV64 supports 128 integer size. + +Signed-off-by: Zong Li +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/lib/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile +index 445ec84..5739bd0 100644 +--- a/arch/riscv/lib/Makefile ++++ b/arch/riscv/lib/Makefile +@@ -2,6 +2,7 @@ lib-y += delay.o + lib-y += memcpy.o + lib-y += memset.o + lib-y += uaccess.o +-lib-y += tishift.o ++ ++lib-(CONFIG_64BIT) += tishift.o + + lib-$(CONFIG_32BIT) += udivdi3.o +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0007-RISC-V-Use-swiotlb-on-RV64-only.patch b/target/linux/riscv64/patches-4.19/0007-RISC-V-Use-swiotlb-on-RV64-only.patch new file mode 100644 index 0000000000..6833d0116f --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0007-RISC-V-Use-swiotlb-on-RV64-only.patch @@ -0,0 +1,32 @@ +From 51858aaf9bea3ddf166bf9d252a1fc351260b497 Mon Sep 17 00:00:00 2001 +From: Zong Li +Date: Tue, 2 Oct 2018 16:52:28 +0800 +Subject: [PATCH 07/41] RISC-V: Use swiotlb on RV64 only + +Only RV64 supports swiotlb. On RV32, it don't select the SWIOTLB. + +Signed-off-by: Zong Li +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/setup.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index b2d26d9..c946198 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -227,7 +227,10 @@ void __init setup_arch(char **cmdline_p) + setup_bootmem(); + paging_init(); + unflatten_device_tree(); ++ ++#ifdef CONFIG_SWIOTLB + swiotlb_init(1); ++#endif + + #ifdef CONFIG_SMP + setup_smp(); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0008-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library-routin.patch b/target/linux/riscv64/patches-4.19/0008-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library-routin.patch new file mode 100644 index 0000000000..f115f72539 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0008-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library-routin.patch @@ -0,0 +1,407 @@ +From 6315730e9eab7de5fa9864bb13a352713f48aef1 Mon Sep 17 00:00:00 2001 +From: Zong Li +Date: Tue, 2 Oct 2018 16:52:29 +0800 +Subject: [PATCH 08/41] lib: Add umoddi3 and udivmoddi4 of GCC library routines + +Add umoddi3 and udivmoddi4 support for 32-bit. + +The RV32 need the umoddi3 to do modulo when the operands are long long +type, like other libraries implementation such as ucmpdi2, lshrdi3 and +so on. + +I encounter the undefined reference 'umoddi3' when I use the in +house dma driver, although it is in house driver, but I think that +umoddi3 is a common function for RV32. + +The udivmoddi4 and umoddi3 are copies from libgcc in gcc. There are other +functions use the udivmoddi4 in libgcc, so I separate the umoddi3 and +udivmoddi4 for flexible extension in the future. + +Signed-off-by: Zong Li +Signed-off-by: Palmer Dabbelt +--- + lib/Kconfig | 3 + + lib/Makefile | 1 + + lib/udivmoddi4.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + lib/umoddi3.c | 32 ++++++ + 4 files changed, 346 insertions(+) + create mode 100644 lib/udivmoddi4.c + create mode 100644 lib/umoddi3.c + +diff --git a/lib/Kconfig b/lib/Kconfig +index a3928d4..d82f206 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -621,3 +621,6 @@ config GENERIC_LIB_CMPDI2 + + config GENERIC_LIB_UCMPDI2 + bool ++ ++config GENERIC_LIB_UMODDI3 ++ bool +diff --git a/lib/Makefile b/lib/Makefile +index 4238764..56a8d9c 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -270,3 +270,4 @@ obj-$(CONFIG_GENERIC_LIB_LSHRDI3) += lshrdi3.o + obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o + obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o + obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o ++obj-$(CONFIG_GENERIC_LIB_UMODDI3) += umoddi3.o udivmoddi4.o +diff --git a/lib/udivmoddi4.c b/lib/udivmoddi4.c +new file mode 100644 +index 0000000..c08bc8a +--- /dev/null ++++ b/lib/udivmoddi4.c +@@ -0,0 +1,310 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see the file COPYING, or write ++ * to the Free Software Foundation, Inc. ++ */ ++ ++#include ++ ++#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz(X)) ++ ++#define W_TYPE_SIZE 32 ++ ++#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) ++#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) ++#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) ++ ++/* If we still don't have umul_ppmm, define it using plain C. */ ++#if !defined(umul_ppmm) ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ unsigned long __x0, __x1, __x2, __x3; \ ++ unsigned short __ul, __vl, __uh, __vh; \ ++ \ ++ __ul = __ll_lowpart(u); \ ++ __uh = __ll_highpart(u); \ ++ __vl = __ll_lowpart(v); \ ++ __vh = __ll_highpart(v); \ ++ \ ++ __x0 = (unsigned long) __ul * __vl; \ ++ __x1 = (unsigned long) __ul * __vh; \ ++ __x2 = (unsigned long) __uh * __vl; \ ++ __x3 = (unsigned long) __uh * __vh; \ ++ \ ++ __x1 += __ll_highpart(__x0); \ ++ __x1 += __x2; \ ++ if (__x1 < __x2) \ ++ __x3 += __ll_B; \ ++ \ ++ (w1) = __x3 + __ll_highpart(__x1); \ ++ (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ ++ } while (0) ++#endif ++ ++#if !defined(sub_ddmmss) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ unsigned long __x; \ ++ __x = (al) - (bl); \ ++ (sh) = (ah) - (bh) - (__x > (al)); \ ++ (sl) = __x; \ ++ } while (0) ++#endif ++ ++/* Define this unconditionally, so it can be used for debugging. */ ++#define __udiv_qrnnd_c(q, r, n1, n0, d) \ ++ do { \ ++ unsigned long __d1, __d0, __q1, __q0; \ ++ unsigned long __r1, __r0, __m; \ ++ __d1 = __ll_highpart(d); \ ++ __d0 = __ll_lowpart(d); \ ++ \ ++ __r1 = (n1) % __d1; \ ++ __q1 = (n1) / __d1; \ ++ __m = (unsigned long) __q1 * __d0; \ ++ __r1 = __r1 * __ll_B | __ll_highpart(n0); \ ++ if (__r1 < __m) { \ ++ __q1--, __r1 += (d); \ ++ if (__r1 >= (d)) \ ++ if (__r1 < __m) \ ++ __q1--, __r1 += (d); \ ++ } \ ++ __r1 -= __m; \ ++ \ ++ __r0 = __r1 % __d1; \ ++ __q0 = __r1 / __d1; \ ++ __m = (unsigned long) __q0 * __d0; \ ++ __r0 = __r0 * __ll_B | __ll_lowpart(n0); \ ++ if (__r0 < __m) { \ ++ __q0--, __r0 += (d); \ ++ if (__r0 >= (d)) \ ++ if (__r0 < __m) \ ++ __q0--, __r0 += (d); \ ++ } \ ++ __r0 -= __m; \ ++ \ ++ (q) = (unsigned long) __q1 * __ll_B | __q0; \ ++ (r) = __r0; \ ++ } while (0) ++ ++/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ ++#if !defined(udiv_qrnnd) ++#define UDIV_NEEDS_NORMALIZATION 1 ++#define udiv_qrnnd __udiv_qrnnd_c ++#endif ++ ++unsigned long long __udivmoddi4(unsigned long long u, unsigned long long v, ++ unsigned long long *rp) ++{ ++ const DWunion nn = {.ll = u }; ++ const DWunion dd = {.ll = v }; ++ DWunion rr, ww; ++ unsigned long d0, d1, n0, n1, n2; ++ unsigned long q0 = 0, q1 = 0; ++ unsigned long b, bm; ++ ++ d0 = dd.s.low; ++ d1 = dd.s.high; ++ n0 = nn.s.low; ++ n1 = nn.s.high; ++ ++#if !UDIV_NEEDS_NORMALIZATION ++ ++ if (d1 == 0) { ++ if (d0 > n1) { ++ /* 0q = nn / 0D */ ++ ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0. */ ++ } else { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ /* Divide intentionally by zero. */ ++ d0 = 1 / d0; ++ ++ udiv_qrnnd(q1, n1, 0, n1, d0); ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0. */ ++ } ++ ++ if (rp != 0) { ++ rr.s.low = n0; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ ++#else /* UDIV_NEEDS_NORMALIZATION */ ++ ++ if (d1 == 0) { ++ if (d0 > n1) { ++ /* 0q = nn / 0D */ ++ ++ count_leading_zeros(bm, d0); ++ ++ if (bm != 0) { ++ /* ++ * Normalize, i.e. make the most significant bit ++ * of the denominator set. ++ */ ++ ++ d0 = d0 << bm; ++ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); ++ n0 = n0 << bm; ++ } ++ ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0 >> bm. */ ++ } else { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ /* Divide intentionally by zero. */ ++ d0 = 1 / d0; ++ ++ count_leading_zeros(bm, d0); ++ ++ if (bm == 0) { ++ /* ++ * From (n1 >= d0) /\ (the most significant bit ++ * of d0 is set), conclude (the most significant ++ * bit of n1 is set) /\ (theleading quotient ++ * digit q1 = 1). ++ * ++ * This special case is necessary, not an ++ * optimization. (Shifts counts of W_TYPE_SIZE ++ * are undefined.) ++ */ ++ ++ n1 -= d0; ++ q1 = 1; ++ } else { ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd(q1, n1, n2, n1, d0); ++ } ++ ++ /* n1 != d0... */ ++ ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0 >> bm. */ ++ } ++ ++ if (rp != 0) { ++ rr.s.low = n0 >> bm; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ ++#endif /* UDIV_NEEDS_NORMALIZATION */ ++ ++ } else { ++ if (d1 > n1) { ++ /* 00 = nn / DD */ ++ ++ q0 = 0; ++ q1 = 0; ++ ++ /* Remainder in n1n0. */ ++ if (rp != 0) { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } else { ++ /* 0q = NN / dd */ ++ ++ count_leading_zeros(bm, d1); ++ if (bm == 0) { ++ /* ++ * From (n1 >= d1) /\ (the most significant bit ++ * of d1 is set), conclude (the most significant ++ * bit of n1 is set) /\ (the quotient digit q0 = ++ * 0 or 1). ++ * ++ * This special case is necessary, not an ++ * optimization. ++ */ ++ ++ /* ++ * The condition on the next line takes ++ * advantage of that n1 >= d1 (true due to ++ * program flow). ++ */ ++ if (n1 > d1 || n0 >= d0) { ++ q0 = 1; ++ sub_ddmmss(n1, n0, n1, n0, d1, d0); ++ } else { ++ q0 = 0; ++ } ++ ++ q1 = 0; ++ ++ if (rp != 0) { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } else { ++ unsigned long m1, m0; ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d1 = (d1 << bm) | (d0 >> b); ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd(q0, n1, n2, n1, d1); ++ umul_ppmm(m1, m0, q0, d0); ++ ++ if (m1 > n1 || (m1 == n1 && m0 > n0)) { ++ q0--; ++ sub_ddmmss(m1, m0, m1, m0, d1, d0); ++ } ++ ++ q1 = 0; ++ ++ /* Remainder in (n1n0 - m1m0) >> bm. */ ++ if (rp != 0) { ++ sub_ddmmss(n1, n0, n1, n0, m1, m0); ++ rr.s.low = (n1 << b) | (n0 >> bm); ++ rr.s.high = n1 >> bm; ++ *rp = rr.ll; ++ } ++ } ++ } ++ } ++ ++ ww.s.low = q0; ++ ww.s.high = q1; ++ ++ return ww.ll; ++} +diff --git a/lib/umoddi3.c b/lib/umoddi3.c +new file mode 100644 +index 0000000..d7bbf0f +--- /dev/null ++++ b/lib/umoddi3.c +@@ -0,0 +1,32 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see the file COPYING, or write ++ * to the Free Software Foundation, Inc. ++ */ ++ ++#include ++#include ++ ++extern unsigned long long __udivmoddi4(unsigned long long u, ++ unsigned long long v, ++ unsigned long long *rp); ++ ++unsigned long long __umoddi3(unsigned long long u, unsigned long long v) ++{ ++ unsigned long long w; ++ (void)__udivmoddi4(u, v, &w); ++ return w; ++} ++EXPORT_SYMBOL(__umoddi3); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0009-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch b/target/linux/riscv64/patches-4.19/0009-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch new file mode 100644 index 0000000000..bc570ebc61 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0009-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch @@ -0,0 +1,28 @@ +From 757331db921428295948fed5e7377a436e66d34e Mon Sep 17 00:00:00 2001 +From: Zong Li +Date: Tue, 2 Oct 2018 16:52:30 +0800 +Subject: [PATCH 09/41] RISC-V: Select GENERIC_LIB_UMODDI3 on RV32 + +On 32-bit, it need to use __umoddi3 by some drivers. + +Signed-off-by: Zong Li +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index a344980..dc262fa 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -108,6 +108,7 @@ config ARCH_RV32I + select GENERIC_LIB_ASHRDI3 + select GENERIC_LIB_LSHRDI3 + select GENERIC_LIB_UCMPDI2 ++ select GENERIC_LIB_UMODDI3 + + config ARCH_RV64I + bool "RV64I" +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0010-RISC-V-Avoid-corrupting-the-upper-32-bit-of-phys_add.patch b/target/linux/riscv64/patches-4.19/0010-RISC-V-Avoid-corrupting-the-upper-32-bit-of-phys_add.patch new file mode 100644 index 0000000000..6bb58c4067 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0010-RISC-V-Avoid-corrupting-the-upper-32-bit-of-phys_add.patch @@ -0,0 +1,34 @@ +From 827a438156e4c423b6875a092e272933952a2910 Mon Sep 17 00:00:00 2001 +From: Vincent Chen +Date: Tue, 2 Oct 2018 16:52:31 +0800 +Subject: [PATCH 10/41] RISC-V: Avoid corrupting the upper 32-bit of + phys_addr_t in ioremap + +For 32bit, the upper 32-bit of phys_addr_t will be flushed to zero +after AND with PAGE_MASK because the data type of PAGE_MASK is +unsigned long. To fix this problem, the page alignment is done by +subtracting the page offset instead of AND with PAGE_MASK. + +Signed-off-by: Vincent Chen +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/mm/ioremap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/mm/ioremap.c b/arch/riscv/mm/ioremap.c +index 70ef272..bd2f2db 100644 +--- a/arch/riscv/mm/ioremap.c ++++ b/arch/riscv/mm/ioremap.c +@@ -42,7 +42,7 @@ static void __iomem *__ioremap_caller(phys_addr_t addr, size_t size, + + /* Page-align mappings */ + offset = addr & (~PAGE_MASK); +- addr &= PAGE_MASK; ++ addr -= offset; + size = PAGE_ALIGN(size + offset); + + area = get_vm_area_caller(size, VM_IOREMAP, caller); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0011-RISC-V-No-need-to-pass-scause-as-arg-to-do_IRQ.patch b/target/linux/riscv64/patches-4.19/0011-RISC-V-No-need-to-pass-scause-as-arg-to-do_IRQ.patch new file mode 100644 index 0000000000..c915356a3f --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0011-RISC-V-No-need-to-pass-scause-as-arg-to-do_IRQ.patch @@ -0,0 +1,50 @@ +From 1ed4237ab616a05225e11d07bf42d5474deec905 Mon Sep 17 00:00:00 2001 +From: Anup Patel +Date: Tue, 2 Oct 2018 12:14:54 -0700 +Subject: [PATCH 11/41] RISC-V: No need to pass scause as arg to do_IRQ() + +The scause is already part of pt_regs so no need to pass +scause as separate arg to do_IRQ(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Anup Patel +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/entry.S | 1 - + arch/riscv/kernel/irq.c | 4 ++-- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S +index fa2c08e..6eaacfa 100644 +--- a/arch/riscv/kernel/entry.S ++++ b/arch/riscv/kernel/entry.S +@@ -168,7 +168,6 @@ ENTRY(handle_exception) + + /* Handle interrupts */ + move a0, sp /* pt_regs */ +- move a1, s4 /* scause */ + tail do_IRQ + 1: + /* Exceptions run with interrupts enabled */ +diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c +index 0cfac48..ca45933 100644 +--- a/arch/riscv/kernel/irq.c ++++ b/arch/riscv/kernel/irq.c +@@ -24,12 +24,12 @@ + */ + #define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) + +-asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs, unsigned long cause) ++asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs) + { + struct pt_regs *old_regs = set_irq_regs(regs); + + irq_enter(); +- switch (cause & ~INTERRUPT_CAUSE_FLAG) { ++ switch (regs->scause & ~INTERRUPT_CAUSE_FLAG) { + case INTERRUPT_CAUSE_TIMER: + riscv_timer_interrupt(); + break; +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0012-RISC-V-Don-t-set-cacheinfo.-physical_line_partition-.patch b/target/linux/riscv64/patches-4.19/0012-RISC-V-Don-t-set-cacheinfo.-physical_line_partition-.patch new file mode 100644 index 0000000000..7463de2bce --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0012-RISC-V-Don-t-set-cacheinfo.-physical_line_partition-.patch @@ -0,0 +1,40 @@ +From 566d6c428eadf9dc06df8b2195dff58d9a97c9e6 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:14:55 -0700 +Subject: [PATCH 12/41] RISC-V: Don't set + cacheinfo.{physical_line_partition,attributes} + +These are just hard coded in the RISC-V port, which doesn't make any +sense. We should probably be setting these from device tree entries +when they exist, but for now I think it's saner to just leave them all +as their default values. + +Signed-off-by: Palmer Dabbelt +Reviewed-by: Christoph Hellwig +Reviewed-by: Jeremy Linton +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/cacheinfo.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/arch/riscv/kernel/cacheinfo.c b/arch/riscv/kernel/cacheinfo.c +index 0bc86e5..cb35ffd 100644 +--- a/arch/riscv/kernel/cacheinfo.c ++++ b/arch/riscv/kernel/cacheinfo.c +@@ -22,13 +22,6 @@ static void ci_leaf_init(struct cacheinfo *this_leaf, + { + this_leaf->level = level; + this_leaf->type = type; +- /* not a sector cache */ +- this_leaf->physical_line_partition = 1; +- /* TODO: Add to DTS */ +- this_leaf->attributes = +- CACHE_WRITE_BACK +- | CACHE_READ_ALLOCATE +- | CACHE_WRITE_ALLOCATE; + } + + static int __init_cache_level(unsigned int cpu) +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0013-RISC-V-Filter-ISA-and-MMU-values-in-cpuinfo.patch b/target/linux/riscv64/patches-4.19/0013-RISC-V-Filter-ISA-and-MMU-values-in-cpuinfo.patch new file mode 100644 index 0000000000..19c12e0299 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0013-RISC-V-Filter-ISA-and-MMU-values-in-cpuinfo.patch @@ -0,0 +1,107 @@ +From 19ccf29bb18f08a4583aa899a8cc8c11e5ea85a6 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:14:56 -0700 +Subject: [PATCH 13/41] RISC-V: Filter ISA and MMU values in cpuinfo + +We shouldn't be directly passing device tree values to userspace, both +because there could be mistakes in device trees and because the kernel +doesn't support arbitrary ISAs. + +Signed-off-by: Palmer Dabbelt +[Atish: checkpatch fix and code comment formatting update] +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/cpu.c | 68 ++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 61 insertions(+), 7 deletions(-) + +diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c +index ca6c81e..1c0bf66 100644 +--- a/arch/riscv/kernel/cpu.c ++++ b/arch/riscv/kernel/cpu.c +@@ -58,6 +58,63 @@ int riscv_of_processor_hart(struct device_node *node) + + #ifdef CONFIG_PROC_FS + ++static void print_isa(struct seq_file *f, const char *orig_isa) ++{ ++ static const char *ext = "mafdc"; ++ const char *isa = orig_isa; ++ const char *e; ++ ++ /* ++ * Linux doesn't support rv32e or rv128i, and we only support booting ++ * kernels on harts with the same ISA that the kernel is compiled for. ++ */ ++#if defined(CONFIG_32BIT) ++ if (strncmp(isa, "rv32i", 5) != 0) ++ return; ++#elif defined(CONFIG_64BIT) ++ if (strncmp(isa, "rv64i", 5) != 0) ++ return; ++#endif ++ ++ /* Print the base ISA, as we already know it's legal. */ ++ seq_puts(f, "isa\t: "); ++ seq_write(f, isa, 5); ++ isa += 5; ++ ++ /* ++ * Check the rest of the ISA string for valid extensions, printing those ++ * we find. RISC-V ISA strings define an order, so we only print the ++ * extension bits when they're in order. ++ */ ++ for (e = ext; *e != '\0'; ++e) { ++ if (isa[0] == e[0]) { ++ seq_write(f, isa, 1); ++ isa++; ++ } ++ } ++ ++ /* ++ * If we were given an unsupported ISA in the device tree then print ++ * a bit of info describing what went wrong. ++ */ ++ if (isa[0] != '\0') ++ pr_info("unsupported ISA \"%s\" in device tree", orig_isa); ++} ++ ++static void print_mmu(struct seq_file *f, const char *mmu_type) ++{ ++#if defined(CONFIG_32BIT) ++ if (strcmp(mmu_type, "riscv,sv32") != 0) ++ return; ++#elif defined(CONFIG_64BIT) ++ if (strcmp(mmu_type, "riscv,sv39") != 0 && ++ strcmp(mmu_type, "riscv,sv48") != 0) ++ return; ++#endif ++ ++ seq_printf(f, "mmu\t: %s\n", mmu_type+6); ++} ++ + static void *c_start(struct seq_file *m, loff_t *pos) + { + *pos = cpumask_next(*pos - 1, cpu_online_mask); +@@ -83,13 +140,10 @@ static int c_show(struct seq_file *m, void *v) + const char *compat, *isa, *mmu; + + seq_printf(m, "hart\t: %lu\n", hart_id); +- if (!of_property_read_string(node, "riscv,isa", &isa) +- && isa[0] == 'r' +- && isa[1] == 'v') +- seq_printf(m, "isa\t: %s\n", isa); +- if (!of_property_read_string(node, "mmu-type", &mmu) +- && !strncmp(mmu, "riscv,", 6)) +- seq_printf(m, "mmu\t: %s\n", mmu+6); ++ if (!of_property_read_string(node, "riscv,isa", &isa)) ++ print_isa(m, isa); ++ if (!of_property_read_string(node, "mmu-type", &mmu)) ++ print_mmu(m, mmu); + if (!of_property_read_string(node, "compatible", &compat) + && strcmp(compat, "riscv")) + seq_printf(m, "uarch\t: %s\n", compat); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0014-RISC-V-Comment-on-the-TLB-flush-in-smp_callin.patch b/target/linux/riscv64/patches-4.19/0014-RISC-V-Comment-on-the-TLB-flush-in-smp_callin.patch new file mode 100644 index 0000000000..e327975d8b --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0014-RISC-V-Comment-on-the-TLB-flush-in-smp_callin.patch @@ -0,0 +1,34 @@ +From b18d6f05252d6b3f725c08d8831a46b003df5b6b Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:14:57 -0700 +Subject: [PATCH 14/41] RISC-V: Comment on the TLB flush in smp_callin() + +This isn't readily apparent from reading the code. + +Signed-off-by: Palmer Dabbelt +[Atish: code comment formatting update] +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/smpboot.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 56abab6..712e9ca 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -106,6 +106,10 @@ asmlinkage void __init smp_callin(void) + trap_init(); + notify_cpu_starting(smp_processor_id()); + set_cpu_online(smp_processor_id(), 1); ++ /* ++ * Remote TLB flushes are ignored while the CPU is offline, so emit ++ * a local TLB flush right now just in case. ++ */ + local_flush_tlb_all(); + local_irq_enable(); + preempt_disable(); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0015-RISC-V-Disable-preemption-before-enabling-interrupts.patch b/target/linux/riscv64/patches-4.19/0015-RISC-V-Disable-preemption-before-enabling-interrupts.patch new file mode 100644 index 0000000000..fe0d8b7a96 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0015-RISC-V-Disable-preemption-before-enabling-interrupts.patch @@ -0,0 +1,38 @@ +From 6db170ff4c088caaf7806c00b29a55f6df07d7b6 Mon Sep 17 00:00:00 2001 +From: Atish Patra +Date: Tue, 2 Oct 2018 12:14:58 -0700 +Subject: [PATCH 15/41] RISC-V: Disable preemption before enabling interrupts + +Currently, irq is enabled before preemption disabling happens. +If the scheduler fired right here and cpu is scheduled then it +may blow up. + +Signed-off-by: Palmer Dabbelt +[Atish: Commit text and code comment formatting update] +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/smpboot.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 712e9ca..670749e 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -111,7 +111,11 @@ asmlinkage void __init smp_callin(void) + * a local TLB flush right now just in case. + */ + local_flush_tlb_all(); +- local_irq_enable(); ++ /* ++ * Disable preemption before enabling interrupts, so we don't try to ++ * schedule a CPU that hasn't actually started yet. ++ */ + preempt_disable(); ++ local_irq_enable(); + cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); + } +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0016-RISC-V-Provide-a-cleaner-raw_smp_processor_id.patch b/target/linux/riscv64/patches-4.19/0016-RISC-V-Provide-a-cleaner-raw_smp_processor_id.patch new file mode 100644 index 0000000000..8f9c856677 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0016-RISC-V-Provide-a-cleaner-raw_smp_processor_id.patch @@ -0,0 +1,55 @@ +From 9639a44394b9859a5576cb36630105733a552bd6 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:14:59 -0700 +Subject: [PATCH 16/41] RISC-V: Provide a cleaner raw_smp_processor_id() + +I'm not sure how I managed to miss this the first time, but this is much +better. + +Signed-off-by: Palmer Dabbelt +[Atish: code comment formatting and other fixes] +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/smp.h | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h +index 3601684..85d7619 100644 +--- a/arch/riscv/include/asm/smp.h ++++ b/arch/riscv/include/asm/smp.h +@@ -14,13 +14,9 @@ + #ifndef _ASM_RISCV_SMP_H + #define _ASM_RISCV_SMP_H + +-/* This both needs asm-offsets.h and is used when generating it. */ +-#ifndef GENERATING_ASM_OFFSETS +-#include +-#endif +- + #include + #include ++#include + + #ifdef CONFIG_SMP + +@@ -34,12 +30,10 @@ void arch_send_call_function_ipi_mask(struct cpumask *mask); + void arch_send_call_function_single_ipi(int cpu); + + /* +- * This is particularly ugly: it appears we can't actually get the definition +- * of task_struct here, but we need access to the CPU this task is running on. +- * Instead of using C we're using asm-offsets.h to get the current processor +- * ID. ++ * Obtains the hart ID of the currently executing task. This relies on ++ * THREAD_INFO_IN_TASK, but we define that unconditionally. + */ +-#define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU))) ++#define raw_smp_processor_id() (current_thread_info()->cpu) + + #endif /* CONFIG_SMP */ + +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0017-RISC-V-Rename-riscv_of_processor_hart-to-riscv_of_pr.patch b/target/linux/riscv64/patches-4.19/0017-RISC-V-Rename-riscv_of_processor_hart-to-riscv_of_pr.patch new file mode 100644 index 0000000000..197bde3052 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0017-RISC-V-Rename-riscv_of_processor_hart-to-riscv_of_pr.patch @@ -0,0 +1,97 @@ +From b2f8cfa7ac34202e5fd9551b6507fcd424634c1b Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:15:00 -0700 +Subject: [PATCH 17/41] RISC-V: Rename riscv_of_processor_hart to + riscv_of_processor_hartid + +It's a bit confusing exactly what this function does: it actually +returns the hartid of an OF processor node, failing with -1 on invalid +nodes. I've changed the name to _hartid() in order to make that a bit +more clear, as well as adding a comment. + +Signed-off-by: Palmer Dabbelt +[Atish: code comment formatting update] +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/processor.h | 2 +- + arch/riscv/kernel/cpu.c | 7 +++++-- + arch/riscv/kernel/smpboot.c | 2 +- + drivers/clocksource/riscv_timer.c | 2 +- + drivers/irqchip/irq-sifive-plic.c | 2 +- + 5 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h +index 3fe4af8..50de774 100644 +--- a/arch/riscv/include/asm/processor.h ++++ b/arch/riscv/include/asm/processor.h +@@ -88,7 +88,7 @@ static inline void wait_for_interrupt(void) + } + + struct device_node; +-extern int riscv_of_processor_hart(struct device_node *node); ++int riscv_of_processor_hartid(struct device_node *node); + + extern void riscv_fill_hwcap(void); + +diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c +index 1c0bf66..4723e23 100644 +--- a/arch/riscv/kernel/cpu.c ++++ b/arch/riscv/kernel/cpu.c +@@ -15,8 +15,11 @@ + #include + #include + +-/* Return -1 if not a valid hart */ +-int riscv_of_processor_hart(struct device_node *node) ++/* ++ * Returns the hart ID of the given device tree node, or -1 if the device tree ++ * node isn't a RISC-V hart. ++ */ ++int riscv_of_processor_hartid(struct device_node *node) + { + const char *isa, *status; + u32 hart; +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 670749e..cfb0b02 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -53,7 +53,7 @@ void __init setup_smp(void) + int hart, im_okay_therefore_i_am = 0; + + while ((dn = of_find_node_by_type(dn, "cpu"))) { +- hart = riscv_of_processor_hart(dn); ++ hart = riscv_of_processor_hartid(dn); + if (hart >= 0) { + set_cpu_possible(hart, true); + set_cpu_present(hart, true); +diff --git a/drivers/clocksource/riscv_timer.c b/drivers/clocksource/riscv_timer.c +index 4e8b347..ad7453f 100644 +--- a/drivers/clocksource/riscv_timer.c ++++ b/drivers/clocksource/riscv_timer.c +@@ -84,7 +84,7 @@ void riscv_timer_interrupt(void) + + static int __init riscv_timer_init_dt(struct device_node *n) + { +- int cpu_id = riscv_of_processor_hart(n), error; ++ int cpu_id = riscv_of_processor_hartid(n), error; + struct clocksource *cs; + + if (cpu_id != smp_processor_id()) +diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c +index 532e9d6..c55eaa3 100644 +--- a/drivers/irqchip/irq-sifive-plic.c ++++ b/drivers/irqchip/irq-sifive-plic.c +@@ -176,7 +176,7 @@ static int plic_find_hart_id(struct device_node *node) + { + for (; node; node = node->parent) { + if (of_device_is_compatible(node, "riscv")) +- return riscv_of_processor_hart(node); ++ return riscv_of_processor_hartid(node); + } + + return -1; +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0018-RISC-V-Rename-im_okay_therefore_i_am-to-found_boot_c.patch b/target/linux/riscv64/patches-4.19/0018-RISC-V-Rename-im_okay_therefore_i_am-to-found_boot_c.patch new file mode 100644 index 0000000000..9d1886cf69 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0018-RISC-V-Rename-im_okay_therefore_i_am-to-found_boot_c.patch @@ -0,0 +1,49 @@ +From 177fae4515889e2407810c5167a5227da8b37cce Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:15:01 -0700 +Subject: [PATCH 18/41] RISC-V: Rename im_okay_therefore_i_am to found_boot_cpu + +The old name was a bit odd. + +Signed-off-by: Palmer Dabbelt +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/smpboot.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index cfb0b02..4a23260 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -50,7 +50,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) + void __init setup_smp(void) + { + struct device_node *dn = NULL; +- int hart, im_okay_therefore_i_am = 0; ++ int hart; ++ bool found_boot_cpu = false; + + while ((dn = of_find_node_by_type(dn, "cpu"))) { + hart = riscv_of_processor_hartid(dn); +@@ -58,13 +59,13 @@ void __init setup_smp(void) + set_cpu_possible(hart, true); + set_cpu_present(hart, true); + if (hart == smp_processor_id()) { +- BUG_ON(im_okay_therefore_i_am); +- im_okay_therefore_i_am = 1; ++ BUG_ON(found_boot_cpu); ++ found_boot_cpu = true; + } + } + } + +- BUG_ON(!im_okay_therefore_i_am); ++ BUG_ON(!found_boot_cpu); + } + + int __cpu_up(unsigned int cpu, struct task_struct *tidle) +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0019-RISC-V-Use-mmgrab.patch b/target/linux/riscv64/patches-4.19/0019-RISC-V-Use-mmgrab.patch new file mode 100644 index 0000000000..c6425cc008 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0019-RISC-V-Use-mmgrab.patch @@ -0,0 +1,40 @@ +From 46373cb442c56d2f8a4c8b3f777c89d20546c9d5 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Tue, 2 Oct 2018 12:15:02 -0700 +Subject: [PATCH 19/41] RISC-V: Use mmgrab() + +commit f1f1007644ff ("mm: add new mmgrab() helper") added a +helper that we missed out on. + +Signed-off-by: Palmer Dabbelt +Reviewed-by: Christoph Hellwig +Signed-off-by: Atish Patra +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/smpboot.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 4a23260..17e7483 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -101,7 +102,7 @@ asmlinkage void __init smp_callin(void) + struct mm_struct *mm = &init_mm; + + /* All kernel threads share the same mm context. */ +- atomic_inc(&mm->mm_count); ++ mmgrab(mm); + current->active_mm = mm; + + trap_init(); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0020-RISC-V-Use-WRITE_ONCE-instead-of-direct-access.patch b/target/linux/riscv64/patches-4.19/0020-RISC-V-Use-WRITE_ONCE-instead-of-direct-access.patch new file mode 100644 index 0000000000..ec7ad2d8c9 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0020-RISC-V-Use-WRITE_ONCE-instead-of-direct-access.patch @@ -0,0 +1,35 @@ +From a37d56fc401108f39dec9ba83ed923a453937a26 Mon Sep 17 00:00:00 2001 +From: Atish Patra +Date: Tue, 2 Oct 2018 12:15:03 -0700 +Subject: [PATCH 20/41] RISC-V: Use WRITE_ONCE instead of direct access + +The secondary harts spin on couple of per cpu variables until both of +these are non-zero so it's not necessary to have any ordering here. +However, WRITE_ONCE should be used to avoid tearing. + +Signed-off-by: Atish Patra +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/smpboot.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 17e7483..1e47861 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -81,8 +81,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) + * the spinning harts that they can continue the boot process. + */ + smp_mb(); +- __cpu_up_stack_pointer[cpu] = task_stack_page(tidle) + THREAD_SIZE; +- __cpu_up_task_pointer[cpu] = tidle; ++ WRITE_ONCE(__cpu_up_stack_pointer[cpu], ++ task_stack_page(tidle) + THREAD_SIZE); ++ WRITE_ONCE(__cpu_up_task_pointer[cpu], tidle); + + while (!cpu_online(cpu)) + cpu_relax(); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0021-RISC-V-Add-logical-CPU-indexing-for-RISC-V.patch b/target/linux/riscv64/patches-4.19/0021-RISC-V-Add-logical-CPU-indexing-for-RISC-V.patch new file mode 100644 index 0000000000..84bb8dd398 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0021-RISC-V-Add-logical-CPU-indexing-for-RISC-V.patch @@ -0,0 +1,121 @@ +From 6825c7a80f1863b975a00042abe140ea24813af2 Mon Sep 17 00:00:00 2001 +From: Atish Patra +Date: Tue, 2 Oct 2018 12:15:04 -0700 +Subject: [PATCH 21/41] RISC-V: Add logical CPU indexing for RISC-V + +Currently, both Linux CPU id and hart id are same. +This is not recommended as it will lead to discontinuous CPU +indexing in Linux. Moreover, kdump kernel will run from CPU0 +which would be absent if we follow existing scheme. + +Implement a logical mapping between Linux CPU id and hart +id to decouple these two. Always mark the boot processor as +CPU0 and all other CPUs get the logical CPU id based on their +booting order. + +Signed-off-by: Atish Patra +Reviewed-by: Anup Patel +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/smp.h | 24 +++++++++++++++++++++++- + arch/riscv/kernel/setup.c | 4 ++++ + arch/riscv/kernel/smp.c | 19 +++++++++++++++++++ + 3 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h +index 85d7619..47fd61df 100644 +--- a/arch/riscv/include/asm/smp.h ++++ b/arch/riscv/include/asm/smp.h +@@ -18,6 +18,13 @@ + #include + #include + ++#define INVALID_HARTID ULONG_MAX ++/* ++ * Mapping between linux logical cpu index and hartid. ++ */ ++extern unsigned long __cpuid_to_hartid_map[NR_CPUS]; ++#define cpuid_to_hartid_map(cpu) __cpuid_to_hartid_map[cpu] ++ + #ifdef CONFIG_SMP + + /* SMP initialization hook for setup_arch */ +@@ -29,12 +36,27 @@ void arch_send_call_function_ipi_mask(struct cpumask *mask); + /* Hook for the generic smp_call_function_single() routine. */ + void arch_send_call_function_single_ipi(int cpu); + ++int riscv_hartid_to_cpuid(int hartid); ++void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out); ++ + /* + * Obtains the hart ID of the currently executing task. This relies on + * THREAD_INFO_IN_TASK, but we define that unconditionally. + */ + #define raw_smp_processor_id() (current_thread_info()->cpu) + +-#endif /* CONFIG_SMP */ ++#else ++ ++static inline int riscv_hartid_to_cpuid(int hartid) ++{ ++ return 0; ++} + ++static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in, ++ struct cpumask *out) ++{ ++ cpumask_set_cpu(cpuid_to_hartid_map(0), out); ++} ++ ++#endif /* CONFIG_SMP */ + #endif /* _ASM_RISCV_SMP_H */ +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index b2d26d9..d5d8611 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -82,6 +82,10 @@ EXPORT_SYMBOL(empty_zero_page); + /* The lucky hart to first increment this variable will boot the other cores */ + atomic_t hart_lottery; + ++unsigned long __cpuid_to_hartid_map[NR_CPUS] = { ++ [0 ... NR_CPUS-1] = INVALID_HARTID ++}; ++ + #ifdef CONFIG_BLK_DEV_INITRD + static void __init setup_initrd(void) + { +diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c +index 906fe21..0bd4893 100644 +--- a/arch/riscv/kernel/smp.c ++++ b/arch/riscv/kernel/smp.c +@@ -38,7 +38,26 @@ enum ipi_message_type { + IPI_MAX + }; + ++int riscv_hartid_to_cpuid(int hartid) ++{ ++ int i = -1; ++ ++ for (i = 0; i < NR_CPUS; i++) ++ if (cpuid_to_hartid_map(i) == hartid) ++ return i; ++ ++ pr_err("Couldn't find cpu id for hartid [%d]\n", hartid); ++ BUG(); ++ return i; ++} + ++void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out) ++{ ++ int cpu; ++ ++ for_each_cpu(cpu, in) ++ cpumask_set_cpu(cpuid_to_hartid_map(cpu), out); ++} + /* Unsupported */ + int setup_profiling_timer(unsigned int multiplier) + { +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0022-RISC-V-Use-Linux-logical-CPU-number-instead-of-harti.patch b/target/linux/riscv64/patches-4.19/0022-RISC-V-Use-Linux-logical-CPU-number-instead-of-harti.patch new file mode 100644 index 0000000000..5ca9433b12 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0022-RISC-V-Use-Linux-logical-CPU-number-instead-of-harti.patch @@ -0,0 +1,322 @@ +From f99fb607fb2bc0d4ce6b9adb764c65e37f40a92b Mon Sep 17 00:00:00 2001 +From: Atish Patra +Date: Tue, 2 Oct 2018 12:15:05 -0700 +Subject: [PATCH 22/41] RISC-V: Use Linux logical CPU number instead of hartid + +Setup the cpu_logical_map during boot. Moreover, every SBI call +and PLIC context are based on the physical hartid. Use the logical +CPU to hartid mapping to pass correct hartid to respective functions. + +Signed-off-by: Atish Patra +Reviewed-by: Anup Patel +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/tlbflush.h | 16 +++++++++++++--- + arch/riscv/kernel/cpu.c | 8 +++++--- + arch/riscv/kernel/head.S | 4 +++- + arch/riscv/kernel/setup.c | 6 ++++++ + arch/riscv/kernel/smp.c | 24 +++++++++++++++--------- + arch/riscv/kernel/smpboot.c | 25 ++++++++++++++++--------- + drivers/clocksource/riscv_timer.c | 12 ++++++++---- + drivers/irqchip/irq-sifive-plic.c | 8 +++++--- + 8 files changed, 71 insertions(+), 32 deletions(-) + +diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h +index 85c2d8b..54fee0c 100644 +--- a/arch/riscv/include/asm/tlbflush.h ++++ b/arch/riscv/include/asm/tlbflush.h +@@ -16,6 +16,7 @@ + #define _ASM_RISCV_TLBFLUSH_H + + #include ++#include + + /* + * Flush entire local TLB. 'sfence.vma' implicitly fences with the instruction +@@ -49,13 +50,22 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, + + #include + ++static inline void remote_sfence_vma(struct cpumask *cmask, unsigned long start, ++ unsigned long size) ++{ ++ struct cpumask hmask; ++ ++ cpumask_clear(&hmask); ++ riscv_cpuid_to_hartid_mask(cmask, &hmask); ++ sbi_remote_sfence_vma(hmask.bits, start, size); ++} ++ + #define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1) + #define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0) + #define flush_tlb_range(vma, start, end) \ +- sbi_remote_sfence_vma(mm_cpumask((vma)->vm_mm)->bits, \ +- start, (end) - (start)) ++ remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start)) + #define flush_tlb_mm(mm) \ +- sbi_remote_sfence_vma(mm_cpumask(mm)->bits, 0, -1) ++ remote_sfence_vma(mm_cpumask(mm), 0, -1) + + #endif /* CONFIG_SMP */ + +diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c +index 4723e23..cccc6f6 100644 +--- a/arch/riscv/kernel/cpu.c ++++ b/arch/riscv/kernel/cpu.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + /* + * Returns the hart ID of the given device tree node, or -1 if the device tree +@@ -138,11 +139,12 @@ static void c_stop(struct seq_file *m, void *v) + + static int c_show(struct seq_file *m, void *v) + { +- unsigned long hart_id = (unsigned long)v - 1; +- struct device_node *node = of_get_cpu_node(hart_id, NULL); ++ unsigned long cpu_id = (unsigned long)v - 1; ++ struct device_node *node = of_get_cpu_node(cpuid_to_hartid_map(cpu_id), ++ NULL); + const char *compat, *isa, *mmu; + +- seq_printf(m, "hart\t: %lu\n", hart_id); ++ seq_printf(m, "hart\t: %lu\n", cpu_id); + if (!of_property_read_string(node, "riscv,isa", &isa)) + print_isa(m, isa); + if (!of_property_read_string(node, "mmu-type", &mmu)) +diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S +index c4d2c63..711190d 100644 +--- a/arch/riscv/kernel/head.S ++++ b/arch/riscv/kernel/head.S +@@ -47,6 +47,8 @@ ENTRY(_start) + /* Save hart ID and DTB physical address */ + mv s0, a0 + mv s1, a1 ++ la a2, boot_cpu_hartid ++ REG_S a0, (a2) + + /* Initialize page tables and relocate to virtual addresses */ + la sp, init_thread_union + THREAD_SIZE +@@ -55,7 +57,7 @@ ENTRY(_start) + + /* Restore C environment */ + la tp, init_task +- sw s0, TASK_TI_CPU(tp) ++ sw zero, TASK_TI_CPU(tp) + + la sp, init_thread_union + li a0, ASM_THREAD_SIZE +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index d5d8611..5e9e6f9 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -81,11 +81,17 @@ EXPORT_SYMBOL(empty_zero_page); + + /* The lucky hart to first increment this variable will boot the other cores */ + atomic_t hart_lottery; ++unsigned long boot_cpu_hartid; + + unsigned long __cpuid_to_hartid_map[NR_CPUS] = { + [0 ... NR_CPUS-1] = INVALID_HARTID + }; + ++void __init smp_setup_processor_id(void) ++{ ++ cpuid_to_hartid_map(0) = boot_cpu_hartid; ++} ++ + #ifdef CONFIG_BLK_DEV_INITRD + static void __init setup_initrd(void) + { +diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c +index 0bd4893..4eac009 100644 +--- a/arch/riscv/kernel/smp.c ++++ b/arch/riscv/kernel/smp.c +@@ -97,14 +97,18 @@ void riscv_software_interrupt(void) + static void + send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) + { +- int i; ++ int cpuid, hartid; ++ struct cpumask hartid_mask; + ++ cpumask_clear(&hartid_mask); + mb(); +- for_each_cpu(i, to_whom) +- set_bit(operation, &ipi_data[i].bits); +- ++ for_each_cpu(cpuid, to_whom) { ++ set_bit(operation, &ipi_data[cpuid].bits); ++ hartid = cpuid_to_hartid_map(cpuid); ++ cpumask_set_cpu(hartid, &hartid_mask); ++ } + mb(); +- sbi_send_ipi(cpumask_bits(to_whom)); ++ sbi_send_ipi(cpumask_bits(&hartid_mask)); + } + + void arch_send_call_function_ipi_mask(struct cpumask *mask) +@@ -146,7 +150,7 @@ void smp_send_reschedule(int cpu) + void flush_icache_mm(struct mm_struct *mm, bool local) + { + unsigned int cpu; +- cpumask_t others, *mask; ++ cpumask_t others, hmask, *mask; + + preempt_disable(); + +@@ -164,9 +168,11 @@ void flush_icache_mm(struct mm_struct *mm, bool local) + */ + cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); + local |= cpumask_empty(&others); +- if (mm != current->active_mm || !local) +- sbi_remote_fence_i(others.bits); +- else { ++ if (mm != current->active_mm || !local) { ++ cpumask_clear(&hmask); ++ riscv_cpuid_to_hartid_mask(&others, &hmask); ++ sbi_remote_fence_i(hmask.bits); ++ } else { + /* + * It's assumed that at least one strongly ordered operation is + * performed on this hart between setting a hart's cpumask bit +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 1e47861..18cda0e 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -53,17 +53,23 @@ void __init setup_smp(void) + struct device_node *dn = NULL; + int hart; + bool found_boot_cpu = false; ++ int cpuid = 1; + + while ((dn = of_find_node_by_type(dn, "cpu"))) { + hart = riscv_of_processor_hartid(dn); +- if (hart >= 0) { +- set_cpu_possible(hart, true); +- set_cpu_present(hart, true); +- if (hart == smp_processor_id()) { +- BUG_ON(found_boot_cpu); +- found_boot_cpu = true; +- } ++ if (hart < 0) ++ continue; ++ ++ if (hart == cpuid_to_hartid_map(0)) { ++ BUG_ON(found_boot_cpu); ++ found_boot_cpu = 1; ++ continue; + } ++ ++ cpuid_to_hartid_map(cpuid) = hart; ++ set_cpu_possible(cpuid, true); ++ set_cpu_present(cpuid, true); ++ cpuid++; + } + + BUG_ON(!found_boot_cpu); +@@ -71,6 +77,7 @@ void __init setup_smp(void) + + int __cpu_up(unsigned int cpu, struct task_struct *tidle) + { ++ int hartid = cpuid_to_hartid_map(cpu); + tidle->thread_info.cpu = cpu; + + /* +@@ -81,9 +88,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) + * the spinning harts that they can continue the boot process. + */ + smp_mb(); +- WRITE_ONCE(__cpu_up_stack_pointer[cpu], ++ WRITE_ONCE(__cpu_up_stack_pointer[hartid], + task_stack_page(tidle) + THREAD_SIZE); +- WRITE_ONCE(__cpu_up_task_pointer[cpu], tidle); ++ WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle); + + while (!cpu_online(cpu)) + cpu_relax(); +diff --git a/drivers/clocksource/riscv_timer.c b/drivers/clocksource/riscv_timer.c +index ad7453f..084e97d 100644 +--- a/drivers/clocksource/riscv_timer.c ++++ b/drivers/clocksource/riscv_timer.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -84,13 +85,16 @@ void riscv_timer_interrupt(void) + + static int __init riscv_timer_init_dt(struct device_node *n) + { +- int cpu_id = riscv_of_processor_hartid(n), error; ++ int cpuid, hartid, error; + struct clocksource *cs; + +- if (cpu_id != smp_processor_id()) ++ hartid = riscv_of_processor_hartid(n); ++ cpuid = riscv_hartid_to_cpuid(hartid); ++ ++ if (cpuid != smp_processor_id()) + return 0; + +- cs = per_cpu_ptr(&riscv_clocksource, cpu_id); ++ cs = per_cpu_ptr(&riscv_clocksource, cpuid); + clocksource_register_hz(cs, riscv_timebase); + + error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING, +@@ -98,7 +102,7 @@ static int __init riscv_timer_init_dt(struct device_node *n) + riscv_timer_starting_cpu, riscv_timer_dying_cpu); + if (error) + pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", +- error, cpu_id); ++ error, cpuid); + return error; + } + +diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c +index c55eaa3..357e9da 100644 +--- a/drivers/irqchip/irq-sifive-plic.c ++++ b/drivers/irqchip/irq-sifive-plic.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + /* + * This driver implements a version of the RISC-V PLIC with the actual layout +@@ -218,7 +219,7 @@ static int __init plic_init(struct device_node *node, + struct of_phandle_args parent; + struct plic_handler *handler; + irq_hw_number_t hwirq; +- int cpu; ++ int cpu, hartid; + + if (of_irq_parse_one(node, i, &parent)) { + pr_err("failed to parse parent for context %d.\n", i); +@@ -229,12 +230,13 @@ static int __init plic_init(struct device_node *node, + if (parent.args[0] == -1) + continue; + +- cpu = plic_find_hart_id(parent.np); +- if (cpu < 0) { ++ hartid = plic_find_hart_id(parent.np); ++ if (hartid < 0) { + pr_warn("failed to parse hart ID for context %d.\n", i); + continue; + } + ++ cpu = riscv_hartid_to_cpuid(hartid); + handler = per_cpu_ptr(&plic_handlers, cpu); + handler->present = true; + handler->ctxid = i; +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0023-RISC-V-Show-CPU-ID-and-Hart-ID-separately-in-proc-cp.patch b/target/linux/riscv64/patches-4.19/0023-RISC-V-Show-CPU-ID-and-Hart-ID-separately-in-proc-cp.patch new file mode 100644 index 0000000000..2ef4e11e89 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0023-RISC-V-Show-CPU-ID-and-Hart-ID-separately-in-proc-cp.patch @@ -0,0 +1,89 @@ +From 4b26d22fdff1e39647cc5952b01d329e83dedfe1 Mon Sep 17 00:00:00 2001 +From: Anup Patel +Date: Tue, 2 Oct 2018 12:15:06 -0700 +Subject: [PATCH 23/41] RISC-V: Show CPU ID and Hart ID separately in + /proc/cpuinfo + +Currently, /proc/cpuinfo show logical CPU ID as Hart ID which +is in-correct. This patch shows CPU ID and Hart ID separately +in /proc/cpuinfo using cpuid_to_hardid_map(). + +With this patch, contents of /proc/cpuinfo looks as follows: +processor : 0 +hart : 1 +isa : rv64imafdc +mmu : sv48 + +processor : 1 +hart : 0 +isa : rv64imafdc +mmu : sv48 + +processor : 2 +hart : 2 +isa : rv64imafdc +mmu : sv48 + +processor : 3 +hart : 3 +isa : rv64imafdc +mmu : sv48 + +Signed-off-by: Anup Patel +Signed-off-by: Atish Patra +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/cpu.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c +index cccc6f6..3a5a2ee 100644 +--- a/arch/riscv/kernel/cpu.c ++++ b/arch/riscv/kernel/cpu.c +@@ -81,7 +81,7 @@ static void print_isa(struct seq_file *f, const char *orig_isa) + #endif + + /* Print the base ISA, as we already know it's legal. */ +- seq_puts(f, "isa\t: "); ++ seq_puts(f, "isa\t\t: "); + seq_write(f, isa, 5); + isa += 5; + +@@ -96,6 +96,7 @@ static void print_isa(struct seq_file *f, const char *orig_isa) + isa++; + } + } ++ seq_puts(f, "\n"); + + /* + * If we were given an unsupported ISA in the device tree then print +@@ -116,7 +117,7 @@ static void print_mmu(struct seq_file *f, const char *mmu_type) + return; + #endif + +- seq_printf(f, "mmu\t: %s\n", mmu_type+6); ++ seq_printf(f, "mmu\t\t: %s\n", mmu_type+6); + } + + static void *c_start(struct seq_file *m, loff_t *pos) +@@ -144,14 +145,15 @@ static int c_show(struct seq_file *m, void *v) + NULL); + const char *compat, *isa, *mmu; + +- seq_printf(m, "hart\t: %lu\n", cpu_id); ++ seq_printf(m, "processor\t: %lu\n", cpu_id); ++ seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id)); + if (!of_property_read_string(node, "riscv,isa", &isa)) + print_isa(m, isa); + if (!of_property_read_string(node, "mmu-type", &mmu)) + print_mmu(m, mmu); + if (!of_property_read_string(node, "compatible", &compat) + && strcmp(compat, "riscv")) +- seq_printf(m, "uarch\t: %s\n", compat); ++ seq_printf(m, "uarch\t\t: %s\n", compat); + seq_puts(m, "\n"); + + return 0; +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0024-RISC-V-Show-IPI-stats.patch b/target/linux/riscv64/patches-4.19/0024-RISC-V-Show-IPI-stats.patch new file mode 100644 index 0000000000..460d373728 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0024-RISC-V-Show-IPI-stats.patch @@ -0,0 +1,178 @@ +From 8b20d2db0a6d2761e0fc156eb74f7a55b92b3147 Mon Sep 17 00:00:00 2001 +From: Anup Patel +Date: Tue, 2 Oct 2018 12:15:07 -0700 +Subject: [PATCH 24/41] RISC-V: Show IPI stats + +This patch provides arch_show_interrupts() implementation to +show IPI stats via /proc/interrupts. + +Now the contents of /proc/interrupts" will look like below: + CPU0 CPU1 CPU2 CPU3 + 8: 17 7 6 14 SiFive PLIC 8 virtio0 + 10: 10 10 9 11 SiFive PLIC 10 ttyS0 +IPI0: 170 673 251 79 Rescheduling interrupts +IPI1: 1 12 27 1 Function call interrupts + +Signed-off-by: Anup Patel +[Atish - Fixed checkpatch errors] +Signed-off-by: Atish Patra +Reviewed-by: Palmer Dabbelt + +Changes since v2: + - Remove use of IPI_CALL_WAKEUP because it's being removed + +Changes since v1: + - Add stub inline show_ipi_stats() function for !CONFIG_SMP + - Make ipi_names[] dynamically sized at compile time + - Minor beautification of ipi_names[] using tabs + +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/smp.h | 9 +++++++++ + arch/riscv/kernel/irq.c | 8 ++++++++ + arch/riscv/kernel/smp.c | 39 ++++++++++++++++++++++++++++++++------- + 3 files changed, 49 insertions(+), 7 deletions(-) + +diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h +index 47fd61df..41aa73b 100644 +--- a/arch/riscv/include/asm/smp.h ++++ b/arch/riscv/include/asm/smp.h +@@ -25,8 +25,13 @@ + extern unsigned long __cpuid_to_hartid_map[NR_CPUS]; + #define cpuid_to_hartid_map(cpu) __cpuid_to_hartid_map[cpu] + ++struct seq_file; ++ + #ifdef CONFIG_SMP + ++/* print IPI stats */ ++void show_ipi_stats(struct seq_file *p, int prec); ++ + /* SMP initialization hook for setup_arch */ + void __init setup_smp(void); + +@@ -47,6 +52,10 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out); + + #else + ++static inline void show_ipi_stats(struct seq_file *p, int prec) ++{ ++} ++ + static inline int riscv_hartid_to_cpuid(int hartid) + { + return 0; +diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c +index ca45933..48e6b7d 100644 +--- a/arch/riscv/kernel/irq.c ++++ b/arch/riscv/kernel/irq.c +@@ -8,6 +8,8 @@ + #include + #include + #include ++#include ++#include + + /* + * Possible interrupt causes: +@@ -24,6 +26,12 @@ + */ + #define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) + ++int arch_show_interrupts(struct seq_file *p, int prec) ++{ ++ show_ipi_stats(p, prec); ++ return 0; ++} ++ + asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs) + { + struct pt_regs *old_regs = set_irq_regs(regs); +diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c +index 4eac009..57b1383 100644 +--- a/arch/riscv/kernel/smp.c ++++ b/arch/riscv/kernel/smp.c +@@ -22,22 +22,24 @@ + #include + #include + #include ++#include + + #include + #include + #include + +-/* A collection of single bit ipi messages. */ +-static struct { +- unsigned long bits ____cacheline_aligned; +-} ipi_data[NR_CPUS] __cacheline_aligned; +- + enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_MAX + }; + ++/* A collection of single bit ipi messages. */ ++static struct { ++ unsigned long stats[IPI_MAX] ____cacheline_aligned; ++ unsigned long bits ____cacheline_aligned; ++} ipi_data[NR_CPUS] __cacheline_aligned; ++ + int riscv_hartid_to_cpuid(int hartid) + { + int i = -1; +@@ -67,6 +69,7 @@ int setup_profiling_timer(unsigned int multiplier) + void riscv_software_interrupt(void) + { + unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; ++ unsigned long *stats = ipi_data[smp_processor_id()].stats; + + /* Clear pending IPI */ + csr_clear(sip, SIE_SSIE); +@@ -81,11 +84,15 @@ void riscv_software_interrupt(void) + if (ops == 0) + return; + +- if (ops & (1 << IPI_RESCHEDULE)) ++ if (ops & (1 << IPI_RESCHEDULE)) { ++ stats[IPI_RESCHEDULE]++; + scheduler_ipi(); ++ } + +- if (ops & (1 << IPI_CALL_FUNC)) ++ if (ops & (1 << IPI_CALL_FUNC)) { ++ stats[IPI_CALL_FUNC]++; + generic_smp_call_function_interrupt(); ++ } + + BUG_ON((ops >> IPI_MAX) != 0); + +@@ -111,6 +118,24 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) + sbi_send_ipi(cpumask_bits(&hartid_mask)); + } + ++static const char * const ipi_names[] = { ++ [IPI_RESCHEDULE] = "Rescheduling interrupts", ++ [IPI_CALL_FUNC] = "Function call interrupts", ++}; ++ ++void show_ipi_stats(struct seq_file *p, int prec) ++{ ++ unsigned int cpu, i; ++ ++ for (i = 0; i < IPI_MAX; i++) { ++ seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, ++ prec >= 4 ? " " : ""); ++ for_each_online_cpu(cpu) ++ seq_printf(p, "%10lu ", ipi_data[cpu].stats[i]); ++ seq_printf(p, " %s\n", ipi_names[i]); ++ } ++} ++ + void arch_send_call_function_ipi_mask(struct cpumask *mask) + { + send_ipi_message(mask, IPI_CALL_FUNC); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0026-RISC-V-Mask-out-the-F-extension-on-systems-without-D.patch b/target/linux/riscv64/patches-4.19/0026-RISC-V-Mask-out-the-F-extension-on-systems-without-D.patch new file mode 100644 index 0000000000..f64619662f --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0026-RISC-V-Mask-out-the-F-extension-on-systems-without-D.patch @@ -0,0 +1,43 @@ +From 86e581e310785782e2025a076dc9a3f5138e5bf3 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Mon, 27 Aug 2018 14:42:53 -0700 +Subject: [PATCH 26/41] RISC-V: Mask out the F extension on systems without D + +The RISC-V Linux port doesn't support systems that have the F extension +but don't have the D extension -- we actually don't support systems +without D either, but Alan's patch set is rectifying that soon. For now +I think we can leave this in a semi-broken state and just wait for +Alan's patch set to get merged for proper non-FPU support -- the patch +set is starting to look good, so doing something in-between doesn't seem +like it's worth the work. + +I don't think it's worth fretting about support for systems with F but +not D for now: our glibc ABIs are IMAC and IMAFDC so they probably won't +end up being popular. We can always extend this in the future. + +CC: Alan Kao +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/cpufeature.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c +index 17011a8..652d102 100644 +--- a/arch/riscv/kernel/cpufeature.c ++++ b/arch/riscv/kernel/cpufeature.c +@@ -57,5 +57,12 @@ void riscv_fill_hwcap(void) + for (i = 0; i < strlen(isa); ++i) + elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; + ++ /* We don't support systems with F but without D, so mask those out ++ * here. */ ++ if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) { ++ pr_info("This kernel does not support systems with F but not D"); ++ elf_hwcap &= ~COMPAT_HWCAP_ISA_F; ++ } ++ + pr_info("elf_hwcap is 0x%lx", elf_hwcap); + } +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0027-RISC-V-Add-FP-register-ptrace-support-for-gdb.patch b/target/linux/riscv64/patches-4.19/0027-RISC-V-Add-FP-register-ptrace-support-for-gdb.patch new file mode 100644 index 0000000000..0c0e5231be --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0027-RISC-V-Add-FP-register-ptrace-support-for-gdb.patch @@ -0,0 +1,112 @@ +From b8c8a9590e4fde82f8c3ee06a521763e6f21e9c8 Mon Sep 17 00:00:00 2001 +From: Jim Wilson +Date: Wed, 17 Oct 2018 17:59:05 -0700 +Subject: [PATCH 27/41] RISC-V: Add FP register ptrace support for gdb. + +Add a variable and a macro to describe FP registers, assuming only D is +supported. FP code is conditional on CONFIG_FPU. The FP regs and FCSR +are copied separately to avoid copying struct padding. Tested by hand and +with the gdb testsuite. + +Signed-off-by: Jim Wilson +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/uapi/asm/elf.h | 3 +++ + arch/riscv/kernel/ptrace.c | 52 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 55 insertions(+) + +diff --git a/arch/riscv/include/uapi/asm/elf.h b/arch/riscv/include/uapi/asm/elf.h +index 1e0dfc3..644a00c 100644 +--- a/arch/riscv/include/uapi/asm/elf.h ++++ b/arch/riscv/include/uapi/asm/elf.h +@@ -19,7 +19,10 @@ typedef unsigned long elf_greg_t; + typedef struct user_regs_struct elf_gregset_t; + #define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t)) + ++/* We don't support f without d, or q. */ ++typedef __u64 elf_fpreg_t; + typedef union __riscv_fp_state elf_fpregset_t; ++#define ELF_NFPREG (sizeof(struct __riscv_d_ext_state) / sizeof(elf_fpreg_t)) + + #if __riscv_xlen == 64 + #define ELF_RISCV_R_SYM(r_info) ELF64_R_SYM(r_info) +diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c +index 9f82a7e..60f1e02 100644 +--- a/arch/riscv/kernel/ptrace.c ++++ b/arch/riscv/kernel/ptrace.c +@@ -28,6 +28,9 @@ + + enum riscv_regset { + REGSET_X, ++#ifdef CONFIG_FPU ++ REGSET_F, ++#endif + }; + + static int riscv_gpr_get(struct task_struct *target, +@@ -54,6 +57,45 @@ static int riscv_gpr_set(struct task_struct *target, + return ret; + } + ++#ifdef CONFIG_FPU ++static int riscv_fpr_get(struct task_struct *target, ++ const struct user_regset *regset, ++ unsigned int pos, unsigned int count, ++ void *kbuf, void __user *ubuf) ++{ ++ int ret; ++ struct __riscv_d_ext_state *fstate = &target->thread.fstate; ++ ++ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0, ++ offsetof(struct __riscv_d_ext_state, fcsr)); ++ if (!ret) { ++ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0, ++ offsetof(struct __riscv_d_ext_state, fcsr) + ++ sizeof(fstate->fcsr)); ++ } ++ ++ return ret; ++} ++ ++static int riscv_fpr_set(struct task_struct *target, ++ const struct user_regset *regset, ++ unsigned int pos, unsigned int count, ++ const void *kbuf, const void __user *ubuf) ++{ ++ int ret; ++ struct __riscv_d_ext_state *fstate = &target->thread.fstate; ++ ++ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0, ++ offsetof(struct __riscv_d_ext_state, fcsr)); ++ if (!ret) { ++ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0, ++ offsetof(struct __riscv_d_ext_state, fcsr) + ++ sizeof(fstate->fcsr)); ++ } ++ ++ return ret; ++} ++#endif + + static const struct user_regset riscv_user_regset[] = { + [REGSET_X] = { +@@ -64,6 +106,16 @@ static const struct user_regset riscv_user_regset[] = { + .get = &riscv_gpr_get, + .set = &riscv_gpr_set, + }, ++#ifdef CONFIG_FPU ++ [REGSET_F] = { ++ .core_note_type = NT_PRFPREG, ++ .n = ELF_NFPREG, ++ .size = sizeof(elf_fpreg_t), ++ .align = sizeof(elf_fpreg_t), ++ .get = &riscv_fpr_get, ++ .set = &riscv_fpr_set, ++ }, ++#endif + }; + + static const struct user_regset_view riscv_user_native_view = { +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0028-RISC-V-Add-futex-support.patch b/target/linux/riscv64/patches-4.19/0028-RISC-V-Add-futex-support.patch new file mode 100644 index 0000000000..8d1ce58b04 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0028-RISC-V-Add-futex-support.patch @@ -0,0 +1,200 @@ +From b90edb33010bcfb9a0d74681be2cdd52300f1e69 Mon Sep 17 00:00:00 2001 +From: Jim Wilson +Date: Tue, 16 Oct 2018 14:42:59 -0700 +Subject: [PATCH 28/41] RISC-V: Add futex support. + +Here is an attempt to add the missing futex support. I started with the MIPS +version of futex.h and modified it until I got it working. I tested it on +a HiFive Unleashed running Fedora Core 29 using the fc29 4.15 version of the +kernel. This was tested against the glibc testsuite, where it fixes 14 nptl +related testsuite failures. That unfortunately only tests the cmpxchg support, +so I also used the testcase at the end of + + https://lwn.net/Articles/148830/ + +which tests the atomic_op functionality, except that it doesn't verify that +the operations are atomic, which they obviously are. This testcase runs +successfully with the patch and fails without it. + +I'm not a kernel expert, so there could be details I got wrong here. I wasn't +sure about the memory model support, so I used aqrl which seemed safest, and +didn't add fences which seemed unnecessary. I'm not sure about the copyright +statements, I left in Ralf Baechle's line because I started with his code. +Checkpatch reports some style problems, but it is the same style as the MIPS +futex.h, and the uses of ENOSYS appear correct even though it complains about +them. I don't know if any of that matters. + +This patch was tested on qemu with the glibc nptl/tst-cond-except +testcase, and the wake_op testcase from above. + +Signed-off-by: Jim Wilson +Reviewed-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Kconfig | 1 + + arch/riscv/include/asm/Kbuild | 1 - + arch/riscv/include/asm/futex.h | 128 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 129 insertions(+), 1 deletion(-) + create mode 100644 arch/riscv/include/asm/futex.h + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index a344980..093361e 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -31,6 +31,7 @@ config RISCV + select HAVE_MEMBLOCK + select HAVE_MEMBLOCK_NODE_MAP + select HAVE_DMA_CONTIGUOUS ++ select HAVE_FUTEX_CMPXCHG if FUTEX + select HAVE_GENERIC_DMA_COHERENT + select HAVE_PERF_EVENTS + select IRQ_DOMAIN +diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild +index efdbe31..6a646d9 100644 +--- a/arch/riscv/include/asm/Kbuild ++++ b/arch/riscv/include/asm/Kbuild +@@ -13,7 +13,6 @@ generic-y += errno.h + generic-y += exec.h + generic-y += fb.h + generic-y += fcntl.h +-generic-y += futex.h + generic-y += hardirq.h + generic-y += hash.h + generic-y += hw_irq.h +diff --git a/arch/riscv/include/asm/futex.h b/arch/riscv/include/asm/futex.h +new file mode 100644 +index 0000000..3b19eba +--- /dev/null ++++ b/arch/riscv/include/asm/futex.h +@@ -0,0 +1,128 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2006 Ralf Baechle (ralf@linux-mips.org) ++ * Copyright (c) 2018 Jim Wilson (jimw@sifive.com) ++ */ ++ ++#ifndef _ASM_FUTEX_H ++#define _ASM_FUTEX_H ++ ++#ifndef CONFIG_RISCV_ISA_A ++/* ++ * Use the generic interrupt disabling versions if the A extension ++ * is not supported. ++ */ ++#ifdef CONFIG_SMP ++#error "Can't support generic futex calls without A extension on SMP" ++#endif ++#include ++ ++#else /* CONFIG_RISCV_ISA_A */ ++ ++#include ++#include ++#include ++#include ++ ++#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ ++{ \ ++ uintptr_t tmp; \ ++ __enable_user_access(); \ ++ __asm__ __volatile__ ( \ ++ "1: " insn " \n" \ ++ "2: \n" \ ++ " .section .fixup,\"ax\" \n" \ ++ " .balign 4 \n" \ ++ "3: li %[r],%[e] \n" \ ++ " jump 2b,%[t] \n" \ ++ " .previous \n" \ ++ " .section __ex_table,\"a\" \n" \ ++ " .balign " RISCV_SZPTR " \n" \ ++ " " RISCV_PTR " 1b, 3b \n" \ ++ " .previous \n" \ ++ : [r] "+r" (ret), [ov] "=&r" (oldval), \ ++ [u] "+m" (*uaddr), [t] "=&r" (tmp) \ ++ : [op] "Jr" (oparg), [e] "i" (-EFAULT) \ ++ : "memory"); \ ++ __disable_user_access(); \ ++} ++ ++static inline int ++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) ++{ ++ int oldval = 0, ret = 0; ++ ++ pagefault_disable(); ++ ++ switch (op) { ++ case FUTEX_OP_SET: ++ __futex_atomic_op("amoswap.w.aqrl %[ov],%z[op],%[u]", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_ADD: ++ __futex_atomic_op("amoadd.w.aqrl %[ov],%z[op],%[u]", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_OR: ++ __futex_atomic_op("amoor.w.aqrl %[ov],%z[op],%[u]", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_ANDN: ++ __futex_atomic_op("amoand.w.aqrl %[ov],%z[op],%[u]", ++ ret, oldval, uaddr, ~oparg); ++ break; ++ case FUTEX_OP_XOR: ++ __futex_atomic_op("amoxor.w.aqrl %[ov],%z[op],%[u]", ++ ret, oldval, uaddr, oparg); ++ break; ++ default: ++ ret = -ENOSYS; ++ } ++ ++ pagefault_enable(); ++ ++ if (!ret) ++ *oval = oldval; ++ ++ return ret; ++} ++ ++static inline int ++futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, ++ u32 oldval, u32 newval) ++{ ++ int ret = 0; ++ u32 val; ++ uintptr_t tmp; ++ ++ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) ++ return -EFAULT; ++ ++ __enable_user_access(); ++ __asm__ __volatile__ ( ++ "1: lr.w.aqrl %[v],%[u] \n" ++ " bne %[v],%z[ov],3f \n" ++ "2: sc.w.aqrl %[t],%z[nv],%[u] \n" ++ " bnez %[t],1b \n" ++ "3: \n" ++ " .section .fixup,\"ax\" \n" ++ " .balign 4 \n" ++ "4: li %[r],%[e] \n" ++ " jump 3b,%[t] \n" ++ " .previous \n" ++ " .section __ex_table,\"a\" \n" ++ " .balign " RISCV_SZPTR " \n" ++ " " RISCV_PTR " 1b, 4b \n" ++ " " RISCV_PTR " 2b, 4b \n" ++ " .previous \n" ++ : [r] "+r" (ret), [v] "=&r" (val), [u] "+m" (*uaddr), [t] "=&r" (tmp) ++ : [ov] "Jr" (oldval), [nv] "Jr" (newval), [e] "i" (-EFAULT) ++ : "memory"); ++ __disable_user_access(); ++ ++ *uval = val; ++ return ret; ++} ++ ++#endif /* CONFIG_RISCV_ISA_A */ ++#endif /* _ASM_FUTEX_H */ +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0029-RISC-V-remove-the-unused-return_to_handler-export.patch b/target/linux/riscv64/patches-4.19/0029-RISC-V-remove-the-unused-return_to_handler-export.patch new file mode 100644 index 0000000000..6498e4794c --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0029-RISC-V-remove-the-unused-return_to_handler-export.patch @@ -0,0 +1,29 @@ +From f31b8de98853091e86a6391f9cd7948a2397287e Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Fri, 21 Sep 2018 08:43:21 +0200 +Subject: [PATCH 29/41] RISC-V: remove the unused return_to_handler export + +This export is not only not needed, but also breaks symbol versioning +due to being an undeclared assembly export. + +Signed-off-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/mcount.S | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S +index 5721624..8a5593f 100644 +--- a/arch/riscv/kernel/mcount.S ++++ b/arch/riscv/kernel/mcount.S +@@ -75,7 +75,6 @@ ENTRY(return_to_handler) + RESTORE_RET_ABI_STATE + jalr a1 + ENDPROC(return_to_handler) +-EXPORT_SYMBOL(return_to_handler) + #endif + + #ifndef CONFIG_DYNAMIC_FTRACE +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0030-riscv-move-GCC-version-check-for-ARCH_SUPPORTS_INT12.patch b/target/linux/riscv64/patches-4.19/0030-riscv-move-GCC-version-check-for-ARCH_SUPPORTS_INT12.patch new file mode 100644 index 0000000000..2166e9bfe5 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0030-riscv-move-GCC-version-check-for-ARCH_SUPPORTS_INT12.patch @@ -0,0 +1,43 @@ +From ee5928843a93c7d246bbe17c5eed95918ed0ddb1 Mon Sep 17 00:00:00 2001 +From: Masahiro Yamada +Date: Fri, 24 Aug 2018 17:33:53 +0900 +Subject: [PATCH 30/41] riscv: move GCC version check for ARCH_SUPPORTS_INT128 + to Kconfig + +This becomes much neater in Kconfig. + +Signed-off-by: Masahiro Yamada +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Kconfig | 1 + + arch/riscv/Makefile | 2 -- + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 093361e..bb80d3e 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -113,6 +113,7 @@ config ARCH_RV32I + config ARCH_RV64I + bool "RV64I" + select 64BIT ++ select ARCH_SUPPORTS_INT128 if GCC_VERSION >= 50000 + select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FTRACE_MCOUNT_RECORD +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index 61ec424..33700e4 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -25,8 +25,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) + + KBUILD_CFLAGS += -mabi=lp64 + KBUILD_AFLAGS += -mabi=lp64 +- +- KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0500, -DCONFIG_ARCH_SUPPORTS_INT128) + + KBUILD_MARCH = rv64im + KBUILD_LDFLAGS += -melf64lriscv +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0031-RISC-V-Cosmetic-menuconfig-changes.patch b/target/linux/riscv64/patches-4.19/0031-RISC-V-Cosmetic-menuconfig-changes.patch new file mode 100644 index 0000000000..d324ca518b --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0031-RISC-V-Cosmetic-menuconfig-changes.patch @@ -0,0 +1,119 @@ +From aef53f97b505ff94190ce3a06dcd0ded6cf5c0ca Mon Sep 17 00:00:00 2001 +From: Nick Kossifidis +Date: Thu, 20 Sep 2018 01:48:15 +0300 +Subject: [PATCH 31/41] RISC-V: Cosmetic menuconfig changes + +* Move the built-in cmdline configuration on a new menu entry "Boot + options", it doesn't make much sense to be part of the debuging menu. + +* Rename "Kernel Type" menu to "Kernel features" to be more consistent with + what other architectures are using, plus "type" is a bit misleading here. + +Signed-off-by: Nick Kossifidis +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Kconfig | 40 +++++++++++++++++++++++++++++++++++++++- + arch/riscv/Kconfig.debug | 35 ----------------------------------- + 2 files changed, 39 insertions(+), 36 deletions(-) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index bb80d3e..6c8329b 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -212,12 +212,50 @@ endmenu + + endmenu + +-menu "Kernel type" ++menu "Kernel features" + + source "kernel/Kconfig.hz" + + endmenu + ++menu "Boot options" ++ ++config CMDLINE_BOOL ++ bool "Built-in kernel command line" ++ help ++ For most platforms, it is firmware or second stage bootloader ++ that by default specifies the kernel command line options. ++ However, it might be necessary or advantageous to either override ++ the default kernel command line or add a few extra options to it. ++ For such cases, this option allows hardcoding command line options ++ directly into the kernel. ++ ++ For that, choose 'Y' here and fill in the extra boot parameters ++ in CONFIG_CMDLINE. ++ ++ The built-in options will be concatenated to the default command ++ line if CMDLINE_FORCE is set to 'N'. Otherwise, the default ++ command line will be ignored and replaced by the built-in string. ++ ++config CMDLINE ++ string "Built-in kernel command string" ++ depends on CMDLINE_BOOL ++ default "" ++ help ++ Supply command-line options at build time by entering them here. ++ ++config CMDLINE_FORCE ++ bool "Built-in command line overrides bootloader arguments" ++ depends on CMDLINE_BOOL ++ help ++ Set this option to 'Y' to have the kernel ignore the bootloader ++ or firmware command line. Instead, the built-in command line ++ will be used exclusively. ++ ++ If you don't know what to do here, say N. ++ ++endmenu ++ + menu "Bus support" + + config PCI +diff --git a/arch/riscv/Kconfig.debug b/arch/riscv/Kconfig.debug +index 3224ff6..c5a72f1 100644 +--- a/arch/riscv/Kconfig.debug ++++ b/arch/riscv/Kconfig.debug +@@ -1,37 +1,2 @@ +- +-config CMDLINE_BOOL +- bool "Built-in kernel command line" +- help +- For most platforms, it is firmware or second stage bootloader +- that by default specifies the kernel command line options. +- However, it might be necessary or advantageous to either override +- the default kernel command line or add a few extra options to it. +- For such cases, this option allows hardcoding command line options +- directly into the kernel. +- +- For that, choose 'Y' here and fill in the extra boot parameters +- in CONFIG_CMDLINE. +- +- The built-in options will be concatenated to the default command +- line if CMDLINE_FORCE is set to 'N'. Otherwise, the default +- command line will be ignored and replaced by the built-in string. +- +-config CMDLINE +- string "Built-in kernel command string" +- depends on CMDLINE_BOOL +- default "" +- help +- Supply command-line options at build time by entering them here. +- +-config CMDLINE_FORCE +- bool "Built-in command line overrides bootloader arguments" +- depends on CMDLINE_BOOL +- help +- Set this option to 'Y' to have the kernel ignore the bootloader +- or firmware command line. Instead, the built-in command line +- will be used exclusively. +- +- If you don't know what to do here, say N. +- + config EARLY_PRINTK + def_bool y +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0032-RISC-V-properly-determine-hardware-caps.patch b/target/linux/riscv64/patches-4.19/0032-RISC-V-properly-determine-hardware-caps.patch new file mode 100644 index 0000000000..107aa03f53 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0032-RISC-V-properly-determine-hardware-caps.patch @@ -0,0 +1,45 @@ +From a18d90df2e83a9891caa85a52ec3921d95915084 Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Tue, 23 Oct 2018 09:33:47 +0200 +Subject: [PATCH 32/41] RISC-V: properly determine hardware caps + +On the Hifive-U platform, cpu 0 is a masked cpu with less capabilities +than the other cpus. Ignore it for the purpose of determining the +hardware capabilities of the system. + +Signed-off-by: Andreas Schwab +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/kernel/cpufeature.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c +index 5493f32..0339087 100644 +--- a/arch/riscv/kernel/cpufeature.c ++++ b/arch/riscv/kernel/cpufeature.c +@@ -28,7 +28,7 @@ bool has_fpu __read_mostly; + + void riscv_fill_hwcap(void) + { +- struct device_node *node; ++ struct device_node *node = NULL; + const char *isa; + size_t i; + static unsigned long isa2hwcap[256] = {0}; +@@ -44,9 +44,11 @@ void riscv_fill_hwcap(void) + + /* + * We don't support running Linux on hertergenous ISA systems. For +- * now, we just check the ISA of the first processor. ++ * now, we just check the ISA of the first "okay" processor. + */ +- node = of_find_node_by_type(NULL, "cpu"); ++ while ((node = of_find_node_by_type(node, "cpu"))) ++ if (riscv_of_processor_hartid(node) >= 0) ++ break; + if (!node) { + pr_warning("Unable to find \"cpu\" devicetree entry"); + return; +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0033-Move-EM_RISCV-into-elf-em.h.patch b/target/linux/riscv64/patches-4.19/0033-Move-EM_RISCV-into-elf-em.h.patch new file mode 100644 index 0000000000..093b844c55 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0033-Move-EM_RISCV-into-elf-em.h.patch @@ -0,0 +1,47 @@ +From 4047c266cca93ba2bc24ca746f2ae267e2d6a9ca Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Mon, 25 Jun 2018 13:23:12 -0700 +Subject: [PATCH 33/41] Move EM_RISCV into elf-em.h + +This should never have been inside our arch port to begin with, it's +just a relic from when we were maintaining out of tree patches. + +Reviewed-by: Kees Cook +Reviewed-by: Paul Walmsley +Reviewed-by: Christoph Hellwig +Tested-by: David Abdurachmanov +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/elf.h | 3 --- + include/uapi/linux/elf-em.h | 1 + + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h +index a1ef503d..697fc23 100644 +--- a/arch/riscv/include/asm/elf.h ++++ b/arch/riscv/include/asm/elf.h +@@ -16,9 +16,6 @@ + #include + #include + +-/* TODO: Move definition into include/uapi/linux/elf-em.h */ +-#define EM_RISCV 0xF3 +- + /* + * These are used to set parameters in the core dumps. + */ +diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h +index 31aa101..93722e6 100644 +--- a/include/uapi/linux/elf-em.h ++++ b/include/uapi/linux/elf-em.h +@@ -41,6 +41,7 @@ + #define EM_TILEPRO 188 /* Tilera TILEPro */ + #define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ + #define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_RISCV 243 /* RISC-V */ + #define EM_BPF 247 /* Linux BPF - in-kernel virtual machine */ + #define EM_FRV 0x5441 /* Fujitsu FR-V */ + +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0034-Revert-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch b/target/linux/riscv64/patches-4.19/0034-Revert-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch new file mode 100644 index 0000000000..6f0c287c1c --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0034-Revert-RISC-V-Select-GENERIC_LIB_UMODDI3-on-RV32.patch @@ -0,0 +1,30 @@ +From 4f404f5ce99d06ffb33ea17995c953456b2d4362 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Fri, 26 Oct 2018 12:37:43 -0700 +Subject: [PATCH 34/41] Revert "RISC-V: Select GENERIC_LIB_UMODDI3 on RV32" + +I'm removing the generic 64-bit divide support, which means this will no +longer work. + +This reverts commit 757331db921428295948fed5e7377a436e66d34e. + +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index fe45134..4198759 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -109,7 +109,6 @@ config ARCH_RV32I + select GENERIC_LIB_ASHRDI3 + select GENERIC_LIB_LSHRDI3 + select GENERIC_LIB_UCMPDI2 +- select GENERIC_LIB_UMODDI3 + + config ARCH_RV64I + bool "RV64I" +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0035-Revert-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library.patch b/target/linux/riscv64/patches-4.19/0035-Revert-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library.patch new file mode 100644 index 0000000000..9087843995 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0035-Revert-lib-Add-umoddi3-and-udivmoddi4-of-GCC-library.patch @@ -0,0 +1,397 @@ +From 9d93e875aa5e097a580a5128b9c9590eaf572427 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Fri, 26 Oct 2018 12:38:11 -0700 +Subject: [PATCH 35/41] Revert "lib: Add umoddi3 and udivmoddi4 of GCC library + routines" + +We don't want 64-bit divide in the kernel. + +This reverts commit 6315730e9eab7de5fa9864bb13a352713f48aef1. + +Signed-off-by: Palmer Dabbelt +--- + lib/Kconfig | 3 - + lib/Makefile | 1 - + lib/udivmoddi4.c | 310 ------------------------------------------------------- + lib/umoddi3.c | 32 ------ + 4 files changed, 346 deletions(-) + delete mode 100644 lib/udivmoddi4.c + delete mode 100644 lib/umoddi3.c + +diff --git a/lib/Kconfig b/lib/Kconfig +index d82f206..a3928d4 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -621,6 +621,3 @@ config GENERIC_LIB_CMPDI2 + + config GENERIC_LIB_UCMPDI2 + bool +- +-config GENERIC_LIB_UMODDI3 +- bool +diff --git a/lib/Makefile b/lib/Makefile +index 56a8d9c..4238764 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -270,4 +270,3 @@ obj-$(CONFIG_GENERIC_LIB_LSHRDI3) += lshrdi3.o + obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o + obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o + obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o +-obj-$(CONFIG_GENERIC_LIB_UMODDI3) += umoddi3.o udivmoddi4.o +diff --git a/lib/udivmoddi4.c b/lib/udivmoddi4.c +deleted file mode 100644 +index c08bc8a..0000000 +--- a/lib/udivmoddi4.c ++++ /dev/null +@@ -1,310 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-/* +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see the file COPYING, or write +- * to the Free Software Foundation, Inc. +- */ +- +-#include +- +-#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz(X)) +- +-#define W_TYPE_SIZE 32 +- +-#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) +-#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) +-#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) +- +-/* If we still don't have umul_ppmm, define it using plain C. */ +-#if !defined(umul_ppmm) +-#define umul_ppmm(w1, w0, u, v) \ +- do { \ +- unsigned long __x0, __x1, __x2, __x3; \ +- unsigned short __ul, __vl, __uh, __vh; \ +- \ +- __ul = __ll_lowpart(u); \ +- __uh = __ll_highpart(u); \ +- __vl = __ll_lowpart(v); \ +- __vh = __ll_highpart(v); \ +- \ +- __x0 = (unsigned long) __ul * __vl; \ +- __x1 = (unsigned long) __ul * __vh; \ +- __x2 = (unsigned long) __uh * __vl; \ +- __x3 = (unsigned long) __uh * __vh; \ +- \ +- __x1 += __ll_highpart(__x0); \ +- __x1 += __x2; \ +- if (__x1 < __x2) \ +- __x3 += __ll_B; \ +- \ +- (w1) = __x3 + __ll_highpart(__x1); \ +- (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ +- } while (0) +-#endif +- +-#if !defined(sub_ddmmss) +-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ +- do { \ +- unsigned long __x; \ +- __x = (al) - (bl); \ +- (sh) = (ah) - (bh) - (__x > (al)); \ +- (sl) = __x; \ +- } while (0) +-#endif +- +-/* Define this unconditionally, so it can be used for debugging. */ +-#define __udiv_qrnnd_c(q, r, n1, n0, d) \ +- do { \ +- unsigned long __d1, __d0, __q1, __q0; \ +- unsigned long __r1, __r0, __m; \ +- __d1 = __ll_highpart(d); \ +- __d0 = __ll_lowpart(d); \ +- \ +- __r1 = (n1) % __d1; \ +- __q1 = (n1) / __d1; \ +- __m = (unsigned long) __q1 * __d0; \ +- __r1 = __r1 * __ll_B | __ll_highpart(n0); \ +- if (__r1 < __m) { \ +- __q1--, __r1 += (d); \ +- if (__r1 >= (d)) \ +- if (__r1 < __m) \ +- __q1--, __r1 += (d); \ +- } \ +- __r1 -= __m; \ +- \ +- __r0 = __r1 % __d1; \ +- __q0 = __r1 / __d1; \ +- __m = (unsigned long) __q0 * __d0; \ +- __r0 = __r0 * __ll_B | __ll_lowpart(n0); \ +- if (__r0 < __m) { \ +- __q0--, __r0 += (d); \ +- if (__r0 >= (d)) \ +- if (__r0 < __m) \ +- __q0--, __r0 += (d); \ +- } \ +- __r0 -= __m; \ +- \ +- (q) = (unsigned long) __q1 * __ll_B | __q0; \ +- (r) = __r0; \ +- } while (0) +- +-/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +-#if !defined(udiv_qrnnd) +-#define UDIV_NEEDS_NORMALIZATION 1 +-#define udiv_qrnnd __udiv_qrnnd_c +-#endif +- +-unsigned long long __udivmoddi4(unsigned long long u, unsigned long long v, +- unsigned long long *rp) +-{ +- const DWunion nn = {.ll = u }; +- const DWunion dd = {.ll = v }; +- DWunion rr, ww; +- unsigned long d0, d1, n0, n1, n2; +- unsigned long q0 = 0, q1 = 0; +- unsigned long b, bm; +- +- d0 = dd.s.low; +- d1 = dd.s.high; +- n0 = nn.s.low; +- n1 = nn.s.high; +- +-#if !UDIV_NEEDS_NORMALIZATION +- +- if (d1 == 0) { +- if (d0 > n1) { +- /* 0q = nn / 0D */ +- +- udiv_qrnnd(q0, n0, n1, n0, d0); +- q1 = 0; +- +- /* Remainder in n0. */ +- } else { +- /* qq = NN / 0d */ +- +- if (d0 == 0) +- /* Divide intentionally by zero. */ +- d0 = 1 / d0; +- +- udiv_qrnnd(q1, n1, 0, n1, d0); +- udiv_qrnnd(q0, n0, n1, n0, d0); +- +- /* Remainder in n0. */ +- } +- +- if (rp != 0) { +- rr.s.low = n0; +- rr.s.high = 0; +- *rp = rr.ll; +- } +- +-#else /* UDIV_NEEDS_NORMALIZATION */ +- +- if (d1 == 0) { +- if (d0 > n1) { +- /* 0q = nn / 0D */ +- +- count_leading_zeros(bm, d0); +- +- if (bm != 0) { +- /* +- * Normalize, i.e. make the most significant bit +- * of the denominator set. +- */ +- +- d0 = d0 << bm; +- n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); +- n0 = n0 << bm; +- } +- +- udiv_qrnnd(q0, n0, n1, n0, d0); +- q1 = 0; +- +- /* Remainder in n0 >> bm. */ +- } else { +- /* qq = NN / 0d */ +- +- if (d0 == 0) +- /* Divide intentionally by zero. */ +- d0 = 1 / d0; +- +- count_leading_zeros(bm, d0); +- +- if (bm == 0) { +- /* +- * From (n1 >= d0) /\ (the most significant bit +- * of d0 is set), conclude (the most significant +- * bit of n1 is set) /\ (theleading quotient +- * digit q1 = 1). +- * +- * This special case is necessary, not an +- * optimization. (Shifts counts of W_TYPE_SIZE +- * are undefined.) +- */ +- +- n1 -= d0; +- q1 = 1; +- } else { +- /* Normalize. */ +- +- b = W_TYPE_SIZE - bm; +- +- d0 = d0 << bm; +- n2 = n1 >> b; +- n1 = (n1 << bm) | (n0 >> b); +- n0 = n0 << bm; +- +- udiv_qrnnd(q1, n1, n2, n1, d0); +- } +- +- /* n1 != d0... */ +- +- udiv_qrnnd(q0, n0, n1, n0, d0); +- +- /* Remainder in n0 >> bm. */ +- } +- +- if (rp != 0) { +- rr.s.low = n0 >> bm; +- rr.s.high = 0; +- *rp = rr.ll; +- } +- +-#endif /* UDIV_NEEDS_NORMALIZATION */ +- +- } else { +- if (d1 > n1) { +- /* 00 = nn / DD */ +- +- q0 = 0; +- q1 = 0; +- +- /* Remainder in n1n0. */ +- if (rp != 0) { +- rr.s.low = n0; +- rr.s.high = n1; +- *rp = rr.ll; +- } +- } else { +- /* 0q = NN / dd */ +- +- count_leading_zeros(bm, d1); +- if (bm == 0) { +- /* +- * From (n1 >= d1) /\ (the most significant bit +- * of d1 is set), conclude (the most significant +- * bit of n1 is set) /\ (the quotient digit q0 = +- * 0 or 1). +- * +- * This special case is necessary, not an +- * optimization. +- */ +- +- /* +- * The condition on the next line takes +- * advantage of that n1 >= d1 (true due to +- * program flow). +- */ +- if (n1 > d1 || n0 >= d0) { +- q0 = 1; +- sub_ddmmss(n1, n0, n1, n0, d1, d0); +- } else { +- q0 = 0; +- } +- +- q1 = 0; +- +- if (rp != 0) { +- rr.s.low = n0; +- rr.s.high = n1; +- *rp = rr.ll; +- } +- } else { +- unsigned long m1, m0; +- /* Normalize. */ +- +- b = W_TYPE_SIZE - bm; +- +- d1 = (d1 << bm) | (d0 >> b); +- d0 = d0 << bm; +- n2 = n1 >> b; +- n1 = (n1 << bm) | (n0 >> b); +- n0 = n0 << bm; +- +- udiv_qrnnd(q0, n1, n2, n1, d1); +- umul_ppmm(m1, m0, q0, d0); +- +- if (m1 > n1 || (m1 == n1 && m0 > n0)) { +- q0--; +- sub_ddmmss(m1, m0, m1, m0, d1, d0); +- } +- +- q1 = 0; +- +- /* Remainder in (n1n0 - m1m0) >> bm. */ +- if (rp != 0) { +- sub_ddmmss(n1, n0, n1, n0, m1, m0); +- rr.s.low = (n1 << b) | (n0 >> bm); +- rr.s.high = n1 >> bm; +- *rp = rr.ll; +- } +- } +- } +- } +- +- ww.s.low = q0; +- ww.s.high = q1; +- +- return ww.ll; +-} +diff --git a/lib/umoddi3.c b/lib/umoddi3.c +deleted file mode 100644 +index d7bbf0f..0000000 +--- a/lib/umoddi3.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-/* +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see the file COPYING, or write +- * to the Free Software Foundation, Inc. +- */ +- +-#include +-#include +- +-extern unsigned long long __udivmoddi4(unsigned long long u, +- unsigned long long v, +- unsigned long long *rp); +- +-unsigned long long __umoddi3(unsigned long long u, unsigned long long v) +-{ +- unsigned long long w; +- (void)__udivmoddi4(u, v, &w); +- return w; +-} +-EXPORT_SYMBOL(__umoddi3); +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0036-RISC-V-refresh-defconfig.patch b/target/linux/riscv64/patches-4.19/0036-RISC-V-refresh-defconfig.patch new file mode 100644 index 0000000000..135cf678cb --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0036-RISC-V-refresh-defconfig.patch @@ -0,0 +1,64 @@ +From 8e5e5a02706aaf939589b792813b8c349cad55e9 Mon Sep 17 00:00:00 2001 +From: Anup Patel +Date: Thu, 1 Nov 2018 10:40:32 +0530 +Subject: [PATCH 36/41] RISC-V: refresh defconfig + +This patch updates defconfig using savedefconfig on Linux-4.19. It is +intended to have no functional change. + +Signed-off-by: Anup Patel +Reviewed-by: Palmer Dabbelt +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/configs/defconfig | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig +index 36473d7..07fa9ea 100644 +--- a/arch/riscv/configs/defconfig ++++ b/arch/riscv/configs/defconfig +@@ -1,6 +1,3 @@ +-CONFIG_SMP=y +-CONFIG_PCI=y +-CONFIG_PCIE_XILINX=y + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y + CONFIG_IKCONFIG=y +@@ -11,10 +8,15 @@ CONFIG_CFS_BANDWIDTH=y + CONFIG_CGROUP_BPF=y + CONFIG_NAMESPACES=y + CONFIG_USER_NS=y ++CONFIG_CHECKPOINT_RESTORE=y + CONFIG_BLK_DEV_INITRD=y + CONFIG_EXPERT=y +-CONFIG_CHECKPOINT_RESTORE=y + CONFIG_BPF_SYSCALL=y ++CONFIG_SMP=y ++CONFIG_PCI=y ++CONFIG_PCIE_XILINX=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y + CONFIG_NET=y + CONFIG_PACKET=y + CONFIG_UNIX=y +@@ -59,6 +61,7 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y + CONFIG_USB_STORAGE=y + CONFIG_USB_UAS=y + CONFIG_VIRTIO_MMIO=y ++CONFIG_SIFIVE_PLIC=y + CONFIG_RAS=y + CONFIG_EXT4_FS=y + CONFIG_EXT4_FS_POSIX_ACL=y +@@ -72,8 +75,5 @@ CONFIG_NFS_V4=y + CONFIG_NFS_V4_1=y + CONFIG_NFS_V4_2=y + CONFIG_ROOT_NFS=y +-# CONFIG_RCU_TRACE is not set + CONFIG_CRYPTO_USER_API_HASH=y +-CONFIG_MODULES=y +-CONFIG_MODULE_UNLOAD=y +-CONFIG_SIFIVE_PLIC=y ++# CONFIG_RCU_TRACE is not set +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0037-RISC-V-defconfig-Enable-printk-timestamps.patch b/target/linux/riscv64/patches-4.19/0037-RISC-V-defconfig-Enable-printk-timestamps.patch new file mode 100644 index 0000000000..fff11d1a01 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0037-RISC-V-defconfig-Enable-printk-timestamps.patch @@ -0,0 +1,33 @@ +From bbe098ce00a42eeff9fd94f6a0e12aada8ee1ef3 Mon Sep 17 00:00:00 2001 +From: Anup Patel +Date: Thu, 1 Nov 2018 10:40:33 +0530 +Subject: [PATCH 37/41] RISC-V: defconfig: Enable printk timestamps + +The printk timestamps are very useful information to visually see +where kernel is spending time during boot. It also helps us see +the timing of hotplug events at runtime. + +This patch enables printk timestamps in RISC-V defconfig so that +we have it enabled by default (similar to other architectures +such as x86_64, arm64, etc). + +Signed-off-by: Anup Patel +Acked-by: Olof Johansson +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/configs/defconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig +index 07fa9ea..ef4f15d 100644 +--- a/arch/riscv/configs/defconfig ++++ b/arch/riscv/configs/defconfig +@@ -76,4 +76,5 @@ CONFIG_NFS_V4_1=y + CONFIG_NFS_V4_2=y + CONFIG_ROOT_NFS=y + CONFIG_CRYPTO_USER_API_HASH=y ++CONFIG_PRINTK_TIME=y + # CONFIG_RCU_TRACE is not set +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0038-riscv-fix-spacing-in-struct-pt_regs.patch b/target/linux/riscv64/patches-4.19/0038-riscv-fix-spacing-in-struct-pt_regs.patch new file mode 100644 index 0000000000..500860833e --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0038-riscv-fix-spacing-in-struct-pt_regs.patch @@ -0,0 +1,31 @@ +From 004049175b3577e684db4d4bcc1999d019640c0d Mon Sep 17 00:00:00 2001 +From: David Abdurachmanov +Date: Mon, 5 Nov 2018 15:40:04 +0100 +Subject: [PATCH 38/41] riscv: fix spacing in struct pt_regs + +Replace 8 spaces with tab to match styling. + +Signed-off-by: David Abdurachmanov +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/include/asm/ptrace.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h +index 2c5df94..bbe1862 100644 +--- a/arch/riscv/include/asm/ptrace.h ++++ b/arch/riscv/include/asm/ptrace.h +@@ -56,8 +56,8 @@ struct pt_regs { + unsigned long sstatus; + unsigned long sbadaddr; + unsigned long scause; +- /* a0 value before the syscall */ +- unsigned long orig_a0; ++ /* a0 value before the syscall */ ++ unsigned long orig_a0; + }; + + #ifdef CONFIG_64BIT +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0039-riscv-add-missing-vdso_install-target.patch b/target/linux/riscv64/patches-4.19/0039-riscv-add-missing-vdso_install-target.patch new file mode 100644 index 0000000000..e283a9709c --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0039-riscv-add-missing-vdso_install-target.patch @@ -0,0 +1,30 @@ +From 6823875abd0a0644163997423015e929198b646f Mon Sep 17 00:00:00 2001 +From: David Abdurachmanov +Date: Mon, 5 Nov 2018 15:35:37 +0100 +Subject: [PATCH 39/41] riscv: add missing vdso_install target + +Building kernel 4.20 for Fedora as RPM fails, because riscv is missing +vdso_install target in arch/riscv/Makefile. + +Signed-off-by: David Abdurachmanov +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/Makefile | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index d1014619..4af153a 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -77,4 +77,8 @@ core-y += arch/riscv/kernel/ arch/riscv/mm/ + + libs-y += arch/riscv/lib/ + ++PHONY += vdso_install ++vdso_install: ++ $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@ ++ + all: vmlinux +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0040-RISC-V-lib-Fix-build-error-for-64-bit.patch b/target/linux/riscv64/patches-4.19/0040-RISC-V-lib-Fix-build-error-for-64-bit.patch new file mode 100644 index 0000000000..1411dae33e --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0040-RISC-V-lib-Fix-build-error-for-64-bit.patch @@ -0,0 +1,34 @@ +From 69f76e0109e02647945322f57cf17c3bc99b4646 Mon Sep 17 00:00:00 2001 +From: Olof Johansson +Date: Tue, 30 Oct 2018 23:47:07 -0700 +Subject: [PATCH 40/41] RISC-V: lib: Fix build error for 64-bit + +Fixes the following build error from tinyconfig: + +riscv64-unknown-linux-gnu-ld: kernel/sched/fair.o: in function `.L8': +fair.c:(.text+0x70): undefined reference to `__lshrti3' +riscv64-unknown-linux-gnu-ld: kernel/time/clocksource.o: in function `.L0 ': +clocksource.c:(.text+0x334): undefined reference to `__lshrti3' + +Fixes: 7f47c73b355f ("RISC-V: Build tishift only on 64-bit") +Signed-off-by: Olof Johansson +Signed-off-by: Palmer Dabbelt +--- + arch/riscv/lib/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile +index 5739bd0..4e2e600 100644 +--- a/arch/riscv/lib/Makefile ++++ b/arch/riscv/lib/Makefile +@@ -3,6 +3,6 @@ lib-y += memcpy.o + lib-y += memset.o + lib-y += uaccess.o + +-lib-(CONFIG_64BIT) += tishift.o ++lib-$(CONFIG_64BIT) += tishift.o + + lib-$(CONFIG_32BIT) += udivdi3.o +-- +2.1.4 + diff --git a/target/linux/riscv64/patches-4.19/0100-riscv-add-S-and-U-modes-to-ISA-string.patch b/target/linux/riscv64/patches-4.19/0100-riscv-add-S-and-U-modes-to-ISA-string.patch new file mode 100644 index 0000000000..eb9540c6dc --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0100-riscv-add-S-and-U-modes-to-ISA-string.patch @@ -0,0 +1,21 @@ +--- + arch/riscv/kernel/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c +index 3a5a2ee31547..4029c7e6872b 100644 +--- a/arch/riscv/kernel/cpu.c ++++ b/arch/riscv/kernel/cpu.c +@@ -64,7 +64,7 @@ int riscv_of_processor_hartid(struct device_node *node) + + static void print_isa(struct seq_file *f, const char *orig_isa) + { +- static const char *ext = "mafdc"; ++ static const char *ext = "mafdcsu"; + const char *isa = orig_isa; + const char *e; + +-- +2.19.1 + + \ No newline at end of file diff --git a/target/linux/riscv64/patches/002-clk-sifive-prci.patch b/target/linux/riscv64/patches-4.19/0101-002-clk-sifive-prci.patch similarity index 100% rename from target/linux/riscv64/patches/002-clk-sifive-prci.patch rename to target/linux/riscv64/patches-4.19/0101-002-clk-sifive-prci.patch diff --git a/target/linux/riscv64/patches/003-clk-gemgxl.patch b/target/linux/riscv64/patches-4.19/0101-003-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_cl.patch similarity index 86% rename from target/linux/riscv64/patches/003-clk-gemgxl.patch rename to target/linux/riscv64/patches-4.19/0101-003-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_cl.patch index c44befcafc..5cdcfdaf1c 100644 --- a/target/linux/riscv64/patches/003-clk-gemgxl.patch +++ b/target/linux/riscv64/patches-4.19/0101-003-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_cl.patch @@ -1,10 +1,18 @@ -From 13317fd60728d24988fb8f5682bfaafe401b3a15 Mon Sep 17 00:00:00 2001 +From 16736520d300998f5bddcabce9a8c99de4824778 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 6 Feb 2018 11:03:07 -0800 Subject: [PATCH] gemgxl-mgmt: implement clock switch for GEM tx_clk -Signed-off-by: Palmer Dabbelt +XXX Should be changed to move this into the network device drivers +as a management IP block --- + .../bindings/clock/sifive,gemgxl-mgmt.txt | 26 ++++ + drivers/clk/sifive/Kconfig | 5 + + drivers/clk/sifive/Makefile | 1 + + drivers/clk/sifive/gemgxl-mgmt.c | 129 ++++++++++++++++++ + 4 files changed, 161 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt + create mode 100644 drivers/clk/sifive/gemgxl-mgmt.c diff --git a/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt b/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt new file mode 100644 @@ -38,26 +46,12 @@ index 0000000000000..349489e33edaa + ... + clocks = <&mgmt>; /* TX clock */ + }; -diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig -index 0000000000000..284bffb121ebd ---- a/drivers/clk/sifive/Kconfig -+++ b/drivers/clk/sifive/Kconfig -@@ -0,0 +1,9 @@ -+config CLK_U54_PRCI -+ bool "PRCI driver for U54 SoCs" -+ ---help--- -+ Supports Power Reset Clock interface found in U540 SoCs -+ -+config CLK_GEMGXL_MGMT -+ bool "TX clock switch for GEMGXL in U540 SoCs" -+ ---help--- -+ Supports clock muxing between 10/100Mbit and 1Gbit TX clock on U540 SoCs diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile -index 0000000000000..7784d2ee0f446 +index 74d58a4c07567..bf70be89b862c 100644 --- a/drivers/clk/sifive/Makefile +++ b/drivers/clk/sifive/Makefile -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_CLK_U54_PRCI) += u54-prci.o +@@ -1 +1,2 @@ + obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o +obj-$(CONFIG_CLK_GEMGXL_MGMT) += gemgxl-mgmt.o diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c new file mode 100644 @@ -194,3 +188,16 @@ index 0000000000000..00b07580fe3ce + return platform_driver_register(&sifive_gemgxl_mgmt_driver); +} +core_initcall(sifive_gemgxl_mgmt_init); +diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig +index 8db4a3eb47820..b6028b46e2d4a 100644 +--- a/drivers/clk/sifive/Kconfig ++++ b/drivers/clk/sifive/Kconfig +@@ -3,3 +3,8 @@ + depends on RISCV + ---help--- + Supports Power Reset Clock interface found in U540 SoCs ++ ++config CLK_GEMGXL_MGMT ++ bool "TX clock switch for GEMGXL in U540 SoCs" ++ ---help--- ++ Supports clock muxing between 10/100Mbit and 1Gbit TX clock on U5 diff --git a/target/linux/riscv64/patches/004-spi-sifive.patch b/target/linux/riscv64/patches-4.19/0101-004-spi-sifive.patch similarity index 100% rename from target/linux/riscv64/patches/004-spi-sifive.patch rename to target/linux/riscv64/patches-4.19/0101-004-spi-sifive.patch diff --git a/target/linux/riscv64/patches/005-spi-is25wp256d.patch b/target/linux/riscv64/patches-4.19/0101-005-spi-is25wp256d.patch similarity index 100% rename from target/linux/riscv64/patches/005-spi-is25wp256d.patch rename to target/linux/riscv64/patches-4.19/0101-005-spi-is25wp256d.patch diff --git a/target/linux/riscv64/patches/006-uart-sifive-serial-driver.patch b/target/linux/riscv64/patches-4.19/0101-006-uart-sifive-serial-driver.patch similarity index 100% rename from target/linux/riscv64/patches/006-uart-sifive-serial-driver.patch rename to target/linux/riscv64/patches-4.19/0101-006-uart-sifive-serial-driver.patch diff --git a/target/linux/riscv64/patches/007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch b/target/linux/riscv64/patches-4.19/0101-007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch similarity index 100% rename from target/linux/riscv64/patches/007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch rename to target/linux/riscv64/patches-4.19/0101-007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch diff --git a/target/linux/riscv64/patches/0009-RISC-V-Networking-fix-Hack.patch b/target/linux/riscv64/patches-4.19/0101-008-RISC-V-Networking-fix-Hack.patch similarity index 100% rename from target/linux/riscv64/patches/0009-RISC-V-Networking-fix-Hack.patch rename to target/linux/riscv64/patches-4.19/0101-008-RISC-V-Networking-fix-Hack.patch diff --git a/target/linux/riscv64/patches-4.19/0101-010-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch b/target/linux/riscv64/patches-4.19/0101-010-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch new file mode 100644 index 0000000000..fd4210b3e0 --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0101-010-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch @@ -0,0 +1,339 @@ +From d6e84658098c6f37875a9e4b151706c6b541dc0b Mon Sep 17 00:00:00 2001 +From: "Wesley W. Terpstra" +Date: Fri, 2 Mar 2018 14:53:51 -0800 +Subject: [PATCH] pwm-sifive: add a driver for SiFive SoC PWM + +--- + .../devicetree/bindings/pwm/pwm-sifive.txt | 28 ++ + drivers/pwm/Kconfig | 10 + + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-sifive.c | 252 ++++++++++++++++++ + 4 files changed, 291 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pwm/pwm-sifive.txt + create mode 100644 drivers/pwm/pwm-sifive.c + +diff --git a/Documentation/devicetree/bindings/pwm/pwm-sifive.txt b/Documentation/devicetree/bindings/pwm/pwm-sifive.txt +new file mode 100644 +index 0000000000000..7cea20db58e55 +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/pwm-sifive.txt +@@ -0,0 +1,28 @@ ++SiFive PWM controller ++ ++Unlike most other PWM controllers, the SiFive PWM controller currently only ++supports one period for all channels in the PWM. This is set globally in DTS. ++The period also has significant restrictions on the values it can achieve, ++which the driver rounds to the nearest achievable frequency. ++ ++Required properties: ++- compatible: should be "sifive,pwm0" ++- reg: physical base address and length of the controller's registers ++- clocks: The frequency the controller runs at ++- #pwm-cells: Should be 2. ++ The first cell is the PWM channel number ++ The second cell is the PWM polarity ++- sifive,approx-period: the driver will get as close to this period as it can ++- interrupts: one interrupt per PWM channel (currently unused in the driver) ++ ++Examples: ++ ++pwm: pwm@10020000 { ++ compatible = "sifive,pwm0"; ++ reg = <0x0 0x10020000 0x0 0x1000>; ++ clocks = <&tlclk>; ++ interrupt-parent = <&plic>; ++ interrupts = <42 43 44 45>; ++ #pwm-cells = <2>; ++ sifive,approx-period = <1000000>; ++}; +diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +index 763ee50ea57d5..c2037d28446fa 100644 +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -387,6 +387,16 @@ config PWM_SAMSUNG + To compile this driver as a module, choose M here: the module + will be called pwm-samsung. + ++config PWM_SIFIVE ++ tristate "SiFive PWM support" ++ depends on OF ++ depends on COMMON_CLK ++ help ++ Generic PWM framework driver for SiFive SoCs. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-sifive. ++ + config PWM_SPEAR + tristate "STMicroelectronics SPEAr PWM support" + depends on PLAT_SPEAR +diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile +index 0258a745f30c9..17c5eb90cb058 100644 +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o + obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o + obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o + obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o ++obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o + obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o + obj-$(CONFIG_PWM_STI) += pwm-sti.o + obj-$(CONFIG_PWM_STM32) += pwm-stm32.o +diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c +new file mode 100644 +index 0000000000000..93bc0844d23a9 +--- /dev/null ++++ b/drivers/pwm/pwm-sifive.c +@@ -0,0 +1,252 @@ ++/* ++ * Copyright (C) 2018 SiFive, Inc ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2, as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_PWM 4 ++ ++/* Register offsets */ ++#define REG_PWMCFG 0x0 ++#define REG_PWMCOUNT 0x8 ++#define REG_PWMS 0x10 ++#define REG_PWMCMP0 0x20 ++ ++/* PWMCFG fields */ ++#define BIT_PWM_SCALE 0 ++#define BIT_PWM_STICKY 8 ++#define BIT_PWM_ZERO_ZMP 9 ++#define BIT_PWM_DEGLITCH 10 ++#define BIT_PWM_EN_ALWAYS 12 ++#define BIT_PWM_EN_ONCE 13 ++#define BIT_PWM0_CENTER 16 ++#define BIT_PWM0_GANG 24 ++#define BIT_PWM0_IP 28 ++ ++#define SIZE_PWMCMP 4 ++#define MASK_PWM_SCALE 0xf ++ ++struct sifive_pwm_device { ++ struct pwm_chip chip; ++ struct notifier_block notifier; ++ struct clk *clk; ++ void __iomem *regs; ++ int irq; ++ unsigned int approx_period; ++ unsigned int real_period; ++}; ++ ++static inline struct sifive_pwm_device *chip_to_sifive(struct pwm_chip *c) ++{ ++ return container_of(c, struct sifive_pwm_device, chip); ++} ++ ++static inline struct sifive_pwm_device *notifier_to_sifive(struct notifier_block *nb) ++{ ++ return container_of(nb, struct sifive_pwm_device, notifier); ++} ++ ++static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state) ++{ ++ struct sifive_pwm_device *pwm = chip_to_sifive(chip); ++ unsigned int duty_cycle; ++ u32 frac; ++ ++ duty_cycle = state->duty_cycle; ++ if (!state->enabled) duty_cycle = 0; ++ if (state->polarity == PWM_POLARITY_NORMAL) duty_cycle = state->period - duty_cycle; ++ ++ frac = ((u64)duty_cycle << 16) / state->period; ++ frac = min(frac, 0xFFFFU); ++ ++ iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP)); ++ ++ if (state->enabled) { ++ state->period = pwm->real_period; ++ state->duty_cycle = ((u64)frac * pwm->real_period) >> 16; ++ if (state->polarity == PWM_POLARITY_NORMAL) ++ state->duty_cycle = state->period - state->duty_cycle; ++ } ++ ++ return 0; ++} ++ ++static void sifive_pwm_get_state(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state) ++{ ++ struct sifive_pwm_device *pwm = chip_to_sifive(chip); ++ unsigned long duty; ++ ++ duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP)); ++ ++ state->period = pwm->real_period; ++ state->duty_cycle = ((u64)duty * pwm->real_period) >> 16; ++ state->polarity = PWM_POLARITY_INVERSED; ++ state->enabled = duty > 0; ++} ++ ++static const struct pwm_ops sifive_pwm_ops = { ++ .get_state = sifive_pwm_get_state, ++ .apply = sifive_pwm_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static struct pwm_device *sifive_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) ++{ ++ struct sifive_pwm_device *pwm = chip_to_sifive(chip); ++ struct pwm_device *dev; ++ ++ if (args->args[0] >= chip->npwm) ++ return ERR_PTR(-EINVAL); ++ ++ dev = pwm_request_from_chip(chip, args->args[0], NULL); ++ if (IS_ERR(dev)) ++ return dev; ++ ++ /* The period cannot be changed on a per-PWM basis */ ++ dev->args.period = pwm->real_period; ++ dev->args.polarity = PWM_POLARITY_NORMAL; ++ if (args->args[1] & PWM_POLARITY_INVERTED) ++ dev->args.polarity = PWM_POLARITY_INVERSED; ++ ++ return dev; ++} ++ ++static void sifive_pwm_update_clock(struct sifive_pwm_device *pwm, unsigned long rate) ++{ ++ /* (1 << (16+scale)) * 10^9/rate = real_period */ ++ unsigned long scalePow = (pwm->approx_period * (u64)rate) / 1000000000; ++ int scale = ilog2(scalePow) - 16; ++ ++ scale = clamp(scale, 0, 0xf); ++ iowrite32((1 << BIT_PWM_EN_ALWAYS) | (scale << BIT_PWM_SCALE), pwm->regs + REG_PWMCFG); ++ ++ pwm->real_period = (1000000000ULL << (16 + scale)) / rate; ++} ++ ++static int sifive_pwm_clock_notifier(struct notifier_block *nb, unsigned long event, void *data) ++{ ++ struct clk_notifier_data *ndata = data; ++ struct sifive_pwm_device *pwm = notifier_to_sifive(nb); ++ ++ if (event == POST_RATE_CHANGE) ++ sifive_pwm_update_clock(pwm, ndata->new_rate); ++ ++ return NOTIFY_OK; ++} ++ ++static int sifive_pwm_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = pdev->dev.of_node; ++ struct sifive_pwm_device *pwm; ++ struct pwm_chip *chip; ++ struct resource *res; ++ int ret; ++ ++ pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); ++ if (!pwm) { ++ dev_err(dev, "Out of memory\n"); ++ return -ENOMEM; ++ } ++ ++ chip = &pwm->chip; ++ chip->dev = dev; ++ chip->ops = &sifive_pwm_ops; ++ chip->of_xlate = sifive_pwm_xlate; ++ chip->of_pwm_n_cells = 2; ++ chip->base = -1; ++ ++ ret = of_property_read_u32(node, "sifive,npwm", &chip->npwm); ++ if (ret < 0 || chip->npwm > MAX_PWM) chip->npwm = MAX_PWM; ++ ++ ret = of_property_read_u32(node, "sifive,approx-period", &pwm->approx_period); ++ if (ret < 0) { ++ dev_err(dev, "Unable to read sifive,approx-period from DTS\n"); ++ return -ENOENT; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pwm->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pwm->regs)) { ++ dev_err(dev, "Unable to map IO resources\n"); ++ return PTR_ERR(pwm->regs); ++ } ++ ++ pwm->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pwm->clk)) { ++ dev_err(dev, "Unable to find controller clock\n"); ++ return PTR_ERR(pwm->clk); ++ } ++ ++ pwm->irq = platform_get_irq(pdev, 0); ++ if (pwm->irq < 0) { ++ dev_err(dev, "Unable to find interrupt\n"); ++ return pwm->irq; ++ } ++ ++ /* Watch for changes to underlying clock frequency */ ++ pwm->notifier.notifier_call = sifive_pwm_clock_notifier; ++ clk_notifier_register(pwm->clk, &pwm->notifier); ++ ++ /* Initialize PWM config */ ++ sifive_pwm_update_clock(pwm, clk_get_rate(pwm->clk)); ++ ++ /* No interrupt handler needed yet */ ++/* ++ ret = devm_request_irq(dev, pwm->irq, sifive_pwm_irq, 0, dev_name(dev), pwm); ++ if (ret) { ++ dev_err(dev, "Unable to bind interrupt\n"); ++ return ret; ++ } ++*/ ++ ++ ret = pwmchip_add(chip); ++ if (ret < 0) { ++ dev_err(dev, "cannot register PWM: %d\n", ret); ++ clk_notifier_unregister(pwm->clk, &pwm->notifier); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, pwm); ++ dev_info(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm); ++ ++ return 0; ++} ++ ++static int sifive_pwm_remove(struct platform_device *dev) ++{ ++ struct sifive_pwm_device *pwm = platform_get_drvdata(dev); ++ struct pwm_chip *chip = &pwm->chip; ++ ++ clk_notifier_unregister(pwm->clk, &pwm->notifier); ++ return pwmchip_remove(chip); ++} ++ ++static const struct of_device_id sifive_pwm_of_match[] = { ++ { .compatible = "sifive,pwm0" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sifive_pwm_of_match); ++ ++static struct platform_driver sifive_pwm_driver = { ++ .probe = sifive_pwm_probe, ++ .remove = sifive_pwm_remove, ++ .driver = { ++ .name = "pwm-sifivem", ++ .of_match_table = of_match_ptr(sifive_pwm_of_match), ++ }, ++}; ++module_platform_driver(sifive_pwm_driver); ++ ++MODULE_DESCRIPTION("SiFive PWM driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/riscv64/patches-4.19/0101-011-sifive-u500-otp-driver-for-SiFive-U500-OTP-contr.patch b/target/linux/riscv64/patches-4.19/0101-011-sifive-u500-otp-driver-for-SiFive-U500-OTP-contr.patch new file mode 100644 index 0000000000..14fb51eaeb --- /dev/null +++ b/target/linux/riscv64/patches-4.19/0101-011-sifive-u500-otp-driver-for-SiFive-U500-OTP-contr.patch @@ -0,0 +1,409 @@ +From 33cd56c2ab57ff984a4d7fbe378b27ef13b87458 Mon Sep 17 00:00:00 2001 +From: "Wesley W. Terpstra" +Date: Mon, 26 Feb 2018 16:49:49 -0800 +Subject: [PATCH] sifive-u500-otp: driver for SiFive U500 OTP controller + +--- + .../bindings/nvmem/sifive-u500-otp.txt | 19 + + drivers/nvmem/Kconfig | 10 + + drivers/nvmem/Makefile | 2 + + drivers/nvmem/sifive-u500-otp.c | 330 ++++++++++++++++++ + 4 files changed, 361 insertions(+) + create mode 100644 Documentation/devicetree/bindings/nvmem/sifive-u500-otp.txt + create mode 100644 drivers/nvmem/sifive-u500-otp.c + +diff --git a/Documentation/devicetree/bindings/nvmem/sifive-u500-otp.txt b/Documentation/devicetree/bindings/nvmem/sifive-u500-otp.txt +new file mode 100644 +index 0000000000000..fc59123719660 +--- /dev/null ++++ b/Documentation/devicetree/bindings/nvmem/sifive-u500-otp.txt +@@ -0,0 +1,19 @@ ++= SiFive U500 OTP controller device tree bindings = ++ ++This binding represents the OTP controller found in U500 SoCs. ++ ++!!! EXERCISE EXTREME CAUTION USING THIS DEVICE !!! ++ ++OTP bits can only be programmed once from 1 to 0. They are contained in the ++chip itself. Incorrectly modifying OTP contents may require a new chip. ++ ++Required properties: ++- compatible: should be "sifive,ememoryotp0" ++- reg: Should contain registers location and length ++ ++For example: ++ ++ otp: sifive,ememoryotp0 { ++ compatible = "sifive,ememoryotp0"; ++ reg = <0x0 0x10070000 0x0 0x1000>; ++ }; +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index ff505af064ba6..e0ea3eca483d6 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -113,6 +113,16 @@ config NVMEM_BCM_OCOTP + This driver can also be built as a module. If so, the module + will be called nvmem-bcm-ocotp. + ++config NVMEM_SIFIVE_U500_OTP ++ tristate "SiFive U500 OTP Controller support" ++ depends on HAS_IOMEM ++ help ++ Say y here to enable read/write access to the SiFive U500 ++ OTP controller. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-sifive-u500-otp. ++ + config NVMEM_SUNXI_SID + tristate "Allwinner SoCs SID support" + depends on ARCH_SUNXI +diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile +index e54dcfa6565a9..d4c64fbbec7f2 100644 +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -9,6 +9,8 @@ nvmem_core-y := core.o + # Devices + obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o + nvmem-bcm-ocotp-y := bcm-ocotp.o ++obj-$(CONFIG_NVMEM_SIFIVE_U500_OTP) += nvmem-sifive-u500-otp.o ++nvmem-sifive-u500-otp-y := sifive-u500-otp.o + obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o + nvmem-imx-iim-y := imx-iim.o + obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o +diff --git a/drivers/nvmem/sifive-u500-otp.c b/drivers/nvmem/sifive-u500-otp.c +new file mode 100644 +index 0000000000000..8c0d0ccea29e0 +--- /dev/null ++++ b/drivers/nvmem/sifive-u500-otp.c +@@ -0,0 +1,330 @@ ++/* ++ * Copyright (C) 2018 SiFive, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Register offsets */ ++#define EMEMORYOTP_REG_GET(reg) ioread32(otp->base + reg) ++#define EMEMORYOTP_REG_SET(reg, val) iowrite32(val, otp->base + reg) ++ ++#define EMEMORYOTP_PA 0x00 ++#define EMEMORYOTP_PAIO 0x04 ++#define EMEMORYOTP_PAS 0x08 ++#define EMEMORYOTP_PCE 0x0C ++#define EMEMORYOTP_PCLK 0x10 ++#define EMEMORYOTP_PDIN 0x14 ++#define EMEMORYOTP_PDOUT 0x18 ++#define EMEMORYOTP_PDSTB 0x1C ++#define EMEMORYOTP_PPROG 0x20 ++#define EMEMORYOTP_PTC 0x24 ++#define EMEMORYOTP_PTM 0x28 ++#define EMEMORYOTP_PTM_REP 0x2C ++#define EMEMORYOTP_PTR 0x30 ++#define EMEMORYOTP_PTRIM 0x34 ++#define EMEMORYOTP_PWE 0x38 ++ ++/* Timing delays (in us) ++ MIN indicates that there is no maximum. ++ TYP indicates that there is a maximum ++ that should not be exceeded. ++ When the minimums are < 1us, I just put 1us. ++*/ ++ ++#define EMEMORYOTP_MIN_TVDS 1 ++#define EMEMORYOTP_MIN_TSAS 2 ++#define EMEMORYOTP_MIN_TTAS 50 ++#define EMEMORYOTP_MIN_TTAH 1 ++#define EMEMORYOTP_MIN_TASH 1 ++#define EMEMORYOTP_MIN_TMS 1 ++#define EMEMORYOTP_MIN_TCS 10 ++#define EMEMORYOTP_MIN_TMH 1 ++#define EMEMORYOTP_MIN_TAS 50 ++ ++#define EMEMORYOTP_MAX_TCD 1 ++#define EMEMORYOTP_MIN_TKH 1 ++ ++// Note: This has an upper limit of 100. ++#define EMEMORYOTP_MIN_TCSP 10 ++#define EMEMORYOTP_TYP_TCSP 11 ++ ++// This has an upper limit of 20. ++#define EMEMORYOTP_MIN_TPPS 5 ++#define EMEMORYOTP_TYP_TPPS 6 ++ ++// This has an upper limit of 20. ++#define EMEMORYOTP_MIN_TPPH 1 ++#define EMEMORYOTP_TYP_TPPH 2 ++ ++// This has upper limit of 100. ++#define EMEMORYOTP_MIN_TPPR 5 ++#define EMEMORYOTP_TYP_TPPR 6 ++ ++// This has upper limit of 20 ++#define EMEMORYOTP_MIN_TPW 10 ++#define EMEMORYOTP_TYP_TPW 11 ++ ++#define EMEMORYOTP_MIN_TASP 1 ++#define EMEMORYOTP_MIN_TDSP 1 ++ ++#define EMEMORYOTP_MIN_TAHP 1 ++#define EMEMORYOTP_MIN_TDHP 1 ++// This has a max of 5! ++#define EMEMORYOTP_MIN_TPWI 1 ++#define EMEMORYOTP_TYP_TPWI 2 ++ ++struct sifive_u500_otp { ++ void __iomem *base; ++ raw_spinlock_t lock; ++ struct nvmem_config config; ++}; ++ ++static void sifive_u500_otp_power_up_sequence(struct sifive_u500_otp *otp) ++{ ++ // Probably don't need to do this, since ++ // all the other stuff has been happening. ++ // But it is on the wave form. ++ udelay(EMEMORYOTP_MIN_TVDS); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PDSTB, 1); ++ udelay(EMEMORYOTP_MIN_TSAS); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PTRIM, 1); ++ udelay(EMEMORYOTP_MIN_TTAS); ++} ++ ++static void sifive_u500_otp_power_down_sequence(struct sifive_u500_otp *otp) ++{ ++ udelay(EMEMORYOTP_MIN_TTAH); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PTRIM, 0); ++ udelay(EMEMORYOTP_MIN_TASH); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PDSTB, 0); ++ // No delay indicated after this ++} ++ ++static void sifive_u500_otp_begin_read(struct sifive_u500_otp *otp) ++{ ++ // Initialize ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCLK, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PA, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PDIN, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PWE, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PTM, 0); ++ udelay(EMEMORYOTP_MIN_TMS); ++ ++ // Enable chip select ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCE, 1); ++ udelay(EMEMORYOTP_MIN_TCS); ++} ++ ++static void sifive_u500_otp_exit_read(struct sifive_u500_otp *otp) ++{ ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCLK, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PA, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PDIN, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PWE, 0); ++ // Disable chip select ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCE, 0); ++ // Wait before changing PTM ++ udelay(EMEMORYOTP_MIN_TMH); ++} ++ ++static unsigned int sifive_u500_otp_read(struct sifive_u500_otp *otp, int address) ++{ ++ unsigned int read_value; ++ int delay; ++ ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PA, address); ++ // Toggle clock ++ udelay(EMEMORYOTP_MIN_TAS); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCLK, 1); ++ ++ // Insert delay until data is ready. ++ // There are lots of delays ++ // on the chart, but I think this is the most relevant. ++ delay = max(EMEMORYOTP_MAX_TCD, EMEMORYOTP_MIN_TKH); ++ udelay(delay); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCLK, 0); ++ read_value = EMEMORYOTP_REG_GET(EMEMORYOTP_PDOUT); ++ ++ // Could check here for things like TCYC < TAH + TCD ++ return read_value; ++} ++ ++static void sifive_u500_otp_pgm_entry(struct sifive_u500_otp *otp) ++{ ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCLK, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PA, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PAS, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PAIO, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PDIN, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PWE, 0); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PTM, 2); ++ udelay(EMEMORYOTP_MIN_TMS); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCE, 1); ++ udelay(EMEMORYOTP_TYP_TCSP); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PPROG, 1); ++ udelay(EMEMORYOTP_TYP_TPPS); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PTRIM, 1); ++} ++ ++static void sifive_u500_otp_pgm_exit(struct sifive_u500_otp *otp) ++{ ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PWE, 0); ++ udelay(EMEMORYOTP_TYP_TPPH); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PPROG, 0); ++ udelay(EMEMORYOTP_TYP_TPPR); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PCE, 0); ++ udelay(EMEMORYOTP_MIN_TMH); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PTM, 0); ++} ++ ++static void sifive_u500_otp_pgm_access(struct sifive_u500_otp *otp, int address, unsigned int write_data) ++{ ++ int i, pas, delay; ++ ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PA, address); ++ for (pas = 0; pas < 2; pas ++) { ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PAS, pas); ++ for (i = 0; i < 32; i++) { ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PAIO, i); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PDIN, (write_data >> i) & 1); ++ delay = max(EMEMORYOTP_MIN_TASP, EMEMORYOTP_MIN_TDSP); ++ udelay(delay); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PWE, 1); ++ udelay(EMEMORYOTP_TYP_TPW); ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PWE, 0); ++ delay = max(EMEMORYOTP_MIN_TAHP, EMEMORYOTP_MIN_TDHP); ++ delay = max(delay, EMEMORYOTP_TYP_TPWI); ++ udelay(delay); ++ } ++ } ++ EMEMORYOTP_REG_SET(EMEMORYOTP_PAS, 0); ++} ++ ++static int sifive_u500_otp_reg_read(void *context, unsigned int offset, void *val, size_t bytes) ++{ ++ struct sifive_u500_otp *otp = context; ++ unsigned long flags; ++ u32 *buf = val; ++ int i; ++ ++ raw_spin_lock_irqsave(&otp->lock, flags); ++ sifive_u500_otp_power_up_sequence(otp); ++ sifive_u500_otp_begin_read(otp); ++ ++ for (i = 0; i < bytes/4; ++i) ++ buf[i] = sifive_u500_otp_read(otp, i+offset/4); ++ ++ sifive_u500_otp_exit_read(otp); ++ sifive_u500_otp_power_down_sequence(otp); ++ raw_spin_unlock_irqrestore(&otp->lock, flags); ++ ++ return 0; ++} ++ ++static int sifive_u500_otp_reg_write(void *context, unsigned int offset, void *val, size_t bytes) ++{ ++ struct sifive_u500_otp *otp = context; ++ unsigned long flags; ++ u32 *buf = val; ++ int i; ++ ++ if (offset % 4 || bytes % 4) ++ return -EINVAL; ++ ++ raw_spin_lock_irqsave(&otp->lock, flags); ++ sifive_u500_otp_power_up_sequence(otp); ++ sifive_u500_otp_pgm_entry(otp); ++ ++ for (i = 0; i < bytes/4; ++i) ++ sifive_u500_otp_pgm_access(otp, i+offset/4, buf[i]); ++ ++ sifive_u500_otp_pgm_exit(otp); ++ sifive_u500_otp_power_down_sequence(otp); ++ raw_spin_unlock_irqrestore(&otp->lock, flags); ++ ++ return 0; ++} ++ ++static int sifive_u500_otp_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ struct sifive_u500_otp *otp; ++ struct nvmem_device *nvmem; ++ ++ otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL); ++ if (!otp) { ++ dev_err(dev, "out of memory\n"); ++ return -ENOMEM; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ otp->base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(otp->base)) { ++ dev_err(dev, "unable to map device memory\n"); ++ return PTR_ERR(otp->base); ++ } ++ ++ otp->config.dev = dev; ++ otp->config.name = "sifive-u500-otp"; ++ otp->config.read_only = false; ++ otp->config.root_only = false; // true; /* writes permanently modify the SoC! */ ++ otp->config.reg_read = sifive_u500_otp_reg_read; ++ otp->config.reg_write = sifive_u500_otp_reg_write; ++ otp->config.size = 16384; /* in bytes */ ++ otp->config.word_size = 4; ++ otp->config.stride = 4; ++ otp->config.priv = otp; ++ ++ raw_spin_lock_init(&otp->lock); ++ nvmem = nvmem_register(&otp->config); ++ if (IS_ERR(nvmem)) { ++ dev_err(dev, "error registering nvmem config\n"); ++ return PTR_ERR(nvmem); ++ } ++ ++ platform_set_drvdata(pdev, nvmem); ++ return 0; ++} ++ ++static int sifive_u500_otp_remove(struct platform_device *pdev) ++{ ++ struct nvmem_device *nvmem = platform_get_drvdata(pdev); ++ ++ return nvmem_unregister(nvmem); ++} ++ ++static const struct of_device_id sifive_u500_otp_dt_ids[] = { ++ { .compatible = "sifive,ememoryotp0" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sifive_u500_otp_dt_ids); ++ ++static struct platform_driver sifive_u500_otp_driver = { ++ .probe = sifive_u500_otp_probe, ++ .remove = sifive_u500_otp_remove, ++ .driver = { ++ .name = "sifive-u500-otp", ++ .of_match_table = sifive_u500_otp_dt_ids, ++ }, ++}; ++module_platform_driver(sifive_u500_otp_driver); ++ ++MODULE_DESCRIPTION("SiFive U500 OTP driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/riscv64/patches/0010-pcie-microsemi-added-support-for-the-Vera-board-root.patch b/target/linux/riscv64/patches/0010-pcie-microsemi-added-support-for-the-Vera-board-root.patch deleted file mode 100644 index 47c75ead58..0000000000 --- a/target/linux/riscv64/patches/0010-pcie-microsemi-added-support-for-the-Vera-board-root.patch +++ /dev/null @@ -1,804 +0,0 @@ -From 1fd6c8fbc07bec3c18771738ce4b2aad3ed228f2 Mon Sep 17 00:00:00 2001 -From: "Wesley W. Terpstra" -Date: Wed, 25 Apr 2018 12:10:15 -0700 -Subject: [PATCH 10/11] pcie-microsemi: added support for the Vera-board root - complex - ---- - drivers/pci/controller/Kconfig | 6 + - drivers/pci/controller/Makefile | 1 + - drivers/pci/controller/pcie-microsemi.c | 754 ++++++++++++++++++++++++++++++++ - 3 files changed, 761 insertions(+) - create mode 100644 drivers/pci/controller/pcie-microsemi.c - -diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig -index 028b2874..4458c119 100644 ---- a/drivers/pci/controller/Kconfig -+++ b/drivers/pci/controller/Kconfig -@@ -278,5 +278,11 @@ config VMD - To compile this driver as a module, choose M here: the - module will be called vmd. - -+config PCIE_MICROSEMI -+ bool "Microsemi AXI PCIe host bridge support" -+ depends on OF || COMPILE_TEST -+ help -+ Say 'Y' here if you want kernel to support the Microsemi AXI PCIe -+ Host Bridge driver. - source "drivers/pci/controller/dwc/Kconfig" - endmenu -diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile -index d56a5074..c3b76ff2 100644 ---- a/drivers/pci/controller/Makefile -+++ b/drivers/pci/controller/Makefile -@@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o - obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o - obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o - obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o -+obj-$(CONFIG_PCIE_MICROSEMI) += pcie-microsemi.o - obj-$(CONFIG_VMD) += vmd.o - # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW - obj-y += dwc/ -diff --git a/drivers/pci/controller/pcie-microsemi.c b/drivers/pci/controller/pcie-microsemi.c -new file mode 100644 -index 00000000..9e2abca2 ---- /dev/null -+++ b/drivers/pci/controller/pcie-microsemi.c -@@ -0,0 +1,754 @@ -+/* -+ * PCIe host controller driver for Microsemi AXI PCIe Bridge -+ * -+ * Copyright (c) 2018 - Microsemi. -+ * Author: Badal Nilawar -+ * -+ * Based on the Xilinx, Altera PCIe driver -+ * -+ * -+ * This program is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "../pci.h" -+ -+/* ECAM definitions */ -+#define ECAM_BUS_NUM_SHIFT 20 -+#define ECAM_DEV_NUM_SHIFT 12 -+ -+/* Number of MSI IRQs */ -+#define MICROSEMI_NUM_MSI_IRQS 32 -+ -+/* PCIe Bridge Phy and Controller Phy offsets */ -+#define PCIE0_BRIDGE_PHY_ADDR_OFFSET 0x03004000u -+#define PCIE0_CRTL_PHY_ADDR_OFFSET 0x03006000u -+ -+#define PCIE0_BRIDGE_ADDR 0x03004000u -+#define PCIE0_CRTL_ADDR 0x03006000u -+ -+#define PCIE1_BRIDGE_ADDR 0x00008000u -+#define PCIE1_CRTL_ADDR 0x0000A000u -+ -+/* PCIe LTSSM State reg */ -+#define LTSSM_STATE 0x5c -+ -+/* PCIe LTSSM L0 state */ -+#define LTSSM_L0_STATE 0x10 -+ -+/* PCIe Controller Phy Regs */ -+#define SEC_ERROR_INT 0x28 -+#define SEC_ERROR_INT_MASK 0x2c -+#define DED_ERROR_INT 0x30 -+#define DED_ERROR_INT_MASK 0x34 -+#define ECC_CONTROL 0x38 -+#define PCIE_EVENT_INT 0x14c -+ -+/* PCIe Bridge Phy Regs */ -+#define IMASK_LOCAL 0x180 -+#define ISTATUS_LOCAL 0x184 -+#define IMASK_HOST 0x188 -+#define ISTATUS_HOST 0x18c -+#define ISTATUS_MSI 0x194 -+#define PCIE_PCI_IDS_DW1 0x9c -+ -+/* PCIe AXI slave table init defines */ -+#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u -+#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u -+#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u -+#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu -+#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u -+ -+#define ATR1_AXI4_SLV0_SRCADDR_PARAM 0x820u -+#define ATR1_AXI4_SLV0_SRC_ADDR 0x824u -+#define ATR1_AXI4_SLV0_TRSL_ADDR_LSB 0x828u -+#define ATR1_AXI4_SLV0_TRSL_ADDR_UDW 0x82cu -+#define ATR1_AXI4_SLV0_TRSL_PARAM 0x830u -+ -+/* PCIe Master table init defines */ -+#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u -+ -+/* Translated ID */ -+#define PCIE_TX_RX_INTERFACE 0x00000000u -+#define PCIE_CONFIG_INTERFACE 0x00000001u -+ -+/* PCIe Config space MSI capability structure */ -+#define PCIE_ENABLE_MSI 0x10000000u -+ -+/* MSI definitions */ -+#define MSI_MSG_ADDR 0x190u -+#define MSI_ENABLE (0x01u << 16) -+#define MSI_ENABLE_MULTI (MICROSEMI_NUM_MSI_IRQS << 20) -+ -+/* MSI Capability Structure */ -+#define MSI_CAP_CTRL 0xE0u -+#define MSI_MSG_ADDR_OFFSET 0xE4u -+#define MSI_MSG_UPPER_ADDR_OFFEST 0xE8u -+#define MSI_MSG_DATA 0xF0u -+ -+ -+ -+/******************************************************************************/ -+/*Enable PCIe local*/ -+#define PCIE_LOCAL_INT_ENABLE 0xF000000u -+ -+/******************************************************************************/ -+/* Clear PCIe interrupt events */ -+#define PCIE_EVENT_INT_DATA 0x00070007u -+#define PCIE_ECC_DISABLE 0x0F000000u -+#define PCIE_SEC_ERROR_INT_CLEAR 0x0000FFFFu -+#define PCIE_DED_ERROR_INT_CLEAR 0x0000FFFFu -+#define PCIE_ISTATUS_CLEAR 0xFFFFFFFFu -+#define PCIE_CLEAR 0x00000000u -+#define PCIE_SET 0x00000001u -+ -+#define ROOT_PORT_ENABLE 0x00000001u -+ -+#define NULL_POINTER 0x00000000u -+ -+/*****************************************************************************/ -+/* PCIe Controller 0 */ -+#define PF_PCIE_CTRL_0 0u -+/* PCIe Controller 1 */ -+#define PF_PCIE_CTRL_1 1u -+ -+/* It indicates that the ATR table is enabled */ -+#define PF_PCIE_ATR_TABLE_ENABLE 1u -+/* It indicates that the the ATR table is disabled */ -+#define PF_PCIE_ATR_TABLE_DISABLE 0u -+ -+ -+/** -+ * struct microsemi_pcie_port - PCIe port information -+ * @reg_base: IO Mapped Register Base -+ * @irq: Interrupt number -+ * @root_busno: Root Bus number -+ * @dev: Device pointer -+ * @msi_domain: MSI IRQ domain pointer -+ * @leg_domain: Legacy IRQ domain pointer -+ * @resources: Bus Resources -+ */ -+struct microsemi_pcie_port { -+ struct platform_device *pdev; -+ void __iomem *reg_base; -+ void __iomem *reg_base_apb; -+ void __iomem *reg_bridge_apb; -+ void __iomem *reg_ctrl_apb; -+ u32 irq; -+ u8 root_busno; -+ struct device *dev; -+ struct irq_domain *msi_domain; -+ struct irq_domain *leg_domain; -+ struct list_head resources; -+}; -+ -+static DECLARE_BITMAP(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS); -+ -+static inline u32 pcie_read(struct microsemi_pcie_port *port, u32 reg) -+{ -+ return readl(port->reg_base + reg); -+} -+ -+static inline void pcie_write(struct microsemi_pcie_port *port, -+ u32 val, u32 reg) -+{ -+ writel(val, port->reg_base + reg); -+} -+ -+static inline bool microsemi_pcie_link_up(struct microsemi_pcie_port *port) -+{ -+ return (readl(port->reg_ctrl_apb + LTSSM_STATE) -+ & LTSSM_L0_STATE) ? 1 : 0; -+} -+ -+/** -+ * microsemi_pcie_valid_device - Check if a valid device is present on bus -+ * @bus: PCI Bus structure -+ * @devfn: device/function -+ * -+ * Return: 'true' on success and 'false' if invalid device is found -+ */ -+static bool microsemi_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) -+{ -+ struct microsemi_pcie_port *port = bus->sysdata; -+ -+ /* Check if link is up when trying to access downstream ports */ -+ if (bus->number != port->root_busno) -+ if (!microsemi_pcie_link_up(port)) -+ return false; -+ -+ /* Only one device down on each root port */ -+ if (bus->number == port->root_busno && devfn > 0) -+ return false; -+ -+ return true; -+} -+ -+/** -+ * microsemi_pcie_map_bus - Get configuration base -+ * @bus: PCI Bus structure -+ * @devfn: Device/function -+ * @where: Offset from base -+ * -+ * Return: Base address of the configuration space needed to be -+ * accessed. -+ */ -+static void __iomem *microsemi_pcie_map_bus(struct pci_bus *bus, -+ unsigned int devfn, int where) -+{ -+ struct microsemi_pcie_port *port = bus->sysdata; -+ int relbus; -+ -+ -+ if (!microsemi_pcie_valid_device(bus, devfn)) -+ return NULL; -+ -+ relbus = (bus->number << ECAM_BUS_NUM_SHIFT) | -+ (devfn << ECAM_DEV_NUM_SHIFT); -+ -+ -+ return port->reg_base + relbus + where; -+} -+ -+/* PCIe operations */ -+static struct pci_ops microsemi_pcie_ops = { -+ .map_bus = microsemi_pcie_map_bus, -+ .read = pci_generic_config_read, -+ .write = pci_generic_config_write, -+}; -+ -+/* MSI functions */ -+ -+/** -+ * microsemi_pcie_destroy_msi - Free MSI number -+ * @irq: IRQ to be freed -+ */ -+static void microsemi_pcie_destroy_msi(unsigned int irq) -+{ -+ struct msi_desc *msi; -+ struct microsemi_pcie_port *port; -+ struct irq_data *d = irq_get_irq_data(irq); -+ irq_hw_number_t hwirq = irqd_to_hwirq(d); -+ -+ if (!test_bit(hwirq, msi_irq_in_use)) { -+ msi = irq_get_msi_desc(irq); -+ port = msi_desc_to_pci_sysdata(msi); -+ dev_err(port->dev, "Trying to free unused MSI#%d\n", irq); -+ } else { -+ clear_bit(hwirq, msi_irq_in_use); -+ } -+} -+ -+/** -+ * microsemi_pcie_assign_msi - Allocate MSI number -+ * -+ * Return: A valid IRQ on success and error value on failure. -+ */ -+static int microsemi_pcie_assign_msi(void) -+{ -+ int pos; -+ -+ pos = find_first_zero_bit(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS); -+ if (pos < MICROSEMI_NUM_MSI_IRQS) -+ set_bit(pos, msi_irq_in_use); -+ else -+ return -ENOSPC; -+ -+ return pos; -+} -+ -+/** -+ * microsemi_msi_teardown_irq - Destroy the MSI -+ * @chip: MSI Chip descriptor -+ * @irq: MSI IRQ to destroy -+ */ -+static void microsemi_msi_teardown_irq(struct msi_controller *chip, -+ unsigned int irq) -+{ -+ microsemi_pcie_destroy_msi(irq); -+ irq_dispose_mapping(irq); -+} -+ -+/** -+ * microsemi_pcie_msi_setup_irq - Setup MSI request -+ * @chip: MSI chip pointer -+ * @pdev: PCIe device pointer -+ * @desc: MSI descriptor pointer -+ * -+ * Return: '0' on success and error value on failure -+ */ -+static int microsemi_pcie_msi_setup_irq(struct msi_controller *chip, -+ struct pci_dev *pdev, -+ struct msi_desc *desc) -+{ -+ struct microsemi_pcie_port *port = pdev->bus->sysdata; -+ unsigned int irq; -+ int hwirq; -+ struct msi_msg msg; -+ -+ hwirq = microsemi_pcie_assign_msi(); -+ if (hwirq < 0) -+ return hwirq; -+ -+ irq = irq_create_mapping(port->msi_domain, hwirq); -+ if (!irq) -+ return -EINVAL; -+ -+ irq_set_msi_desc(irq, desc); -+ -+ msg.address_hi = 0; -+ msg.address_lo = MSI_MSG_ADDR; -+ msg.data = hwirq; -+ -+ pci_write_msi_msg(irq, &msg); -+ -+ return 0; -+} -+ -+/* MSI Chip Descriptor */ -+static struct msi_controller microsemi_pcie_msi_chip = { -+ .setup_irq = microsemi_pcie_msi_setup_irq, -+ .teardown_irq = microsemi_msi_teardown_irq, -+}; -+ -+/* HW Interrupt Chip Descriptor */ -+static struct irq_chip microsemi_msi_irq_chip = { -+ .name = "Microsemi PCIe MSI", -+ .irq_enable = pci_msi_unmask_irq, -+ .irq_disable = pci_msi_mask_irq, -+ .irq_mask = pci_msi_mask_irq, -+ .irq_unmask = pci_msi_unmask_irq, -+}; -+ -+/** -+ * microsemi_pcie_msi_map - Set the handler for the MSI and mark IRQ as valid -+ * @domain: IRQ domain -+ * @irq: Virtual IRQ number -+ * @hwirq: HW interrupt number -+ * -+ * Return: Always returns 0. -+ */ -+static int microsemi_pcie_msi_map(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) -+{ -+ irq_set_chip_and_handler(irq, -+ µsemi_msi_irq_chip, handle_simple_irq); -+ irq_set_chip_data(irq, domain->host_data); -+ -+ return 0; -+} -+ -+/* IRQ Domain operations */ -+static const struct irq_domain_ops msi_domain_ops = { -+ .map = microsemi_pcie_msi_map, -+}; -+ -+/** -+ * microsemi_pcie_enable_msi - Enable MSI support -+ * @port: PCIe port information -+ */ -+static void microsemi_pcie_enable_msi(struct microsemi_pcie_port *port) -+{ -+ u32 cap_ctrl; -+ -+ cap_ctrl = pcie_read(port, MSI_CAP_CTRL); -+ -+ pcie_write(port, cap_ctrl | MSI_ENABLE_MULTI | MSI_ENABLE, MSI_CAP_CTRL); -+ pcie_write(port, MSI_MSG_ADDR, MSI_MSG_ADDR_OFFSET); -+} -+ -+/* INTx Functions */ -+ -+/** -+ * microsemi_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid -+ * @domain: IRQ domain -+ * @irq: Virtual IRQ number -+ * @hwirq: HW interrupt number -+ * -+ * Return: Always returns 0. -+ */ -+static int microsemi_pcie_intx_map(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) -+{ -+ irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); -+ irq_set_chip_data(irq, domain->host_data); -+ -+ return 0; -+} -+ -+/* INTx IRQ Domain operations */ -+static const struct irq_domain_ops intx_domain_ops = { -+ .map = microsemi_pcie_intx_map, -+ .xlate = pci_irqd_intx_xlate, -+}; -+ -+/* PCIe HW Functions */ -+ -+/** -+ * microsemi_pcie_intr_handler - Interrupt Service Handler -+ * @irq: IRQ number -+ * @data: PCIe port information -+ * -+ * Return: IRQ_HANDLED on success and IRQ_NONE on failure -+ */ -+static irqreturn_t microsemi_pcie_intr_handler(int irq, void *data) -+{ -+ struct microsemi_pcie_port *port = (struct microsemi_pcie_port *)data; -+ struct device *dev = port->dev; -+ unsigned long status; -+ unsigned long msi; -+ u32 bit; -+ u32 virq; -+ -+ -+ status = readl(port->reg_bridge_apb + ISTATUS_LOCAL); -+ -+ status = (status >> 24) & 0x0f; -+ for_each_set_bit(bit, &status, PCI_NUM_INTX) { -+ /* clear interrupts */ -+ writel(1 << (bit+24), -+ port->reg_bridge_apb + ISTATUS_LOCAL); -+ -+ virq = irq_find_mapping(port->leg_domain, bit); -+ -+ if (virq) -+ generic_handle_irq(virq); -+ else -+ dev_err(dev, "unexpected IRQ, INT%d\n", bit); -+ } -+ -+ status = readl(port->reg_bridge_apb + ISTATUS_LOCAL); -+ if ((status & 0x10000000) == 0x10000000) { -+ writel((1 << 28), port->reg_bridge_apb + ISTATUS_LOCAL); -+ msi = readl(port->reg_bridge_apb + ISTATUS_MSI); -+ for_each_set_bit(bit, &msi, MICROSEMI_NUM_MSI_IRQS) { -+ /* clear interrupts */ -+ writel((1 << bit), -+ port->reg_bridge_apb + ISTATUS_MSI); -+ virq = irq_find_mapping(port->msi_domain, bit); -+ if (virq) -+ generic_handle_irq(virq); -+ else -+ dev_err(dev, "unexpected IRQ, INT%d\n", bit); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * microsemi_pcie_init_irq_domain - Initialize IRQ domain -+ * @port: PCIe port information -+ * -+ * Return: '0' on success and error value on failure -+ */ -+static int microsemi_pcie_init_irq_domain(struct microsemi_pcie_port *port) -+{ -+ struct device *dev = port->dev; -+ struct device_node *node = dev->of_node; -+ struct device_node *pcie_intc_node; -+ -+ /* Setup INTx */ -+ pcie_intc_node = of_get_next_child(node, NULL); -+ if (!pcie_intc_node) { -+ dev_err(dev, "No PCIe Intc node found\n"); -+ return -ENODEV; -+ } -+ dev_info(dev, "Intc node foundi %s\n", pcie_intc_node->name); -+ -+ port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, -+ &intx_domain_ops, -+ port); -+ if (!port->leg_domain) { -+ dev_err(dev, "Failed to get a INTx IRQ domain\n"); -+ return -ENODEV; -+ } -+ -+ /* Setup MSI */ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) { -+ port->msi_domain = irq_domain_add_linear(node, -+ MICROSEMI_NUM_MSI_IRQS, -+ &msi_domain_ops, -+ µsemi_pcie_msi_chip); -+ if (!port->msi_domain) { -+ dev_err(dev, "Failed to get a MSI IRQ domain\n"); -+ return -ENODEV; -+ } -+ microsemi_pcie_enable_msi(port); -+ } -+ return 0; -+} -+ -+/** -+ * microsemi_pcie_init_port - Parse Device tree, Initialize hardware -+ * @port: PCIe port information -+ * -+ * Return: '0' on success and error value on failure -+ */ -+static int microsemi_pcie_init_port(struct microsemi_pcie_port *port) -+{ -+ struct device *dev = port->dev; -+ struct device_node *node = dev->of_node; -+ struct of_pci_range_parser parser; -+ struct of_pci_range range; -+ struct resource regs; -+ struct resource regs1; -+ resource_size_t size; -+ u32 bit, pf_bridge_id = 1; -+ const char *type; -+ int err; -+ -+ type = of_get_property(node, "device_type", NULL); -+ if (!type || strcmp(type, "pci")) { -+ dev_err(dev, "invalid \"device_type\" %s\n", type); -+ return -EINVAL; -+ } -+ -+ err = of_address_to_resource(node, 0, ®s); -+ if (err) { -+ dev_err(dev, "missing \"reg\" property\n"); -+ return err; -+ } -+ -+ port->reg_base = devm_pci_remap_cfg_resource(dev, ®s); -+ if (IS_ERR(port->reg_base)) -+ return PTR_ERR(port->reg_base); -+ -+ -+ err = of_address_to_resource(node, 1, ®s1); -+ if (err) { -+ dev_err(dev, "missing \"reg\" property\n"); -+ return err; -+ } -+ -+ -+ port->reg_base_apb = devm_ioremap_resource(dev, ®s1); -+ if (IS_ERR(port->reg_base_apb)) -+ return PTR_ERR(port->reg_base_apb); -+ -+ if (pf_bridge_id == 0) { -+ port->reg_bridge_apb = port->reg_base_apb + PCIE0_BRIDGE_ADDR; -+ port->reg_ctrl_apb = port->reg_base_apb + PCIE0_CRTL_ADDR; -+ } else { -+ port->reg_bridge_apb = port->reg_base_apb + PCIE1_BRIDGE_ADDR; -+ port->reg_ctrl_apb = port->reg_base_apb + PCIE1_CRTL_ADDR; -+ } -+ -+ port->irq = irq_of_parse_and_map(node, 0); -+ -+ err = devm_request_irq(dev, port->irq, microsemi_pcie_intr_handler, -+ IRQF_SHARED | IRQF_NO_THREAD, -+ "microsemi-pcie", port); -+ if (err) { -+ dev_err(dev, "unable to request irq %d\n", port->irq); -+ return err; -+ } -+ -+ -+ /* Clear and Disable interrupts */ -+ -+ writel(0x0f000000, port->reg_ctrl_apb + ECC_CONTROL); -+ writel(0x00070007, port->reg_ctrl_apb + PCIE_EVENT_INT); -+ writel(0x0000ffff, port->reg_ctrl_apb + SEC_ERROR_INT); -+ writel(0x0000ffff, port->reg_ctrl_apb + SEC_ERROR_INT_MASK); -+ writel(0x0000ffff, port->reg_ctrl_apb + DED_ERROR_INT); -+ writel(0x0000ffff, port->reg_ctrl_apb + DED_ERROR_INT_MASK); -+ -+ writel(0x00000000, port->reg_bridge_apb + IMASK_LOCAL); -+ writel(0xffffffff, port->reg_bridge_apb + ISTATUS_LOCAL); -+ writel(0x00000000, port->reg_bridge_apb + IMASK_HOST); -+ writel(0xffffffff, port->reg_bridge_apb + ISTATUS_HOST); -+ -+ dev_info(dev, "interrupt disabled\n"); -+ -+ /* Configure Address Translation Table 0 for pcie config space */ -+ -+ writel(PCIE_CONFIG_INTERFACE, -+ port->reg_bridge_apb + ATR0_AXI4_SLV0_TRSL_PARAM); -+ -+ size = resource_size(®s); -+ -+ bit = find_first_bit((const unsigned long *)&size, 64) - 1; -+ -+ writel((u32)regs.start | bit << 1 | 0x01, -+ port->reg_bridge_apb + ATR0_AXI4_SLV0_SRCADDR_PARAM); -+ -+// writel((u32)(regs.start >> 32), -+// port->reg_bridge_apb + ATR0_AXI4_SLV0_SRC_ADDR); -+ -+ writel((u32)regs.start, -+ port->reg_bridge_apb + ATR0_AXI4_SLV0_TRSL_ADDR_LSB); -+ -+// writel((u32)(regs.start >> 32), -+// port->reg_bridge_apb + ATR0_AXI4_SLV0_TRSL_ADDR_UDW); -+ -+ -+ if (of_pci_range_parser_init(&parser, node)) { -+ dev_err(dev, "missing \"ranges\" property\n"); -+ return -EINVAL; -+ } -+ -+ -+ for_each_of_pci_range(&parser, &range) { -+ switch (range.flags & IORESOURCE_TYPE_BITS) { -+ case IORESOURCE_MEM: -+ -+ size = range.size; -+ bit = find_first_bit((const unsigned long *)&size, 64) - 1; -+ -+ /* Configure Address Translation Table 1 for pcie mem space */ -+ -+ writel(PCIE_TX_RX_INTERFACE, -+ port->reg_bridge_apb + ATR1_AXI4_SLV0_TRSL_PARAM); -+ -+ writel((u32)range.cpu_addr | bit << 1 | 0x01, -+ port->reg_bridge_apb + ATR1_AXI4_SLV0_SRCADDR_PARAM); -+ -+// writel((u32)(range.cpu_addr >> 32), -+// port->reg_bridge_apb + ATR1_AXI4_SLV0_SRC_ADDR); -+ -+ writel((u32)range.pci_addr, -+ port->reg_bridge_apb + ATR1_AXI4_SLV0_TRSL_ADDR_LSB); -+ -+// writel((u32)(range.pci_addr >> 32), -+// port->reg_bridge_apb + ATR1_AXI4_SLV0_TRSL_ADDR_UDW); -+ -+ break; -+ } -+ -+ } -+ -+ -+ writel(readl(port->reg_bridge_apb + ATR0_PCIE_WIN0_SRCADDR_PARAM) -+ | 0x3E, -+ port->reg_bridge_apb + ATR0_PCIE_WIN0_SRCADDR_PARAM); -+ -+ writel(0, port->reg_bridge_apb + 0x604); -+ -+ writel((readl(port->reg_bridge_apb + PCIE_PCI_IDS_DW1) & 0xffff) -+ | (PCI_CLASS_BRIDGE_PCI << 16), -+ port->reg_bridge_apb + PCIE_PCI_IDS_DW1); -+ -+ pcie_write(port, 0x00ff0100, 0x18); -+ -+ /* Enable interrupts */ -+ writel(PCIE_ENABLE_MSI | PCIE_LOCAL_INT_ENABLE, -+ port->reg_bridge_apb + IMASK_LOCAL); -+ -+ -+ return 0; -+} -+ -+/** -+ * microsemi_pcie_probe - Probe function -+ * @pdev: Platform device pointer -+ * -+ * Return: '0' on success and error value on failure -+ */ -+static int microsemi_pcie_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct microsemi_pcie_port *port; -+ struct pci_bus *bus, *child; -+ struct pci_host_bridge *bridge; -+ int err; -+ resource_size_t iobase = 0; -+ LIST_HEAD(res); -+ -+ pr_err("%s In \n", __func__); -+ if (!dev->of_node) -+ return -ENODEV; -+ -+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port)); -+ if (!bridge) -+ return -ENODEV; -+ -+ port = pci_host_bridge_priv(bridge); -+ -+ port->dev = dev; -+ port->pdev = pdev; -+ -+ err = microsemi_pcie_init_port(port); -+ if (err) { -+ dev_err(dev, "Pcie port initialization failed\n"); -+ return err; -+ } -+ -+ -+ err = microsemi_pcie_init_irq_domain(port); -+ if (err) { -+ dev_err(dev, "Failed creating IRQ Domain\n"); -+ return err; -+ } -+ -+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -+ &iobase); -+ if (err) { -+ dev_err(dev, "Getting bridge resources failed\n"); -+ return err; -+ } -+ -+ err = devm_request_pci_bus_resources(dev, &res); -+ if (err) -+ goto error; -+ -+ -+ list_splice_init(&res, &bridge->windows); -+ bridge->dev.parent = dev; -+ bridge->sysdata = port; -+ bridge->busnr = 0; -+ bridge->ops = µsemi_pcie_ops; -+ bridge->map_irq = of_irq_parse_and_map_pci; -+ bridge->swizzle_irq = pci_common_swizzle; -+ -+#ifdef CONFIG_PCI_MSI -+ microsemi_pcie_msi_chip.dev = dev; -+ bridge->msi = µsemi_pcie_msi_chip; -+#endif -+ err = pci_scan_root_bus_bridge(bridge); -+ dev_info(dev, "pci_scan_root_bus_bridge done\n"); -+ if (err < 0) -+ goto error; -+ -+ bus = bridge->bus; -+ -+ pci_assign_unassigned_bus_resources(bus); -+ list_for_each_entry(child, &bus->children, node) -+ pcie_bus_configure_settings(child); -+ pci_bus_add_devices(bus); -+ -+ return 0; -+ -+error: -+ pci_free_resource_list(&res); -+ return err; -+} -+ -+static const struct of_device_id microsemi_pcie_of_match[] = { -+ { .compatible = "ms-pf,axi-pcie-host", }, -+ {} -+}; -+ -+static struct platform_driver microsemi_pcie_driver = { -+ .driver = { -+ .name = "microsemi-pcie", -+ .of_match_table = microsemi_pcie_of_match, -+ .suppress_bind_attrs = true, -+ }, -+ .probe = microsemi_pcie_probe, -+}; -+builtin_platform_driver(microsemi_pcie_driver); --- -2.7.4 - -- 2.30.2