RISC-V Linux Port v9
Subsystems (10)
Palmer Dabbelt
maintainerAs per suggestions on our v8 patch set, I've split the core architecture code out from our drivers and would like to submit this patch set to be included into linux-next, with the goal being to be merged in during the next merge window. This patch set is based on 4.14-rc2, but if it's better to have it based on something else then I can change it around.
This patch set contains just the core arch code for RISC-V, so while it builds an nominally boots, you can't print or take an interrupt so it's not that useful. If you're looking to actually boot a system it would probably be better to use the full patch set listed below. We're in the process of cleaning up our drivers so we can submit them to the relevant maintainers, but I thought it was most important to get the core code in shape first.
We've collected a handful of tags from reviewers, and the remainder of the patch set only got minimal feedback last time. Here's what changed:
* We now use the device tree to initialize the timer driver so it's less tighly coupled with the arch port.
* I cleaned up the defconfigs -- there's actually now just one, and it's empty. For now I think we're OK with what the kernel sets as defaults, but I anticipate we'll begin to expand this as people start to use the port more.
* The VDSO symbols version is sane.
* We WFI while spinning in the boot loop.
* A handful of comments have been added.
While there are still a handful of FIXMEs in this patch set, we've started to get enough interest from various users and contributors that maintaining an out of tree patch set is starting to become a big burden. I'm hoping the patches are good enough that we can get them merged soon, as that way everyone will be able to work in a more reasonable fashion. I believe I've taken into account everyone's feedback, but if I've missed anything please just ping me.
This patch set is also availiable on github
https://github.com/riscv/riscv-linux/tree/riscv-for-submission-v9-arch
as is the entire patch set necessary to get a more functional RISC-V system up and running, including a handful of patches that aren't ready for upstream yet.
https://github.com/riscv/riscv-linux/tree/riscv-for-submission-v9
Thanks!
Here's the full patch list, in case something gets lost:
[PATCH v9 01/12] MAINTAINERS: Add RISC-V
[PATCH v9 02/12] lib: Add shared copies of some GCC library routines [PATCH v9 03/12] dt-bindings: RISC-V CPU Bindings
[PATCH v9 04/12] RISC-V: Init and Halt Code
[PATCH v9 05/12] RISC-V: Atomic and Locking Code
[PATCH v9 06/12] RISC-V: Generic library routines and assembly [PATCH v9 07/12] RISC-V: ELF and module implementation [PATCH v9 08/12] RISC-V: Task implementation
[PATCH v9 09/12] RISC-V: Device, timer, IRQs, and the SBI [PATCH v9 10/12] RISC-V: Paging and MMU
[PATCH v9 11/12] RISC-V: User-facing API
[PATCH v9 12/12] RISC-V: Build Infrastructure
Here's the change highlights from the whole patch set:
(v8) I know it may not be the ideal time to submit a patch set right now, as it's the middle of the merge window, but things have calmed down quite a bit in the last month so I thought it would be good to get everyone on the same page. There's been a handful of changes since the last patch set, but most of them are fairly minor:
* We changed PAGE_OFFSET to allowing mapping more physical memory on 64-bit systems. This is user configurable, as it triggers a different code model that generates slightly less efficient code.
* The device tree binding documentation is back, I'd managed to lose it at some point.
* We now pass the atomic64 test suite. The SBI timer driver has been
* refactored.
(v7) It's been a while since my last patch set, but the changes han been fairly minimal:
* The PCI cleanup patches have been dropped, we'll do them as a separate patch set later.
* We've the Kconfig entries from CONFIG_ISA_* to CONFIG_RISCV_ISA_*, to make grep easier.
* There have been a handful of memory model related tweaks in I/O land, particularly relating the PCI and the upcoming platform specification. There are significant comments in the relevant files. This is still a WIP, but I think we're close to getting as good as we're going to get until we end up with some more specifications.
(v6) As it's been only a day since the v5 patch set, the changes are pretty minimal:
* The patch set is now based on linux-next/master, which I believe is a better base now that we're getting closer to upstream.
* EARLY_PRINTK is no longer an option. Since the SBI console is reasonable, there's no penalty to enabling it (and thus no benefit to disabling it).
* The mmap syscalls were refactored a bit.
(v5) Things have really started to calm down, so this is fairly similar to the v4 patch set. The most interesting changes include:
* We've moved back to a single patch set.
* SMP support has been fixed, I was accidentally running on a non-SMP configuration. There were various mistakes all over the tree as a result of this.
* The cmpxchg syscalls have been removed, as they were deemed a bad idea. As a result, RISC-V Linux systems mandate the A extension. The corresponding Kconfig entry to enable builds on non-A systems has been removed.
* A few more atomic fixes: mostly fence changes, but those resulted in a handful of additional macros that were no longer necessary.
* riscv_early_sie has been removed.
(v4) There have only been a few changes since the v3 patch set:
* The cmpxchg64 syscall is no longer enabled on 32-bit systems. It's not possible to provide this on SMP systems, and it's not necessary as glibc knows not to call it.
* We provide a ELF_HWCAP so users can determine the ISA of the machine the kernel is running on.
* The multi-line comments are in a better form.
* There were a handful of headers that could be replaced with the asm-generic versions, and a few unnecessary definitions.
* We no longer use printk, but instead use pr_*.
* A few Kconfig and defconfig entries have been cleaned up.
(v3) A highlight of the changes since the v2 patch set includes:
* We've split out all our drivers into separate patch sets, which I've already sent out to the relevant maintainers. I haven't included those patches in this patch set, but some of them are necessary to build our port. A git tree that contains all our patch sets merged together lives at
<https://github.com/riscv/riscv-linux/tree/riscv-for-submission-v3>.
* The patch set is now split up differently: rather than being split per directory it is split per topic. Hopefully this will make it easier to review the port on the mailing list. The split is a bit rough, so you probably still want to look at the patch set as a whole.
* atomic.h has been completely rewritten and is hopefully now correct. I've attempted to sanitize the various other memory model related code as well, and I think it should all be sane now aside from a handful of FIXMEs commented in the code.
* We've changed the cmpexchg syscall to always exist and to not be multiplexed. There is also a VDSO entry for compare and exchange, which allows kernels with the A extension to execute user code without the A extension reasonably fast.
* Our user-visible register state now contains enough space for the Q extension for 128-bit floating point, as well as a few words to allow extensibility to future ISA extensions like the eventual V extension for vectors.
* A handful of driver cleanups, but these have been split into separate patch sets now so I won't duplicate them here.
(v2) A highlight of the changes since the v1 patch set includes:
* We've split out our drivers into the right places, which means now there's a lot more patches. I'll be submitting these patches to various subsystem maintainers and including them in any future RISC-V patch sets until they've been merged.
* The SBI console driver has been completely rewritten to use the HVC helpers and is now significantly smaller.
* We've begun to use weaker barriers as opposed to just the big "fence". There's still some work to do here, specifically:
- We need fences in the relaxed MMIO functions.
- The non-relaxed MMIO functions are missing R/W bits on their fences.
- Many AMOs need the aq and rl bits set.
* We now have thread_info in task_struct. As a result, sscratch now contains TP instead of SP. This was necessary because thread_info is no longer on the stack.
* A few shared routines have been added that we use instead of creating another arch copy.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Palmer Dabbelt
maintainerPATCH v9 1/12 MAINTAINERS: Add RISC-V
From: Jonathan Neuschäfer <[email protected]>
RISC-V needs a MAINTAINERS entry. Let's add one.
--- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+)
MAINTAINERS +10 -0
@@ -11501,6 +11501,16 @@ S: Maintained F: drivers/mtd/nand/r852.c F: drivers/mtd/nand/r852.h +RISC-V ARCHITECTURE +M: Palmer Dabbelt <[email protected]> +M: Albert Ou <[email protected]> +L: [email protected] +T: git https://github.com/riscv/riscv-linux +S: Supported +F: arch/riscv/ +K: riscv +N: riscv + ROCCAT DRIVERS M: Stefan Achatz <[email protected]> W: http://sourceforge.net/projects/roccat/
Signature · 6 lines
2.13.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Palmer Dabbelt
maintainerPATCH v9 2/12 lib: Add shared copies of some GCC library routines
In reply to Palmer DabbeltMany ports (m32r, microblaze, mips, parisc, score, and sparc) use functionally identical copies of various GCC library routine files, which came up as we were submitting the RISC-V port (which also uses some of these).
This patch adds a new copy of these library routine files, which are functionally identical to the various other copies. These are availiable via Kconfig as CONFIG_GENERIC_$ROUTINE, which currently isn't used anywhere.
--- include/lib/libgcc.h | 43 +++++++++++++++++++++++++++++++ lib/Kconfig | 18 +++++++++++++ lib/Makefile | 8 ++++++ lib/ashldi3.c | 44 ++++++++++++++++++++++++++++++++ lib/ashrdi3.c | 46 +++++++++++++++++++++++++++++++++ lib/cmpdi2.c | 42 ++++++++++++++++++++++++++++++ lib/lshrdi3.c | 45 ++++++++++++++++++++++++++++++++ lib/muldi3.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/ucmpdi2.c | 35 +++++++++++++++++++++++++ 9 files changed, 353 insertions(+) create mode 100644 include/lib/libgcc.h create mode 100644 lib/ashldi3.c create mode 100644 lib/ashrdi3.c create mode 100644 lib/cmpdi2.c create mode 100644 lib/lshrdi3.c create mode 100644 lib/muldi3.c create mode 100644 lib/ucmpdi2.c
include/lib/libgcc.h new file +43 -0
@@ -0,0 +1,43 @@ +/* +* include/lib/libgcc.h +* +* 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. +*/ + +#ifndef __LIB_LIBGCC_H +#define __LIB_LIBGCC_H + +#include <asm/byteorder.h> + +typedef int word_type __attribute__ ((mode (__word__))); + +#ifdef __BIG_ENDIAN +struct DWstruct { +int high, low; +}; +#elif defined(__LITTLE_ENDIAN) +struct DWstruct { +int low, high; +}; +#else +#error I feel sick. +#endif + +typedef union { +struct DWstruct s; +long long ll; +}DWunion ; + +#endif /* __ASM_LIBGCC_H */
lib/Kconfig +18 -0
@@ -587,3 +587,21 @@ config STRING_SELFTEST bool "Test string functions" endmenu + +config GENERIC_ASHLDI3 + bool + +config GENERIC_ASHRDI3 + bool + +config GENERIC_LSHRDI3 + bool + +config GENERIC_MULDI3 + bool + +config GENERIC_CMPDI2 + bool + +config GENERIC_UCMPDI2 + bool
lib/Makefile +8 -0
@@ -247,3 +247,11 @@ UBSAN_SANITIZE_ubsan.o := n obj-$(CONFIG_SBITMAP) += sbitmap.o obj-$(CONFIG_PARMAN) += parman.o + +# GCC library routines +obj-$(CONFIG_GENERIC_ASHLDI3) += ashldi3.o +obj-$(CONFIG_GENERIC_ASHRDI3) += ashrdi3.o +obj-$(CONFIG_GENERIC_LSHRDI3) += lshrdi3.o +obj-$(CONFIG_GENERIC_MULDI3) += muldi3.o +obj-$(CONFIG_GENERIC_CMPDI2) += cmpdi2.o +obj-$(CONFIG_GENERIC_UCMPDI2) += ucmpdi2.o
lib/ashldi3.c new file +44 -0
44 lines not on this page · raw message
lib/ashrdi3.c new file +46 -0
46 lines not on this page · raw message
lib/cmpdi2.c new file +42 -0
42 lines not on this page · raw message
lib/lshrdi3.c new file +45 -0
45 lines not on this page · raw message
lib/muldi3.c new file +72 -0
72 lines not on this page · raw message
lib/ucmpdi2.c new file +35 -0
@@ -0,0 +1,35 @@ +/* +* 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 <linux/module.h> +#include <lib/libgcc.h> + +word_type __ucmpdi2 (unsigned long long a,unsigned long long b) +{ +const DWunion au = {.ll = a}; +const DWunion bu = {.ll = b}; + +if ((unsigned int ) au.s.high < (unsigned int ) bu.s.high) +return 0 ; +else if ((unsigned int ) au.s.high > (unsigned int ) bu.s.high) +return 2 ; +if ((unsigned int ) au.s.low < (unsigned int ) bu.s.low) +return 0 ; +else if ((unsigned int ) au.s.low > (unsigned int ) bu.s.low) +return 2 ; +return 1 ; +} +EXPORT_SYMBOL (__ucmpdi2);
Signature · 1 line
2.13.5
Palmer Dabbelt
maintainerPATCH v9 3/12 dt-bindings: RISC-V CPU Bindings
In reply to Palmer DabbeltThis patch adds device tree bindings for RISC-V CPUs, patterned after the ARM device tree CPU bindings.
--- Documentation/devicetree/bindings/riscv/cpus.txt | 162 +++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 Documentation/devicetree/bindings/riscv/cpus.txt
Documentation/devicetree/bindings/riscv/cpus.txt new file +162 -0
@@ -0,0 +1,162 @@ +=================== +RISC-V CPU Bindings +=================== + +The device tree allows to describe the layout of CPUs in a system through +the "cpus" node, which in turn contains a number of subnodes (ie "cpu") +defining properties for every cpu. + +Bindings for CPU nodes follow the Devicetree Specification, available from: + +https://www.devicetree.org/specifications/ + +with updates for 32-bit and 64-bit RISC-V systems provided in this document. + +=========== +Terminology +=========== + +This document uses some terminology common to the RISC-V community that is not +widely used, the definitions of which are listed here: + +* hart: A hardware execution context, which contains all the state mandated by + the RISC-V ISA: a PC and some registers. This terminology is designed to + disambiguate software's view of execution contexts from any particular + microarchitectural implementation strategy. For example, my Intel laptop is + described as having one socket with two cores, each of which has two hyper + threads. Therefore this system has four harts. + +===================================== +cpus and cpu node bindings definition +===================================== + +The RISC-V architecture, in accordance with the Devicetree Specification, +requires the cpus and cpu nodes to be present and contain the properties +described below. + +- cpus node + + Description: Container of cpu nodes + + The node name must be "cpus". + + A cpus node must define the following properties: + + - #address-cells + Usage: required + Value type: <u32> + Definition: must be set to 1 + - #size-cells + Usage: required + Value type: <u32> + Definition: must be set to 0 + +- cpu node + + Description: Describes a hart context + + PROPERTIES + + - device_type + Usage: required + Value type: <string> + Definition: must be "cpu" + - reg + Usage: required + Value type: <u32> + Definition: The hart ID of this CPU node + - compatible: + Usage: required + Value type: <stringlist> + Definition: must contain "riscv", may contain one of + "sifive,rocket0" + - mmu-type: + Usage: optional + Value type: <string> + Definition: Specifies the CPU's MMU type. Possible values are + "riscv,sv32" + "riscv,sv39" + "riscv,sv48" + - riscv,isa: + Usage: required + Value type: <string> + Definition: Contains the RISC-V ISA string of this hart. These + ISA strings are defined by the RISC-V ISA manual. + +Example: SiFive Freedom U540G Development Kit +--------------------------------------------- + +This system contains two harts: a hart marked as disabled that's used for +low-level system tasks and should be ignored by Linux, and a second hart that +Linux is allowed to run on. + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <1000000>; + cpu@0 { + clock-frequency = <1600000000>; + compatible = "sifive,rocket0", "riscv"; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <16384>; + next-level-cache = <&L15 &L0>; + reg = <0>; + riscv,isa = "rv64imac"; + status = "disabled"; + L10: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu@1 { + clock-frequency = <1600000000>; + compatible = "sifive,rocket0", "riscv"; + d-cache-block-size = <64>; + d-cache-sets = <64>; + d-cache-size = <32768>; + d-tlb-sets = <1>; + d-tlb-size = <32>; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <64>; + i-cache-size = <32768>; + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv39"; + next-level-cache = <&L15 &L0>; + reg = <1>; + riscv,isa = "rv64imafdc"; + status = "okay"; + tlb-split; + L13: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + +Example: Spike ISA Simulator with 1 Hart +---------------------------------------- + +This device tree matches the Spike ISA golden model as run with `spike -p1`. + + cpus { + cpu@0 { + device_type = "cpu"; + reg = <0x00000000>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv48"; + clock-frequency = <0x3b9aca00>; + interrupt-controller { + #interrupt-cells = <0x00000001>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + } + } + }
Signature · 6 lines
2.13.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Mark Rutland
reviewerRe: [PATCH v9 03/12] dt-bindings: RISC-V CPU Bindings
Hi Palmer,
Sorry for the delay in getting round to this.
Quoted 2 lines · Palmer Dabbelt
This patch adds device tree bindings for RISC-V CPUs, patterned after the ARM device tree CPU bindings.
[...]
Quoted 9 lines
+- cpu node
Documentation/devicetree/bindings/riscv/cpus.txt new file +8
-0+ + Description: Describes a hart context + + PROPERTIES + + - device_type + Usage: required + Value type: <string>
Documentation/devicetree/bindings/riscv/cpus.txt line 72
Quoted 10 lines
Documentation/devicetree/bindings/riscv/cpus.txt new file +10
-0+ Definition: must be "cpu" + - reg + Usage: required + Value type: <u32> + Definition: The hart ID of this CPU node + - compatible: + Usage: required + Value type: <stringlist> + Definition: must contain "riscv", may contain one of + "sifive,rocket0"
It might make sense to have "riscv,cpu" as your genric RISC-V CPU compatible string, to avoid ambiguity with the vendor-prefix.
Documentation/devicetree/bindings/riscv/cpus.txt line 79
Quoted 7 lines
Documentation/devicetree/bindings/riscv/cpus.txt new file +7
-0+ - mmu-type: + Usage: optional + Value type: <string> + Definition: Specifies the CPU's MMU type. Possible values are + "riscv,sv32" + "riscv,sv39" + "riscv,sv48"
I would *strongly* recommend that from day one, you determine the SMP bringup mechanism via an enable-method property, and document the contract with FW/bootloader somewhere in the kernel tree.
For arm64 we started by documenting our spin-table in Documentation/arm64/booting.txt, and later added PSCI support.
Using an explicit enable-method property from day one makes it easier to extend thigns without ambiguity. e.g. an old kernel that doesn't know of some new enable-method can just give up on SMP and continue as UP, rather than doing something wrong for that system.
Generally, making things explicit in the DT will make support / extension easier, and help to avoid painful-to-debug bugs.
Documentation/devicetree/bindings/riscv/cpus.txt line 85
Quoted 6 lines
Documentation/devicetree/bindings/riscv/cpus.txt new file +6
-0+ - riscv,isa: + Usage: required + Value type: <string> + Definition: Contains the RISC-V ISA string of this hart. These + ISA strings are defined by the RISC-V ISA manual. +
IIUC from the example, this describes a number of ISA extenstions in a single string. It might make mroe sense to have separate flags for each extension. will be easier for the kernel to parse as new extensions are added, and minimized ambiguity / typo problems.
[...]
Quoted 6 lines
Documentation/devicetree/bindings/riscv/cpus.txt new file +6
-0+Example: Spike ISA Simulator with 1 Hart +---------------------------------------- + +This device tree matches the Spike ISA golden model as run with `spike -p1`. + + cpus {
Documentation/devicetree/bindings/riscv/cpus.txt line 157
Quoted 10 lines
Documentation/devicetree/bindings/riscv/cpus.txt new file +10
-0+ cpu@0 { + device_type = "cpu"; + reg = <0x00000000>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv48"; + clock-frequency = <0x3b9aca00>; + interrupt-controller { + #interrupt-cells = <0x00000001>;
Trivial nit: this would be nicer as:
#interrupt-cells = <1>;
Thanks,
Mark.
Re: [patches] Re: [PATCH v9 03/12] dt-bindings: RISC-V CPU Bindings
Hi Palmer,
On Thu, Oct 05, 2017 at 11:16:33AM +0100, Mark Rutland wrote:
[...]
Quoted 3 lines
I would *strongly* recommend that from day one, you determine the SMP bringup mechanism via an enable-method property, and document the contract with FW/bootloader somewhere in the kernel tree.
Somewhat, but not quite related: Please consider making the availability of the Supervisor Binary Interface explicit in the devicetree. I understand that the general plan is to make the SBI a mandatory feature of every RISC-V system capable of running Linux, but I do want to explore the possibility of running without run-time resident firmware at some point in the future. Thus it would be nice if the devicetree would indicate the presence of the SBI from the start, to avoid having to invent a way to express its *absence* later on.
It could look something like this (modelled after qcom,scm):
/ {
firmware {
sbi {
compatible = "riscv,sbi";
};
};
};This topic may warrant some discussion, because other people may have different opinions, and there hasn't been a discussion about it, AFAICS.
Thanks,
Jonathan Neuschäfer
Palmer Dabbelt
maintainerRe: [patches] Re: [PATCH v9 03/12] dt-bindings: RISC-V CPU Bindings
Quoted 7 lines · On Sun, 19 Nov 2017 23:35:28 PST (-0800), [email protected] wrote:
Hi Palmer,
On Thu, Oct 05, 2017 at 11:16:33AM +0100, Mark Rutland wrote:
[...]Quoted 3 lines
I would *strongly* recommend that from day one, you determine the SMP bringup mechanism via an enable-method property, and document the contract with FW/bootloader somewhere in the kernel tree.
Sorry, I forgot about this. I've prepared a patch.
Quoted 19 lines
Somewhat, but not quite related: Please consider making the availability of the Supervisor Binary Interface explicit in the devicetree. I understand that the general plan is to make the SBI a mandatory feature of every RISC-V system capable of running Linux, but I do want to explore the possibility of running without run-time resident firmware at some point in the future. Thus it would be nice if the devicetree would indicate the presence of the SBI from the start, to avoid having to invent a way to express its *absence* later on.
It could look something like this (modelled after qcom,scm):
/ { firmware { sbi { compatible = "riscv,sbi"; }; }; };
Quoted 2 lines
This topic may warrant some discussion, because other people may have different opinions, and there hasn't been a discussion about it, AFAICS.
I don't think there's any penalty to putting it in the device tree, I'll send a patch.
Palmer Dabbelt
maintainerPATCH v9 4/12 RISC-V: Init and Halt Code
In reply to Palmer DabbeltThis contains the various __init C functions, the initial assembly kernel entry point, and the code to reset the system. When a file was init-related this patch contains the entire file.
--- arch/riscv/include/asm/bug.h | 88 ++++++++++++++ arch/riscv/include/asm/cache.h | 22 ++++ arch/riscv/include/asm/smp.h | 52 +++++++++ arch/riscv/kernel/cacheinfo.c | 105 +++++++++++++++++ arch/riscv/kernel/cpu.c | 108 +++++++++++++++++ arch/riscv/kernel/head.S | 157 +++++++++++++++++++++++++ arch/riscv/kernel/irq.c | 39 +++++++ arch/riscv/kernel/reset.c | 36 ++++++ arch/riscv/kernel/setup.c | 257 +++++++++++++++++++++++++++++++++++++++++ arch/riscv/kernel/smp.c | 110 ++++++++++++++++++ arch/riscv/kernel/smpboot.c | 114 ++++++++++++++++++ arch/riscv/kernel/time.c | 61 ++++++++++ arch/riscv/kernel/traps.c | 180 +++++++++++++++++++++++++++++ arch/riscv/kernel/vdso.c | 125 ++++++++++++++++++++ arch/riscv/mm/init.c | 70 +++++++++++ 15 files changed, 1524 insertions(+) create mode 100644 arch/riscv/include/asm/bug.h create mode 100644 arch/riscv/include/asm/cache.h create mode 100644 arch/riscv/include/asm/smp.h create mode 100644 arch/riscv/kernel/cacheinfo.c create mode 100644 arch/riscv/kernel/cpu.c create mode 100644 arch/riscv/kernel/head.S create mode 100644 arch/riscv/kernel/irq.c create mode 100644 arch/riscv/kernel/reset.c create mode 100644 arch/riscv/kernel/setup.c create mode 100644 arch/riscv/kernel/smp.c create mode 100644 arch/riscv/kernel/smpboot.c create mode 100644 arch/riscv/kernel/time.c create mode 100644 arch/riscv/kernel/traps.c create mode 100644 arch/riscv/kernel/vdso.c create mode 100644 arch/riscv/mm/init.c
arch/riscv/include/asm/bug.h new file +88 -0
@@ -0,0 +1,88 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_BUG_H +#define _ASM_RISCV_BUG_H + +#include <linux/compiler.h> +#include <linux/const.h> +#include <linux/types.h> + +#include <asm/asm.h> + +#ifdef CONFIG_GENERIC_BUG +#define __BUG_INSN _AC(0x00100073, UL)/* ebreak */ + +#ifndef __ASSEMBLY__ +typedef u32 bug_insn_t ; + +#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS +#define __BUG_ENTRY_ADDR INT " 1b - 2b" +#define __BUG_ENTRY_FILE INT " %0 - 2b" +#else +#define __BUG_ENTRY_ADDR RISCV_PTR " 1b" +#define __BUG_ENTRY_FILE RISCV_PTR " %0" +#endif + +#ifdef CONFIG_DEBUG_BUGVERBOSE +#define __BUG_ENTRY \ + __BUG_ENTRY_ADDR "\n\t" \ + __BUG_ENTRY_FILE "\n\t" \ + SHORT " %1" +#else +#define __BUG_ENTRY \ + __BUG_ENTRY_ADDR +#endif + +#define BUG () \ +do { \ + __asm__ __volatile__ ( \ + "1:\n\t" \ + "ebreak\n" \ + ".pushsection __bug_table,\"a\"\n\t" \ + "2:\n\t" \ + __BUG_ENTRY "\n\t" \ + ".org 2b + %2\n\t" \ + ".popsection" \ + : \ + : "i" (__FILE__), "i" (__LINE__), \ + "i" (sizeof(struct bug_entry))); \ + unreachable(); \ +} while (0) +#endif /* !__ASSEMBLY__ */ +#else /* CONFIG_GENERIC_BUG */ +#ifndef __ASSEMBLY__ +#define BUG () \ +do { \ + __asm__ __volatile__ ("ebreak\n"); \ + unreachable(); \ +} while (0) +#endif /* !__ASSEMBLY__ */ +#endif /* CONFIG_GENERIC_BUG */ + +#define HAVE_ARCH_BUG + +#include <asm-generic/bug.h> + +#ifndef __ASSEMBLY__ + +struct pt_regs ; +struct task_struct ; + +extern void die (struct pt_regs *regs,const char *str); +extern void do_trap (struct pt_regs *regs,int signo,int code, +unsigned long addr,struct task_struct *tsk); + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_RISCV_BUG_H */
arch/riscv/include/asm/cache.h new file +22 -0
@@ -0,0 +1,22 @@ +/* +* Copyright (C) 2017 Chen Liqin <[email protected]> +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_CACHE_H +#define _ASM_RISCV_CACHE_H + +#define L1_CACHE_SHIFT 6 + +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#endif /* _ASM_RISCV_CACHE_H */
arch/riscv/include/asm/smp.h new file +52 -0
52 lines not on this page · raw message
arch/riscv/kernel/cacheinfo.c new file +105 -0
105 lines not on this page · raw message
arch/riscv/kernel/cpu.c new file +108 -0
108 lines not on this page · raw message
arch/riscv/kernel/head.S new file +157 -0
157 lines not on this page · raw message
arch/riscv/kernel/irq.c new file +39 -0
@@ -0,0 +1,39 @@ +/* +* 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 <linux/interrupt.h> +#include <linux/irqchip.h> +#include <linux/irqdomain.h> + +#ifdef CONFIG_RISCV_INTC +#include <linux/irqchip/irq-riscv-intc.h> +#endif + +void __init init_IRQ (void ) +{ +irqchip_init (); +} + +asmlinkage void __irq_entry do_IRQ(unsigned int cause, struct pt_regs *regs) +{ +#ifdef CONFIG_RISCV_INTC +/* +* FIXME: We don't want a direct call to riscv_intc_irq here. The plan +* is to put an IRQ domain here and let the interrupt controller +* register with that, but I poked around the arm64 code a bit and +* there might be a better way to do it (ie, something fully generic). +*/ +riscv_intc_irq (cause, regs); +#endif +}
arch/riscv/kernel/reset.c new file +36 -0
@@ -0,0 +1,36 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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 <linux/reboot.h> +#include <linux/export.h> +#include <asm/sbi.h> + +void (*pm_power_off)(void ) = machine_power_off; +EXPORT_SYMBOL (pm_power_off); + +void machine_restart (char *cmd) +{ +do_kernel_restart (cmd); +while (1 ); +} + +void machine_halt (void ) +{ +machine_power_off (); +} + +void machine_power_off (void ) +{ +sbi_shutdown (); +while (1 ); +}
arch/riscv/kernel/setup.c new file +257 -0
257 lines not on this page · raw message
arch/riscv/kernel/smp.c new file +110 -0
110 lines not on this page · raw message
arch/riscv/kernel/smpboot.c new file +114 -0
114 lines not on this page · raw message
arch/riscv/kernel/time.c new file +61 -0
61 lines not on this page · raw message
arch/riscv/kernel/traps.c new file +180 -0
180 lines not on this page · raw message
arch/riscv/kernel/vdso.c new file +125 -0
125 lines not on this page · raw message
arch/riscv/mm/init.c new file +70 -0
70 lines not on this page · raw message
Signature · 1 line
2.13.5
Mark Rutland
reviewerRe: [PATCH v9 04/12] RISC-V: Init and Halt Code
arch/riscv/include/asm/smp.h line 45
Quoted 7 lines · Palmer Dabbelt
arch/riscv/include/asm/smp.h new file +7
-0+/* +* 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. +*/ +#define raw_smp_processor_id () (*((int*)((char*)get_current() + TASK_TI_CPU)))
Are you using CONFIG_THREAD_INFO_IN_TASK?
I assume so, becauase 'TI' usually stands for thread_info.
So if you can include your <asm/thread_info.h> here, I think you can do something like:
#define get_ti() ((struct thread_info *)get_current())
#define raw_smp_processor_id() (get_ti()->cpu)
[...]
Quoted 5 lines
arch/riscv/kernel/cacheinfo.c new file +5
-0+static void ci_leaf_init (struct cacheinfo *this_leaf, +struct device_node *node, +enum cache_type type,unsigned int level) +{ + this_leaf->of_node = node;
arch/riscv/kernel/cacheinfo.c line 33
Quoted 10 lines
arch/riscv/kernel/cacheinfo.c new file +10
-0+ 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 ; +}
In practice, it's very hard to remove implicit assumptions later down the line, so I'd recommend you add this to your DT from the outset.
[...]
arch/riscv/kernel/cpu.c line 19
Quoted 2 lines
arch/riscv/kernel/cpu.c new file +2
-0+/* Return -1 if not a valid hart */ +int riscv_of_processor_hart (struct device_node *node)
Perhaps s/hart/hart_id/ for the function name? Otherwise, it's not immediately obvious what it is doing.
Quoted 7 lines
arch/riscv/kernel/cpu.c new file +7
-0+{ +const char *isa, *status; +u32 hart; + +if (!of_device_is_compatible (node,"riscv" )) { +pr_warn ("Found incompatible CPU\n" ); +return -(ENODEV );
arch/riscv/kernel/cpu.c line 36
Quoted 10 lines
arch/riscv/kernel/cpu.c new file +10
-0+ } + +if (of_property_read_u32 (node,"reg" , &hart)) { +pr_warn ("Found CPU without hart ID\n" ); +return -(ENODEV ); + } +if (hart >=NR_CPUS ) { +pr_info ("Found hart ID %d, which is above NR_CPUs. Disabling this hart\n" , hart); +return -(ENODEV ); + }
Here you assume that the hard ID is equalt to the Linux logical ID.
I'd recommend that (as other architectures do), you decouple the two.
That's going to be necessary for things like kdump to work, as the kdump kernel will run on (Linux logical) CPU0, but may have been executed from any secondary CPU.
arch/riscv/kernel/cpu.c line 45
Quoted 9 lines
arch/riscv/kernel/cpu.c new file +9
-0+ +if (of_property_read_string (node,"status" , &status)) { +pr_warn ("CPU with hartid=%d has no \"status\" property\n" , hart); +return -(ENODEV ); + } +if (strcmp (status,"okay" )) { +pr_info ("CPU with hartid=%d has a non-okay status of \"%s\"\n" , hart, status); +return -(ENODEV ); + }
Please use of_device_is_available().
arch/riscv/kernel/cpu.c line 54
Quoted 9 lines
arch/riscv/kernel/cpu.c new file +9
-0+ +if (of_property_read_string (node,"riscv,isa" , &isa)) { +pr_warn ("CPU with hartid=%d has no \"riscv,isa\" property\n" , hart); +return -(ENODEV ); + } +if (isa[0 ] !='r' || isa[1 ] !='v' ) { +pr_warn ("CPU with hartid=%d has an invalid ISA of \"%s\"\n" , hart, isa); +return -(ENODEV ); + }
As mentioned on the binding patch, I'd recommend that you use a set of discrete flags.
[...]
Quoted 8 lines
arch/riscv/kernel/cpu.c new file +8
-0+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 ); +const char *compat, *isa, *mmu; + +seq_printf (m,"hart\t: %lu\n" , hart_id); + if (!of_property_read_string(node, "riscv,isa", &isa)
arch/riscv/kernel/cpu.c line 96
Quoted 10 lines
arch/riscv/kernel/cpu.c new file +10
-0+ && 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,"compatible" , &compat) + &&strcmp (compat,"riscv" )) +seq_printf (m,"uarch\t: %s\n" , compat); +seq_puts (m,"\n" );
I'd *very strongly* recommend that you don't pass the DT values straight through to userspace.
Otherwise, things like riscv,isa = "rvtypo'd\nsomething" get exposed, and inevitably, some subset of userspace ends up relying upon it, while others break based upon it.
Further, specifically for the ISA parts, this is a very bad idea. If some ISA extensions require kernel support (e.g. to context switch state, or disable some configurable traps), they cannot work without kernel support. Generally, the wayt to handle this is for the kernel to detect the features at boot time, and save these in hwcaps.
Later, the hwcaps can be used to generate /proc/cpunifo output, and are also exposed via auxv, which avoids applications and libraries having to parse /proc/cpuinfo just to determine whether they have a particular feature, which doesn't work in many situations (e.g. early boot where /proc may not be mounted).
Take a look at arm64's hwcaps for an example of how to use hwcaps.
[...]
I deleted the context from my draft, but I didn't spot a header sta the start of your head.S. I would very strongly recommend that you have a header with magic, image size (including unpopulated BSS), and other room for expansion, so that bootloaders can figure out how to load your kernel correctly.
[...]
Quoted 12 lines
arch/riscv/kernel/head.S new file +12
-0+ENTRY(_start) + /* Mask all interrupts */ + csrw sie, zero + + /* Load the global pointer */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* + * Disable FPU to detect illegal usage of
arch/riscv/kernel/head.S line 45
Quoted 10 lines
arch/riscv/kernel/head.S new file +10
-0+ * floating point in kernel space + */ + li t0, SR_FS + csrc sstatus, t0 + + /* Pick one hart to run the main boot sequence */ + la a3, hart_lottery + li a2, 1 + amoadd.w a3, a2, (a3) + bnez a3, .Lsecondary_start
I would *very strongly* recommend that you do not throw all CPUs into the kernel at the start of time, and instead have a mechanism where you can bring CPUs into the kernel individually.
While it's simple, it comes with a number of long term problems (e.g. for kexec/kdump), some of which are unsolvable (e.g. as you cannot know how many CPUs are stuck in the kernel text, which haven't been brought online).
If you want a simple SMP bringup mechanism, ePAPR's spin-table (and arm64's different-but-identically-named spin-table) are good starting points. Just make sure you require each CPU is brought online individually. We didn't do that for arm64 from day one, and it still prevents us from making improvements that we'd like to, years later.
Doing that will also simplify decoupling the HART IDs from linux logical IDs, necessary for kdump/kexec, etc.
[...]
Quoted 4 lines
+/*
+ * Allow the user to manually add a memory region (in case DTS is broken);
+ * "mem_end=nn[KkMmGg]"
+ */
This doesn't have a start, so it can't work for discontiguous memory blocks (e.g. if FW has reserved/carved-out a chunk in the middle).
Other architectures have "mem=" which would allow you to specify a region. I'd generally recommend you provide an incentive to fix dts, however.
arch/riscv/kernel/setup.c line 215
Quoted 8 lines
arch/riscv/kernel/setup.c new file +8
-0+void __init setup_arch (char **cmdline_p) +{ +#if defined(CONFIG_HVC_RISCV_SBI ) +if (likely (early_console ==NULL )) { + early_console = &riscv_sbi_early_console_dev; +register_console (early_console); + } +#endif
This would be better driven by the DT or command line. Otherwise, this may come back to bite you in future, as you have to come up with a new mechanism to describe absence of the console, rather than using an exsiting mechanism to describe its presence.
[...]
Quoted 13 lines
arch/riscv/kernel/smpboot.c new file +13
-0+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 ; + +while ((dn =of_find_node_by_type (dn,"cpu" ))) { + hart =riscv_of_processor_hart (dn); +if (hart >=0 ) { +set_cpu_possible (hart, true);
arch/riscv/kernel/smpboot.c line 68
Quoted 10 lines
arch/riscv/kernel/smpboot.c new file +10
-0+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 (!im_okay_therefore_i_am); +}
That name is somewhat opaque. Perhaps bool found_boot_cpu?
Quoted 5 lines
arch/riscv/kernel/smpboot.c new file +5
-0+ +int __cpu_up (unsigned int cpu,struct task_struct *tidle) +{ + tidle->thread_info.cpu = cpu; +
arch/riscv/kernel/smpboot.c line 83
Quoted 10 lines
arch/riscv/kernel/smpboot.c new file +10
-0+/* +* On RISC-V systems, all harts boot on their own accord. Our _start +* selects the first hart to boot the kernel and causes the remainder +* of the harts to spin in a loop waiting for their stack pointer to be +* setup by that main hart. Writing __cpu_up_stack_pointer signals to +* 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;
Shouldn't these be WRITE_ONCE() (or some atomic) to avoid tearing?
How are the secondaries reading these? Is there any requirement on the order these become visible?
[...]
arch/riscv/kernel/smpboot.c line 103
Quoted 9 lines
arch/riscv/kernel/smpboot.c new file +9
-0+/* +* C entry point for a secondary processor. +*/ +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);
I beleive this should be:
mmgrab(mm);
See commit f1f1007644ffc805 ("mm: add new mmgrab() helper")
arch/riscv/kernel/smpboot.c line 110
Quoted 7 lines
arch/riscv/kernel/smpboot.c new file +7
-0+ current->active_mm = mm; + +trap_init (); +init_clockevent (); +notify_cpu_starting (smp_processor_id ()); +set_cpu_online (smp_processor_id (),1 ); +local_flush_tlb_all ();
Why do you need a TLB flush here?
arch/riscv/kernel/smpboot.c line 112
Quoted 2 lines
arch/riscv/kernel/smpboot.c new file +2
-0+local_irq_enable (); +preempt_disable ();
I believe these two should be the other way around, if the preempt_disable() is necessary.
Thanks,
Mark.
Palmer Dabbelt
maintainerRe: [PATCH v9 04/12] RISC-V: Init and Halt Code
Sorry it took me an absurd amount of time to get back around to this... I'm adding our mailing list, as we didn't even have one a year ago.
I've included a few patches in line here, but they're just drafts. I'll test them and submit them properly.
Quoted 11 lines · On Thu, 05 Oct 2017 04:01:12 PDT (-0700), [email protected] wrote:
arch/riscv/include/asm/smp.h line 45
Quoted 7 lines · Palmer Dabbelt
arch/riscv/include/asm/smp.h new file +7
-0+/* +* 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. +*/ +#define raw_smp_processor_id () (*((int*)((char*)get_current() + TASK_TI_CPU)))Are you using
CONFIG_THREAD_INFO_IN_TASK?
Quoted 7 lines
I assume so, becauase 'TI' usually stands for
thread_info.So if you can include your <
asm/thread_info.h> here, I think you can do something like:#define
get_ti()((structthread_info*)get_current())
#defineraw_smp_processor_id()(get_ti()->cpu)
Thanks. I'm not sure how I didn't manage to figure that out, but it appears to work.
commit d999f1419829c708462dacbfe8d62a795ba6cecc
gpg: Signature made Tue 24 Jul 2018 04:12:45 PM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Tue Jul 24 16:11:54 2018 -0700
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 <[email protected]>
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 85e4220839b0..f6a1df5c8df8 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -14,11 +14,6 @@
#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 <asm/asm-offsets.h>
-#endif
-
#include <linux/cpumask.h>
#include <linux/irqreturn.h>
@@ -36,13 +31,12 @@ 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);
-/*
- * 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.
- */
-#define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU)))
+/* Obtains the hart ID of the currently executing task. This relies on
+ * THREAD_INFO_IN_TASK, but we define that unconditionally. */
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define get_ti() ((struct thread_info *)get_current())
+#define raw_smp_processor_id() (get_ti()->cpu)
+#endif
/* Interprocessor interrupt handler */
irqreturn_t handle_ipi(void);Quoted 10 lines
Quoted 10 lines
arch/riscv/kernel/cacheinfo.c new file +10
-0+static void ci_leaf_init (struct cacheinfo *this_leaf, +struct device_node *node, +enum cache_type type,unsigned int level) +{ + this_leaf->of_node = node; + this_leaf->level = level; + this_leaf->type = type; +/* not a sector cache */ + this_leaf->physical_line_partition =1 ; +/* TODO: Add to DTS */
Quoted 8 lines
arch/riscv/kernel/cacheinfo.c line 33
Quoted 5 lines
arch/riscv/kernel/cacheinfo.c new file +5
-0+ this_leaf->attributes = +CACHE_WRITE_BACK + |CACHE_READ_ALLOCATE + |CACHE_WRITE_ALLOCATE ; +}In practice, it's very hard to remove implicit assumptions later down the line, so I'd recommend you add this to your DT from the outset.
Are these actually used by anything? I poked around the kernel and it appears that pretty much all they do is get printed in drivers/base/cacheinfo.c. It looks like we're only filling out half the info in there anyway so it feels like we'd be better off just deleting these and waiting until we have a proper scheme before setting anything.
Quoted 5 lines
arch/riscv/kernel/cpu.c line 19
Quoted 2 lines
arch/riscv/kernel/cpu.c new file +2
-0+/* Return -1 if not a valid hart */ +int riscv_of_processor_hart (struct device_node *node)Perhaps s/hart/hart_id/ for the function name? Otherwise, it's not immediately obvious what it is doing.
Makes sense. I've gone and added a comment as well:
commit c1547731897ca4cb683fbb3bf26dd243a9ed6486
gpg: Signature made Wed 25 Jul 2018 02:36:07 PM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Wed Jul 25 14:31:57 2018 -0700
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.
Signed-off-by: Palmer Dabbelt <[email protected]>
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 3fe4af8147d2..9d32670d84a4 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -88,7 +88,9 @@ static inline void wait_for_interrupt(void)
}
struct device_node;
-extern 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. */
+extern 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 ca6c81e54e37..19e98c1710dd 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -16,7 +16,7 @@
#include <linux/of.h>
/* Return -1 if not a valid hart */
-int riscv_of_processor_hart(struct device_node *node)
+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 f741458c5a3f..e08efc60726c 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);Quoted 20 lines
Quoted 7 lines
arch/riscv/kernel/cpu.c new file +7
-0+{ +const char *isa, *status; +u32 hart; + +if (!of_device_is_compatible (node,"riscv" )) { +pr_warn ("Found incompatible CPU\n" ); +return -(ENODEV );arch/riscv/kernel/cpu.c line 36
Quoted 10 lines
arch/riscv/kernel/cpu.c new file +10
-0+ } + +if (of_property_read_u32 (node,"reg" , &hart)) { +pr_warn ("Found CPU without hart ID\n" ); +return -(ENODEV ); + } +if (hart >=NR_CPUS ) { +pr_info ("Found hart ID %d, which is above NR_CPUs. Disabling this hart\n" , hart); +return -(ENODEV ); + }Here you assume that the hard ID is equalt to the Linux logical ID.
Quoted 5 lines
I'd recommend that (as other architectures do), you decouple the two.
That's going to be necessary for things like kdump to work, as the kdump kernel will run on (Linux logical) CPU0, but may have been executed from any secondary CPU.
This is a good point. We currently have another headache with CPU numbering on some systems where the machine CPU ID of 0 actually isn't a Linux CPU (ie, it doesn't have virtual memory) and we're handling the remapping in the bootloader. That's a bit convoluted, so it might be easier to handle the remapping in Linux.
Quoted 12 lines
arch/riscv/kernel/cpu.c line 45
Quoted 9 lines
arch/riscv/kernel/cpu.c new file +9
-0+ +if (of_property_read_string (node,"status" , &status)) { +pr_warn ("CPU with hartid=%d has no \"status\" property\n" , hart); +return -(ENODEV ); + } +if (strcmp (status,"okay" )) { +pr_info ("CPU with hartid=%d has a non-okay status of \"%s\"\n" , hart, status); +return -(ENODEV ); + }Please use
of_device_is_available().
Quoted 12 lines
arch/riscv/kernel/cpu.c line 54
Quoted 9 lines
arch/riscv/kernel/cpu.c new file +9
-0+ +if (of_property_read_string (node,"riscv,isa" , &isa)) { +pr_warn ("CPU with hartid=%d has no \"riscv,isa\" property\n" , hart); +return -(ENODEV ); + } +if (isa[0 ] !='r' || isa[1 ] !='v' ) { +pr_warn ("CPU with hartid=%d has an invalid ISA of \"%s\"\n" , hart, isa); +return -(ENODEV ); + }As mentioned on the binding patch, I'd recommend that you use a set of discrete flags.
RISC-V defines what the ISA string means, and it's got all sorts of mechanism for extensibility already defined. I'm trying to avoid inventing any other encodings of this as they're just going to be incompatible in some subtle way.
Quoted 34 lines
[...]
Quoted 8 lines
arch/riscv/kernel/cpu.c new file +8
-0+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 ); +const char *compat, *isa, *mmu; + +seq_printf (m,"hart\t: %lu\n" , hart_id); + if (!of_property_read_string(node, "riscv,isa", &isa)arch/riscv/kernel/cpu.c line 96
Quoted 10 lines
arch/riscv/kernel/cpu.c new file +10
-0+ && 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,"compatible" , &compat) + &&strcmp (compat,"riscv" )) +seq_printf (m,"uarch\t: %s\n" , compat); +seq_puts (m,"\n" );I'd *very strongly* recommend that you don't pass the DT values straight through to userspace.
Otherwise, things like riscv,isa = "rvtypo'd\nsomething" get exposed, and inevitably, some subset of userspace ends up relying upon it, while others break based upon it.
Further, specifically for the ISA parts, this is a very bad idea. If some ISA extensions require kernel support (e.g. to context switch state, or disable some configurable traps), they cannot work without kernel support. Generally, the wayt to handle this is for the kernel to detect the features at boot time, and save these in hwcaps.
Quoted 7 lines
Later, the hwcaps can be used to generate
/proc/cpunifooutput, and are also exposed via auxv, which avoids applications and libraries having to parse/proc/cpuinfojust to determine whether they have a particular feature, which doesn't work in many situations (e.g. early boot where /proc may not be mounted).Take a look at arm64's hwcaps for an example of how to use hwcaps.
Yes, that's a very good point. We actually have an implementation of hwcaps (that's exposed via the aux vector) that's cropped up in the mean time, and while the right thing to do is probably to generate cpuinfo from that I do at least have a simple patch that allows us to avoid passing garbage to userspace:
commit 6dbfebe5b2ddd873283abf625556b99f98cc85f2
gpg: Signature made Fri 27 Jul 2018 10:40:02 AM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Fri Jul 27 09:57:29 2018 -0700
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.
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 19e98c1710dd..a18b4e3962a1 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -58,6 +58,57 @@ int riscv_of_processor_hartid(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_printf(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 +134,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);
Quoted 42 lines
[...]
I deleted the context from my draft, but I didn't spot a header sta the start of your
head.S. I would very strongly recommend that you have a header with magic, image size (including unpopulated BSS), and other room for expansion, so that bootloaders can figure out how to load your kernel correctly.[...]
Quoted 12 lines
arch/riscv/kernel/head.S new file +12
-0+ENTRY(_start) + /* Mask all interrupts */ + csrw sie, zero + + /* Load the global pointer */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* + * Disable FPU to detect illegal usage ofarch/riscv/kernel/head.S line 45
Quoted 10 lines
arch/riscv/kernel/head.S new file +10
-0+ * floating point in kernel space + */ + li t0, SR_FS + csrc sstatus, t0 + + /* Pick one hart to run the main boot sequence */ + la a3, hart_lottery + li a2, 1 + amoadd.w a3, a2, (a3) + bnez a3, .Lsecondary_startI would *very strongly* recommend that you do not throw all CPUs into the kernel at the start of time, and instead have a mechanism where you can bring CPUs into the kernel individually.
While it's simple, it comes with a number of long term problems (e.g. for kexec/kdump), some of which are unsolvable (e.g. as you cannot know how many CPUs are stuck in the kernel text, which haven't been brought online).
Quoted 8 lines
If you want a simple SMP bringup mechanism, ePAPR's spin-table (and arm64's different-but-identically-named spin-table) are good starting points. Just make sure you require each CPU is brought online individually. We didn't do that for arm64 from day one, and it still prevents us from making improvements that we'd like to, years later.
Doing that will also simplify decoupling the HART IDs from linux logical IDs, necessary for kdump/kexec, etc.
Defining a proper platform specification is something we've been punting on for too long. It's nominally on my plate, but I'm a bit behind right now. We've been able to get away without one because we don't have real bootloaders yet, but it's really time to get started working on this so we don't end up in a bad situation where we have production hardware out there that is capable of running Linux but is stuck with pre-specification firmware.
Quoted 7 lines
[...]
Quoted 4 lines
+/*
+ * Allow the user to manually add a memory region (in case DTS is broken);
+ * "mem_end=nn[KkMmGg]"
+ */
Quoted 6 lines
This doesn't have a start, so it can't work for discontiguous memory blocks (e.g. if FW has reserved/carved-out a chunk in the middle).
Other architectures have "mem=" which would allow you to specify a region. I'd generally recommend you provide an incentive to fix dts, however.
Thanks, we've already removed this.
Quoted 5 lines
Quoted 5 lines
arch/riscv/kernel/setup.c new file +5
-0+void __init setup_arch (char **cmdline_p) +{ +#if defined(CONFIG_HVC_RISCV_SBI ) +if (likely (early_console ==NULL )) { + early_console = &riscv_sbi_early_console_dev;
Quoted 8 lines
arch/riscv/kernel/setup.c line 215
Quoted 3 lines
arch/riscv/kernel/setup.c new file +3
-0+ register_console(early_console); + } +#endif This would be better driven by the DT or command line. Otherwise, this may come back to bite you in future, as you have to come up with a new mechanism to describe absence of the console, rather than using an exsiting mechanism to describe its presence.
That makes sense. I think we'll have to roll this into a platform discussion.
Quoted 19 lines
[...]
Quoted 17 lines
arch/riscv/kernel/smpboot.c new file +17
-0+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 ; + +while ((dn =of_find_node_by_type (dn,"cpu" ))) { + hart =riscv_of_processor_hart (dn); +if (hart >=0 ) { +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 ;
Quoted 8 lines
arch/riscv/kernel/smpboot.c line 68
Quoted 6 lines
arch/riscv/kernel/smpboot.c new file +6
-0+ } + } + } + +BUG_ON (!im_okay_therefore_i_am); +}That name is somewhat opaque. Perhaps bool
found_boot_cpu?
Makes sense -- the name was odd but I couldn't think of anything better to change it to.
commit 21c4ed85816420ff8641bfdceaf239cafd415faf
gpg: Signature made Fri 27 Jul 2018 03:09:44 PM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Fri Jul 27 15:09:23 2018 -0700
RISC-V: Rename im_okay_therefore_i_am to found_boot_cpu
The old name was a bit odd.
Signed-off-by: Palmer Dabbelt <[email protected]>
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index e08efc60726c..4f18ca5050bc 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -50,7 +50,7 @@ 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, found_boot_cpu = 0;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
hart = riscv_of_processor_hartid(dn);
@@ -58,13 +58,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 = 1;
}
}
}
- BUG_ON(!im_okay_therefore_i_am);
+ BUG_ON(!found_boot_cpu);
}
int __cpu_up(unsigned int cpu, struct task_struct *tidle)Quoted 18 lines
Quoted 5 lines
arch/riscv/kernel/smpboot.c new file +5
-0+ +int __cpu_up (unsigned int cpu,struct task_struct *tidle) +{ + tidle->thread_info.cpu = cpu; +arch/riscv/kernel/smpboot.c line 83
Quoted 10 lines
arch/riscv/kernel/smpboot.c new file +10
-0+/* +* On RISC-V systems, all harts boot on their own accord. Our _start +* selects the first hart to boot the kernel and causes the remainder +* of the harts to spin in a loop waiting for their stack pointer to be +* setup by that main hart. Writing __cpu_up_stack_pointer signals to +* 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;Shouldn't these be
WRITE_ONCE()(or some atomic) to avoid tearing?
Quoted 2 lines
How are the secondaries reading these? Is there any requirement on the order these become visible?
They just need to be WRITE_ONCE, the secondary harts spin until both of these are non-zero so it's not necessary to have any ordering here. Thanks for pointing this out, though, as this would have been an afwul bug to track down :)
commit 21c4ed85816420ff8641bfdceaf239cafd415faf
gpg: Signature made Fri 27 Jul 2018 03:09:44 PM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Fri Jul 27 15:09:23 2018 -0700
RISC-V: Rename im_okay_therefore_i_am to found_boot_cpu
The old name was a bit odd.
Signed-off-by: Palmer Dabbelt <[email protected]>
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index e08efc60726c..4f18ca5050bc 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -50,7 +50,7 @@ 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, found_boot_cpu = 0;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
hart = riscv_of_processor_hartid(dn);
@@ -58,13 +58,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 = 1;
}
}
}
- BUG_ON(!im_okay_therefore_i_am);
+ BUG_ON(!found_boot_cpu);
}
int __cpu_up(unsigned int cpu, struct task_struct *tidle)Quoted 14 lines
[...]
arch/riscv/kernel/smpboot.c line 103
Quoted 9 lines
arch/riscv/kernel/smpboot.c new file +9
-0+/* +* C entry point for a secondary processor. +*/ +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);I beleive this should be:
Quoted 3 lines
mmgrab(mm);See commit
f1f1007644ffc805("mm: add newmmgrab()helper")
Thanks!
commit 120b58060bbd67d893552d89b18ebbc7fea66ea9
gpg: Signature made Fri 27 Jul 2018 03:19:16 PM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Fri Jul 27 15:16:35 2018 -0700
RISC-V: Use mmgrab()
f1f1007644ff ("mm: add new mmgrab() helper") added a helper that we
missed out on.
Signed-off-by: Palmer Dabbelt <[email protected]>
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index 4f18ca5050bc..57552fa3892b 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -79,8 +79,8 @@ 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();
@@ -100,7 +100,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);
+ mm_grab(mm);
current->active_mm = mm;
trap_init();Quoted 9 lines
arch/riscv/kernel/smpboot.c line 110
Quoted 7 lines
arch/riscv/kernel/smpboot.c new file +7
-0+ current->active_mm = mm; + +trap_init (); +init_clockevent (); +notify_cpu_starting (smp_processor_id ()); +set_cpu_online (smp_processor_id (),1 ); +local_flush_tlb_all ();Why do you need a TLB flush here?
On RISC-V systems there is a mask that specifies which CPUs to target with remote TLB flushes. If the CPU is offline then it will not be included as part of the mask bits set for global TLB flushes, so they're essentially ignored. Thus we do a local flush here in case any other flushes were ignored.
commit ab8e24dede6b8555cb89c5b948bcb8bff7037ad3
gpg: Signature made Mon 30 Jul 2018 11:33:58 AM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Mon Jul 30 11:33:21 2018 -0700
RISC-V: Comment on the TLB flush in smp_callin()
Signed-off-by: Palmer Dabbelt <[email protected]>
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index 9d56f23952a7..b06af8cedf64 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -107,6 +107,8 @@ asmlinkage void __init smp_callin(void)
init_clockevent();
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();Quoted 5 lines
arch/riscv/kernel/smpboot.c line 112
Quoted 2 lines
arch/riscv/kernel/smpboot.c new file +2
-0+local_irq_enable (); +preempt_disable ();I believe these two should be the other way around, if the
preempt_disable()is necessary.
I'm honestly not sure here, all this early boot stuff is a bit of a mystery to me. I seem some architectures having (arm and arm64) having preempt_disable() first, some others (alpha) having local_irq_enable() first. Logically it makes sense to me that preemption should be disabled before enabling interrupts, as otherwise you could take an interrupt in the middle and get the scheduler all confused.
commit b60a66c94f7ec1982b5dd12f2c2e2a352574992d
gpg: Signature made Mon 30 Jul 2018 03:20:39 PM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Mon Jul 30 15:19:43 2018 -0700
RISC-V: Disable preemption before enabling interrupts when booting secondary harts
I'm not sure, but I think this was a bug: if the scheduler fired right
here then I believe it would blow up.
Signed-off-by: Palmer Dabbelt <[email protected]>
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index b06af8cedf64..2b9d51b9e0a5 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -110,7 +110,9 @@ asmlinkage void __init smp_callin(void)
/* 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();
+ /* 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);
}I'll clean up the patches and submit them for real, so feel free to comment on the real patches as these might be horribly broken.
Sorry this took so long to get around to, and thanks for the feedback!
Mark Rutland
reviewerRe: [PATCH v9 04/12] RISC-V: Init and Halt Code
Quoted 2 lines · Palmer Dabbelt
Sorry it took me an absurd amount of time to get back around to this... I'm adding our mailing list, as we didn't even have one a year ago.
No worries; we all get swamped with things.
Quoted 22 lines
I've included a few patches in line here, but they're just drafts. I'll test them and submit them properly.
Quoted 10 lines
Quoted 10 lines
arch/riscv/kernel/cacheinfo.c new file +10
-0+static void ci_leaf_init (struct cacheinfo *this_leaf, +struct device_node *node, +enum cache_type type,unsigned int level) +{ + this_leaf->of_node = node; + this_leaf->level = level; + this_leaf->type = type; +/* not a sector cache */ + this_leaf->physical_line_partition =1 ; +/* TODO: Add to DTS */ Quoted 8 lines
arch/riscv/kernel/cacheinfo.c line 33
Quoted 5 lines
arch/riscv/kernel/cacheinfo.c new file +5
-0+ this_leaf->attributes = +CACHE_WRITE_BACK + |CACHE_READ_ALLOCATE + |CACHE_WRITE_ALLOCATE ; +}In practice, it's very hard to remove implicit assumptions later down the line, so I'd recommend you add this to your DT from the outset.
Quoted 5 lines
Are these actually used by anything? I poked around the kernel and it appears that pretty much all they do is get printed in
drivers/base/cacheinfo.c. It looks like we're only filling out half the info in there anyway so it feels like we'd be better off just deleting these and waiting until we have a proper scheme before setting anything.
I think that would make sense. That way you should be able to assume that the data is correct if present, and if anyone screams that they ned it, you'll be able to find out why.
[...]
Quoted 57 lines
Quoted 20 lines
Quoted 7 lines
arch/riscv/kernel/cpu.c new file +7
-0+{ +const char *isa, *status; +u32 hart; + +if (!of_device_is_compatible (node,"riscv" )) { +pr_warn ("Found incompatible CPU\n" ); +return -(ENODEV );arch/riscv/kernel/cpu.c line 36
Quoted 10 lines
arch/riscv/kernel/cpu.c new file +10
-0+ } + +if (of_property_read_u32 (node,"reg" , &hart)) { +pr_warn ("Found CPU without hart ID\n" ); +return -(ENODEV ); + } +if (hart >=NR_CPUS ) { +pr_info ("Found hart ID %d, which is above NR_CPUs. Disabling this hart\n" , hart); +return -(ENODEV ); + }Here you assume that the hard ID is equalt to the Linux logical ID.
Quoted 5 lines
I'd recommend that (as other architectures do), you decouple the two.
That's going to be necessary for things like kdump to work, as the kdump kernel will run on (Linux logical) CPU0, but may have been executed from any secondary CPU.
This is a good point. We currently have another headache with CPU numbering on some systems where the machine CPU ID of 0 actually isn't a Linux CPU (ie, it doesn't have virtual memory) and we're handling the remapping in the bootloader. That's a bit convoluted, so it might be easier to handle the remapping in Linux.
Quoted 12 lines
arch/riscv/kernel/cpu.c line 45
Quoted 9 lines
arch/riscv/kernel/cpu.c new file +9
-0+ +if (of_property_read_string (node,"status" , &status)) { +pr_warn ("CPU with hartid=%d has no \"status\" property\n" , hart); +return -(ENODEV ); + } +if (strcmp (status,"okay" )) { +pr_info ("CPU with hartid=%d has a non-okay status of \"%s\"\n" , hart, status); +return -(ENODEV ); + }Please use
of_device_is_available().Quoted 12 lines
arch/riscv/kernel/cpu.c line 54
Quoted 9 lines
arch/riscv/kernel/cpu.c new file +9
-0+ +if (of_property_read_string (node,"riscv,isa" , &isa)) { +pr_warn ("CPU with hartid=%d has no \"riscv,isa\" property\n" , hart); +return -(ENODEV ); + } +if (isa[0 ] !='r' || isa[1 ] !='v' ) { +pr_warn ("CPU with hartid=%d has an invalid ISA of \"%s\"\n" , hart, isa); +return -(ENODEV ); + }As mentioned on the binding patch, I'd recommend that you use a set of discrete flags.
Quoted 3 lines
RISC-V defines what the ISA string means, and it's got all sorts of mechanism for extensibility already defined. I'm trying to avoid inventing any other encodings of this as they're just going to be incompatible in some subtle way.
Ok.
Quoted 100 lines
Quoted 35 lines
[...]
Quoted 8 lines
arch/riscv/kernel/cpu.c new file +8
-0+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 ); +const char *compat, *isa, *mmu; + +seq_printf (m,"hart\t: %lu\n" , hart_id); + if (!of_property_read_string(node, "riscv,isa", &isa)arch/riscv/kernel/cpu.c line 96
Quoted 10 lines
arch/riscv/kernel/cpu.c new file +10
-0+ && 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,"compatible" , &compat) + &&strcmp (compat,"riscv" )) +seq_printf (m,"uarch\t: %s\n" , compat); +seq_puts (m,"\n" );I'd *very strongly* recommend that you don't pass the DT values straight through to userspace.
Otherwise, things like riscv,isa = "rvtypo'd\nsomething" get exposed, and inevitably, some subset of userspace ends up relying upon it, while others break based upon it.
Further, specifically for the ISA parts, this is a very bad idea. If some ISA extensions require kernel support (e.g. to context switch state, or disable some configurable traps), they cannot work without kernel support. Generally, the wayt to handle this is for the kernel to detect the features at boot time, and save these in hwcaps.
Quoted 7 lines
Later, the hwcaps can be used to generate
/proc/cpunifooutput, and are also exposed via auxv, which avoids applications and libraries having to parse/proc/cpuinfojust to determine whether they have a particular feature, which doesn't work in many situations (e.g. early boot where /proc may not be mounted).Take a look at arm64's hwcaps for an example of how to use hwcaps.
Yes, that's a very good point. We actually have an implementation of hwcaps (that's exposed via the aux vector) that's cropped up in the mean time, and while the right thing to do is probably to generate cpuinfo from that I do at least have a simple patch that allows us to avoid passing garbage to userspace:
commit
6dbfebe5b2ddd873283abf625556b99f98cc85f2
gpg: Signature made Fri 27 Jul 2018 10:40:02 AM PDT
gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
gpg: issuer "[email protected]"
gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate]
gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate]
Author: Palmer Dabbelt <[email protected]>
Date: Fri Jul 27 09:57:29 2018 -0700RISC-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 <[email protected]>diff --git
a/arch/riscv/kernel/cpu.cb/arch/riscv/kernel/cpu.cindex19e98c1710dd..a18b4e3962a1100644
---a/arch/riscv/kernel/cpu.c
+++b/arch/riscv/kernel/cpu.c
@@ -58,6 +58,57 @@ intriscv_of_processor_hartid(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. */
+#ifdefined(CONFIG_32BIT)
+ if (strncmp(isa, "rv32i", 5)!= 0)
+ return;
+#elifdefined(CONFIG_64BIT)
+ if (strncmp(isa, "rv64i", 5)!= 0)
+ return;
+#endif
+
+ /* Print the base ISA, as we already know it's legal. */
+seq_printf(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);
Quoted 8 lines
+ 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);
It's probably best to do this once at boot time, rather than each time someone (e.g. libc) reads /proc/cpuinfo. That way you get a message in a deterministic location, and don't end up with an accidental DoS.
[...]
Quoted 41 lines
Quoted 32 lines
Quoted 12 lines
arch/riscv/kernel/head.S new file +12
-0+ENTRY(_start) + /* Mask all interrupts */ + csrw sie, zero + + /* Load the global pointer */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* + * Disable FPU to detect illegal usage ofarch/riscv/kernel/head.S line 45
Quoted 10 lines
arch/riscv/kernel/head.S new file +10
-0+ * floating point in kernel space + */ + li t0, SR_FS + csrc sstatus, t0 + + /* Pick one hart to run the main boot sequence */ + la a3, hart_lottery + li a2, 1 + amoadd.w a3, a2, (a3) + bnez a3, .Lsecondary_startI would *very strongly* recommend that you do not throw all CPUs into the kernel at the start of time, and instead have a mechanism where you can bring CPUs into the kernel individually.
While it's simple, it comes with a number of long term problems (e.g. for kexec/kdump), some of which are unsolvable (e.g. as you cannot know how many CPUs are stuck in the kernel text, which haven't been brought online).
Quoted 8 lines
If you want a simple SMP bringup mechanism, ePAPR's spin-table (and arm64's different-but-identically-named spin-table) are good starting points. Just make sure you require each CPU is brought online individually. We didn't do that for arm64 from day one, and it still prevents us from making improvements that we'd like to, years later.
Doing that will also simplify decoupling the HART IDs from linux logical IDs, necessary for kdump/kexec, etc.
Quoted 6 lines
Defining a proper platform specification is something we've been punting on for too long. It's nominally on my plate, but I'm a bit behind right now. We've been able to get away without one because we don't have real bootloaders yet, but it's really time to get started working on this so we don't end up in a bad situation where we have production hardware out there that is capable of running Linux but is stuck with pre-specification firmware.
Indeed; best of luck! :)
[...]
Quoted 17 lines
Quoted 17 lines
Quoted 4 lines
arch/riscv/kernel/smpboot.c new file +4
-0+int __cpu_up (unsigned int cpu,struct task_struct *tidle) +{ + tidle->thread_info.cpu = cpu; +arch/riscv/kernel/smpboot.c line 83
Quoted 10 lines
arch/riscv/kernel/smpboot.c new file +10
-0+/* +* On RISC-V systems, all harts boot on their own accord. Our _start +* selects the first hart to boot the kernel and causes the remainder +* of the harts to spin in a loop waiting for their stack pointer to be +* setup by that main hart. Writing __cpu_up_stack_pointer signals to +* 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;Shouldn't these be
WRITE_ONCE()(or some atomic) to avoid tearing?
Quoted 6 lines
Quoted 2 lines
How are the secondaries reading these? Is there any requirement on the order these become visible?
They just need to be
WRITE_ONCE, the secondary harts spin until both of these are non-zero so it's not necessary to have any ordering here. Thanks for pointing this out, though, as this would have been an afwul bug to track down :)
Ok. I assume the other end is doing something equivalent to READ_ONCE() for each!
[...]
Quoted 70 lines
Quoted 13 lines
arch/riscv/kernel/smpboot.c line 103
Quoted 10 lines
arch/riscv/kernel/smpboot.c new file +9
-0+/* +* C entry point for a secondary processor. +*/ +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);I beleive this should be:
Quoted 3 lines
mmgrab(mm);See commit
f1f1007644ffc805("mm: add newmmgrab()helper")Thanks!
commit 120b58060bbd67d893552d89b18ebbc7fea66ea9 gpg: Signature made Fri 27 Jul 2018 03:19:16 PM PDT gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41 gpg: issuer "[email protected]" gpg: Good signature from "Palmer Dabbelt <[email protected]>" [ultimate] gpg: aka "Palmer Dabbelt <[email protected]>" [ultimate] Author: Palmer Dabbelt <[email protected]> Date: Fri Jul 27 15:16:35 2018 -0700 RISC-V: Use mmgrab() f1f1007644ff ("mm: add new mmgrab() helper") added a helper that we missed out on. Signed-off-by: Palmer Dabbelt <[email protected]> diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 4f18ca5050bc..57552fa3892b 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -79,8 +79,8 @@ 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(); @@ -100,7 +100,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); + mm_grab(mm); current->active_mm = mm; trap_init();Quoted 9 lines
arch/riscv/kernel/smpboot.c line 110
Quoted 7 lines
arch/riscv/kernel/smpboot.c new file +7
-0+ current->active_mm = mm; + +trap_init (); +init_clockevent (); +notify_cpu_starting (smp_processor_id ()); +set_cpu_online (smp_processor_id (),1 ); +local_flush_tlb_all ();Why do you need a TLB flush here?
Quoted 4 lines
On RISC-V systems there is a mask that specifies which CPUs to target with remote TLB flushes. If the CPU is offline then it will not be included as part of the mask bits set for global TLB flushes, so they're essentially ignored. Thus we do a local flush here in case any other flushes were ignored.
Is that just for transient kernel mappings (e.g. vmalloc), or other things (e.g. junk values in the TLB out-of-reset)?
For the former that may be ok, depending on your TLB architecture, but for the latter I'd suspect that you need to do TLB maintenance before enabling the MMU.
Thanks,
Mark.
Palmer Dabbelt
maintainerPATCH v9 5/12 RISC-V: Atomic and Locking Code
In reply to Palmer DabbeltThis contains all the code that directly interfaces with the RISC-V memory model. While this code corforms to the current RISC-V ISA specifications (user 2.2 and priv 1.10), the memory model is somewhat underspecified in those documents. There is a working group that hopes to produce a formal memory model by the end of the year, but my understanding is that the basic definitions we're relying on here won't change significantly.
--- arch/riscv/include/asm/atomic.h | 375 ++++++++++++++++++++++++++++++++ arch/riscv/include/asm/barrier.h | 68 ++++++ arch/riscv/include/asm/bitops.h | 218 +++++++++++++++++++ arch/riscv/include/asm/cacheflush.h | 39 ++++ arch/riscv/include/asm/cmpxchg.h | 134 ++++++++++++ arch/riscv/include/asm/io.h | 303 ++++++++++++++++++++++++++ arch/riscv/include/asm/spinlock.h | 165 ++++++++++++++ arch/riscv/include/asm/spinlock_types.h | 33 +++ arch/riscv/include/asm/tlb.h | 24 ++ arch/riscv/include/asm/tlbflush.h | 64 ++++++ 10 files changed, 1423 insertions(+) create mode 100644 arch/riscv/include/asm/atomic.h create mode 100644 arch/riscv/include/asm/barrier.h create mode 100644 arch/riscv/include/asm/bitops.h create mode 100644 arch/riscv/include/asm/cacheflush.h create mode 100644 arch/riscv/include/asm/cmpxchg.h create mode 100644 arch/riscv/include/asm/io.h create mode 100644 arch/riscv/include/asm/spinlock.h create mode 100644 arch/riscv/include/asm/spinlock_types.h create mode 100644 arch/riscv/include/asm/tlb.h create mode 100644 arch/riscv/include/asm/tlbflush.h
arch/riscv/include/asm/atomic.h new file +375 -0
@@ -0,0 +1,375 @@ +/* +* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. +* 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 Licence +* as published by the Free Software Foundation; either version +* 2 of the Licence, or (at your option) any later version. +*/ + +#ifndef _ASM_RISCV_ATOMIC_H +#define _ASM_RISCV_ATOMIC_H + +#ifdef CONFIG_GENERIC_ATOMIC64 +# include <asm-generic/atomic64.h> +#else +# if (__riscv_xlen <64 ) +# error "64-bit atomics require XLEN to be at least 64" +# endif +#endif + +#include <asm/cmpxchg.h> +#include <asm/barrier.h> + +#define ATOMIC_INIT (i) { (i) } +static __always_inline int atomic_read(const atomic_t *v) +{ +return READ_ONCE (v->counter); +} +static __always_inline void atomic_set(atomic_t *v, int i) +{ +WRITE_ONCE (v->counter, i); +} + +#ifndef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC64_INIT (i) { (i) } +static __always_inline long atomic64_read (const atomic64_t *v) +{ +return READ_ONCE (v->counter); +} +static __always_inline void atomic64_set(atomic64_t *v, long i) +{ +WRITE_ONCE (v->counter, i); +} +#endif + +/* +* First, the atomic ops that have no ordering constraints and therefor don't +* have the AQ or RL bits set. These don't return anything, so there's only +* one version to worry about. +*/ +#define ATOMIC_OP (op, asm_op, c_op,I , asm_type, c_type, prefix) \ +static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ +{ \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type " zero, %1, %0" \ + : "+A" (v->counter) \ + : "r" (I) \ + : "memory"); \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (op, asm_op, c_op,I ) \ + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) +#else +#define ATOMIC_OPS (op, asm_op, c_op,I ) \ + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) \ + ATOMIC_OP (op, asm_op, c_op, I, d, long, 64) +#endif + +ATOMIC_OPS(add, add, +, i) +ATOMIC_OPS(sub, add, +, -i) +ATOMIC_OPS(and, and, &, i) +ATOMIC_OPS( or, or, |, i) +ATOMIC_OPS(xor, xor, ^, i) + +#undef ATOMIC_OP +#undef ATOMIC_OPS + +/* +* Atomic ops that have ordered, relaxed, acquire, and relese variants. +* There's two flavors of these: the arithmatic ops have both fetch and return +* versions, while the logical ops only have fetch versions. +*/ +#define ATOMIC_FETCH_OP (op, asm_op, c_op,I , asm_or, c_or, asm_type, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \ +{ \ + register c_type ret; \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \ + : "+A" (v->counter), "=r" (ret) \ + : "r" (I) \ + : "memory"); \ + return ret; \ +} + +#define ATOMIC_OP_RETURN (op, asm_op, c_op,I , asm_or, c_or, asm_type, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (op, asm_op, c_op,I , asm_or, c_or) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) +#else +#define ATOMIC_OPS (op, asm_op, c_op,I , asm_or, c_or) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, d, long, 64) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) +#endif + +ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) +ATOMIC_OPS(add, add, +, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, ) + +ATOMIC_OPS(sub, add, +, -i, , _relaxed) +ATOMIC_OPS(sub, add, +, -i, .aq , _acquire) +ATOMIC_OPS(sub, add, +, -i, .rl , _release) +ATOMIC_OPS(sub, add, +, -i, .aqrl, ) + +#undef ATOMIC_OPS + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ + ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w, int, ) +#else +#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ + ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) +#endif + +ATOMIC_OPS(and, and, &, i, , _relaxed) +ATOMIC_OPS(and, and, &, i, .aq , _acquire) +ATOMIC_OPS(and, and, &, i, .rl , _release) +ATOMIC_OPS(and, and, &, i, .aqrl, ) + +ATOMIC_OPS( or, or, |, i, , _relaxed) +ATOMIC_OPS( or, or, |, i, .aq , _acquire) +ATOMIC_OPS( or, or, |, i, .rl , _release) +ATOMIC_OPS( or, or, |, i, .aqrl, ) + +ATOMIC_OPS(xor, xor, ^, i, , _relaxed) +ATOMIC_OPS(xor, xor, ^, i, .aq , _acquire) +ATOMIC_OPS(xor, xor, ^, i, .rl , _release) +ATOMIC_OPS(xor, xor, ^, i, .aqrl, ) + +#undef ATOMIC_OPS + +#undef ATOMIC_FETCH_OP +#undef ATOMIC_OP_RETURN + +/* + * The extra atomic operations that are constructed from one of the core + * AMO-based operations above (aside from sub, which is easier to fit above). + * These are required to perform a barrier, but they're OK this way because + * atomic_*_return is also required to perform a barrier. + */ +#define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \ +static __always_inline bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_##func_op##_return(i, v) comp_op I; \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS(op, func_op, comp_op, I) \ + ATOMIC_OP (op, func_op, comp_op, I, int, ) +#else +#define ATOMIC_OPS(op, func_op, comp_op, I) \ + ATOMIC_OP (op, func_op, comp_op, I, int, ) \ + ATOMIC_OP (op, func_op, comp_op, I, long, 64) +#endif + +ATOMIC_OPS(add_and_test, add, ==, 0) +ATOMIC_OPS(sub_and_test, sub, ==, 0) +ATOMIC_OPS(add_negative, add, <, 0) + +#undef ATOMIC_OP +#undef ATOMIC_OPS + +#define ATOMIC_OP(op, func_op, c_op, I, c_type, prefix) \ +static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v) \ +{ \ + atomic##prefix##_##func_op(I, v); \ +} + +#define ATOMIC_FETCH_OP(op, func_op, c_op, I, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_fetch_##func_op(I, v); \ +} + +#define ATOMIC_OP_RETURN (op, asm_op, c_op,I , c_type, prefix) \ +static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_fetch_##op(v) c_op I; \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (op, asm_op, c_op,I ) \ + ATOMIC_OP (op, asm_op, c_op, I, int, ) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) +#else +#define ATOMIC_OPS (op, asm_op, c_op,I ) \ + ATOMIC_OP (op, asm_op, c_op, I, int, ) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \ + ATOMIC_OP (op, asm_op, c_op, I, long, 64) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, long, 64) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64) +#endif + +ATOMIC_OPS(inc, add, +, 1) +ATOMIC_OPS(dec, add, +, -1) + +#undef ATOMIC_OPS +#undef ATOMIC_OP +#undef ATOMIC_FETCH_OP +#undef ATOMIC_OP_RETURN + +#define ATOMIC_OP (op, func_op, comp_op,I , prefix) \ +static __always_inline bool atomic##prefix##_##op(atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_##func_op##_return(v) comp_op I; \ +} + +ATOMIC_OP(inc_and_test, inc, ==, 0, ) +ATOMIC_OP(dec_and_test, dec, ==, 0, ) +#ifndef CONFIG_GENERIC_ATOMIC64 +ATOMIC_OP(inc_and_test, inc, ==, 0, 64) +ATOMIC_OP(dec_and_test, dec, ==, 0, 64) +#endif + +#undef ATOMIC_OP + +/* This is required to provide a barrier on success. */ +static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ +int prev, rc; + + __asm__ __volatile__ ( +"0:\n\t" +"lr.w.aqrl %[p], %[c]\n\t" +"beq %[p], %[u], 1f\n\t" +"add %[rc], %[p], %[a]\n\t" +"sc.w.aqrl %[rc], %[rc], %[c]\n\t" +"bnez %[rc], 0b\n\t" +"1:" + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) + : [a]"r" (a), [u]"r" (u) + :"memory" ); +return prev; +} + +#ifndef CONFIG_GENERIC_ATOMIC64 +static __always_inline long __atomic64_add_unless(atomic64_t *v, long a, long u) +{ + long prev, rc; + + __asm__ __volatile__ ( +"0:\n\t" +"lr.d.aqrl %[p], %[c]\n\t" +"beq %[p], %[u], 1f\n\t" +"add %[rc], %[p], %[a]\n\t" +"sc.d.aqrl %[rc], %[rc], %[c]\n\t" +"bnez %[rc], 0b\n\t" +"1:" + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) + : [a]"r" (a), [u]"r" (u) + :"memory" ); +return prev; +} + +static __always_inline int atomic64_add_unless(atomic64_t *v, long a, long u) +{ +return __atomic64_add_unless (v, a, u) != u; +} +#endif + +/* +* The extra atomic operations that are constructed from one of the core +* LR/SC-based operations above. +*/ +static __always_inline int atomic_inc_not_zero(atomic_t *v) +{ +return __atomic_add_unless (v,1 ,0 ); +} + +#ifndef CONFIG_GENERIC_ATOMIC64 +static __always_inline long atomic64_inc_not_zero (atomic64_t *v) +{ +return atomic64_add_unless (v,1 ,0 ); +} +#endif + +/* +* atomic_{cmp,}xchg is required to have exactly the same ordering semantics as +* {cmp,}xchg and the operations that return, so they need a barrier. We just +* use the other implementations directly. +*/ +#define ATOMIC_OP (c_t, prefix, c_or, size, asm_or) \ +static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) \ +{ \ + return __cmpxchg(&(v->counter), o, n, size, asm_or, asm_or); \ +} \ +static __always_inline c_t atomic##prefix##_xchg##c_or(atomic##prefix##_t *v, c_t n) \ +{ \ + return __xchg(n, &(v->counter), size, asm_or); \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (c_or, asm_or) \ + ATOMIC_OP( int, , c_or, 4, asm_or) +#else +#define ATOMIC_OPS (c_or, asm_or) \ + ATOMIC_OP( int, , c_or, 4, asm_or) \ + ATOMIC_OP(long, 64, c_or, 8, asm_or) +#endif + +ATOMIC_OPS( , .aqrl) +ATOMIC_OPS(_acquire, .aq) +ATOMIC_OPS(_release, .rl) +ATOMIC_OPS(_relaxed, ) + +#undef ATOMIC_OPS +#undef ATOMIC_OP + +static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset) +{ + int prev, rc; + + __asm__ __volatile__ ( + "0:\n\t" + "lr.w.aqrl %[p], %[c]\n\t" + "sub %[rc], %[p], %[o]\n\t" + "bltz %[rc], 1f\n\t" + "sc.w.aqrl %[rc], %[rc], %[c]\n\t" + "bnez %[rc], 0b\n\t" + "1:" + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) + : [o]"r" (offset) + : "memory"); +return prev - offset; +} + +#define atomic_dec_if_positive (v) atomic_sub_if_positive(v, 1) + +#ifndef CONFIG_GENERIC_ATOMIC64 +static __always_inline long atomic64_sub_if_positive (atomic64_t *v,int offset) +{ +long prev, rc; + + __asm__ __volatile__ ( +"0:\n\t" +"lr.d.aqrl %[p], %[c]\n\t" +"sub %[rc], %[p], %[o]\n\t" +"bltz %[rc], 1f\n\t" +"sc.d.aqrl %[rc], %[rc], %[c]\n\t" +"bnez %[rc], 0b\n\t" +"1:" + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) + : [o]"r" (offset) + :"memory" ); +return prev - offset; +} + +#define atomic64_dec_if_positive (v) atomic64_sub_if_positive(v, 1) +#endif + +#endif /* _ASM_RISCV_ATOMIC_H */
arch/riscv/include/asm/barrier.h new file +68 -0
68 lines not on this page · raw message
arch/riscv/include/asm/bitops.h new file +218 -0
218 lines not on this page · raw message
arch/riscv/include/asm/cacheflush.h new file +39 -0
@@ -0,0 +1,39 @@ +/* +* Copyright (C) 2015 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_CACHEFLUSH_H +#define _ASM_RISCV_CACHEFLUSH_H + +#include <asm-generic/cacheflush.h> + +#undef flush_icache_range +#undef flush_icache_user_range + +static inline void local_flush_icache_all (void ) +{ + asmvolatile ("fence.i" :::"memory" ); +} + +#ifndef CONFIG_SMP + +#define flush_icache_range (start, end) local_flush_icache_all() +#define flush_icache_user_range (vma, pg, addr, len) local_flush_icache_all() + +#else /* CONFIG_SMP */ + +#define flush_icache_range (start, end) sbi_remote_fence_i(0) +#define flush_icache_user_range (vma, pg, addr, len) sbi_remote_fence_i(0) + +#endif /* CONFIG_SMP */ + +#endif /* _ASM_RISCV_CACHEFLUSH_H */
arch/riscv/include/asm/cmpxchg.h new file +134 -0
134 lines not on this page · raw message
arch/riscv/include/asm/io.h new file +303 -0
303 lines not on this page · raw message
arch/riscv/include/asm/spinlock.h new file +165 -0
165 lines not on this page · raw message
arch/riscv/include/asm/spinlock_types.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* Copyright (C) 2015 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_SPINLOCK_TYPES_H +#define _ASM_RISCV_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { +volatile unsigned int lock; +}arch_spinlock_t ; + +#define __ARCH_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { +volatile unsigned int lock; +}arch_rwlock_t ; + +#define __ARCH_RW_LOCK_UNLOCKED { 0 } + +#endif
arch/riscv/include/asm/tlb.h new file +24 -0
@@ -0,0 +1,24 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_TLB_H +#define _ASM_RISCV_TLB_H + +#include <asm-generic/tlb.h> + +static inline void tlb_flush (struct mmu_gather *tlb) +{ +flush_tlb_mm (tlb->mm); +} + +#endif /* _ASM_RISCV_TLB_H */
arch/riscv/include/asm/tlbflush.h new file +64 -0
64 lines not on this page · raw message
Signature · 6 lines
2.13.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Hi Palmer,
Some late comments on this which you might want to address as you get the chance.
Quoted 105 lines · Palmer Dabbelt
This contains all the code that directly interfaces with the RISC-V memory model. While this code corforms to the current RISC-V ISA specifications (user 2.2 and priv 1.10), the memory model is somewhat underspecified in those documents. There is a working group that hopes to produce a formal memory model by the end of the year, but my understanding is that the basic definitions we're relying on here won't change significantly.
Reviewed-by Arnd Bergmann <[email protected]>Signed-off-by Palmer Dabbelt <[email protected]>--- arch/riscv/include/asm/atomic.h | 375 ++++++++++++++++++++++++++++++++ arch/riscv/include/asm/barrier.h | 68 ++++++ arch/riscv/include/asm/bitops.h | 218 +++++++++++++++++++ arch/riscv/include/asm/cacheflush.h | 39 ++++ arch/riscv/include/asm/cmpxchg.h | 134 ++++++++++++ arch/riscv/include/asm/io.h | 303 ++++++++++++++++++++++++++ arch/riscv/include/asm/spinlock.h | 165 ++++++++++++++ arch/riscv/include/asm/spinlock_types.h | 33 +++ arch/riscv/include/asm/tlb.h | 24 ++ arch/riscv/include/asm/tlbflush.h | 64 ++++++ 10 files changed, 1423 insertions(+) create mode 100644 arch/riscv/include/asm/atomic.h create mode 100644 arch/riscv/include/asm/barrier.h create mode 100644 arch/riscv/include/asm/bitops.h create mode 100644 arch/riscv/include/asm/cacheflush.h create mode 100644 arch/riscv/include/asm/cmpxchg.h create mode 100644 arch/riscv/include/asm/io.h create mode 100644 arch/riscv/include/asm/spinlock.h create mode 100644 arch/riscv/include/asm/spinlock_types.h create mode 100644 arch/riscv/include/asm/tlb.h create mode 100644 arch/riscv/include/asm/tlbflush.harch/riscv/include/asm/atomic.h new file +66
-0@@ -0,0 +1,375 @@ +/* +* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. +* 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 Licence +* as published by the Free Software Foundation; either version +* 2 of the Licence, or (at your option) any later version. +*/ + +#ifndef _ASM_RISCV_ATOMIC_H +#define _ASM_RISCV_ATOMIC_H + +#ifdef CONFIG_GENERIC_ATOMIC64 +# include <asm-generic/atomic64.h> +#else +# if (__riscv_xlen <64 ) +# error "64-bit atomics require XLEN to be at least 64" +# endif +#endif + +#include <asm/cmpxchg.h> +#include <asm/barrier.h> + +#define ATOMIC_INIT (i) { (i) } +static __always_inline int atomic_read(const atomic_t *v) +{ +return READ_ONCE (v->counter); +} +static __always_inline void atomic_set(atomic_t *v, int i) +{ +WRITE_ONCE (v->counter, i); +} + +#ifndef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC64_INIT (i) { (i) } +static __always_inline long atomic64_read (const atomic64_t *v) +{ +return READ_ONCE (v->counter); +} +static __always_inline void atomic64_set(atomic64_t *v, long i) +{ +WRITE_ONCE (v->counter, i); +} +#endif + +/* +* First, the atomic ops that have no ordering constraints and therefor don't +* have the AQ or RL bits set. These don't return anything, so there's only +* one version to worry about. +*/ +#define ATOMIC_OP (op, asm_op, c_op,I , asm_type, c_type, prefix) \ +static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ +{ \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type " zero, %1, %0" \ + : "+A" (v->counter) \ + : "r" (I) \ + : "memory"); \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (op, asm_op, c_op,I ) \ + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) +#else
arch/riscv/include/asm/atomic.h line 76
Quoted 10 lines
arch/riscv/include/asm/atomic.h new file +10
-0+#define ATOMIC_OPS (op, asm_op, c_op,I ) \ + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) \ + ATOMIC_OP (op, asm_op, c_op, I, d, long, 64) +#endif + +ATOMIC_OPS(add, add, +, i) +ATOMIC_OPS(sub, add, +, -i) +ATOMIC_OPS(and, and, &, i) +ATOMIC_OPS( or, or, |, i) +ATOMIC_OPS(xor, xor, ^, i)
What is the point in the c_op parameter to these things?
Quoted 29 lines
arch/riscv/include/asm/atomic.h new file +29
-0+/* +* Atomic ops that have ordered, relaxed, acquire, and relese variants. +* There's two flavors of these: the arithmatic ops have both fetch and return +* versions, while the logical ops only have fetch versions. +*/ +#define ATOMIC_FETCH_OP (op, asm_op, c_op,I , asm_or, c_or, asm_type, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \ +{ \ + register c_type ret; \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \ + : "+A" (v->counter), "=r" (ret) \ + : "r" (I) \ + : "memory"); \ + return ret; \ +} + +#define ATOMIC_OP_RETURN (op, asm_op, c_op,I , asm_or, c_or, asm_type, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (op, asm_op, c_op,I , asm_or, c_or) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) +#else +#define ATOMIC_OPS (op, asm_op, c_op,I , asm_or, c_or) \
arch/riscv/include/asm/atomic.h line 119
Quoted 10 lines
arch/riscv/include/asm/atomic.h new file +10
-0+ ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, d, long, 64) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) +#endif + +ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) +ATOMIC_OPS(add, add, +, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )
Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x) = 1;atomic_add_return(y, 1);WRITE_ONCE(z) = 1;
P1:READ_ONCE(z) // reads 1smp_rmb();READ_ONCE(x) // must not read 0
arch/riscv/include/asm/atomic.h line 305
Quoted 5 lines
arch/riscv/include/asm/atomic.h new file +5
-0+/* +* atomic_{cmp,}xchg is required to have exactly the same ordering semantics as +* {cmp,}xchg and the operations that return, so they need a barrier. We just +* use the other implementations directly. +*/
We also have relaxed/acquire/release versions of cmpxchg and xchg, if you want to implement them.
Quoted 120 lines
arch/riscv/include/asm/atomic.h new file +70
-0+#define ATOMIC_OP (c_t, prefix, c_or, size, asm_or) \ +static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) \ +{ \ + return __cmpxchg(&(v->counter), o, n, size, asm_or, asm_or); \ +} \ +static __always_inline c_t atomic##prefix##_xchg##c_or(atomic##prefix##_t *v, c_t n) \ +{ \ + return __xchg(n, &(v->counter), size, asm_or); \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS (c_or, asm_or) \ + ATOMIC_OP( int, , c_or, 4, asm_or) +#else +#define ATOMIC_OPS (c_or, asm_or) \ + ATOMIC_OP( int, , c_or, 4, asm_or) \ + ATOMIC_OP(long, 64, c_or, 8, asm_or) +#endif + +ATOMIC_OPS( , .aqrl) +ATOMIC_OPS(_acquire, .aq) +ATOMIC_OPS(_release, .rl) +ATOMIC_OPS(_relaxed, ) + +#undef ATOMIC_OPS +#undef ATOMIC_OP + +static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset) +{ + int prev, rc; + + __asm__ __volatile__ ( + "0:\n\t" + "lr.w.aqrl %[p], %[c]\n\t" + "sub %[rc], %[p], %[o]\n\t" + "bltz %[rc], 1f\n\t" + "sc.w.aqrl %[rc], %[rc], %[c]\n\t" + "bnez %[rc], 0b\n\t" + "1:" + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) + : [o]"r" (offset) + : "memory"); +return prev - offset; +} + +#define atomic_dec_if_positive (v) atomic_sub_if_positive(v, 1) + +#ifndef CONFIG_GENERIC_ATOMIC64 +static __always_inline long atomic64_sub_if_positive (atomic64_t *v,int offset) +{ +long prev, rc; + + __asm__ __volatile__ ( +"0:\n\t" +"lr.d.aqrl %[p], %[c]\n\t" +"sub %[rc], %[p], %[o]\n\t" +"bltz %[rc], 1f\n\t" +"sc.d.aqrl %[rc], %[rc], %[c]\n\t" +"bnez %[rc], 0b\n\t" +"1:" + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) + : [o]"r" (offset) + :"memory" ); +return prev - offset; +} + +#define atomic64_dec_if_positive (v) atomic64_sub_if_positive(v, 1) +#endif + +#endif /* _ASM_RISCV_ATOMIC_H */ arch/riscv/include/asm/barrier.h new file +44
-0@@ -0,0 +1,68 @@ +/* +* Based on arch/arm/include/asm/barrier.h +* +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2013 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 version 2 as +* published by the Free Software Foundation. +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _ASM_RISCV_BARRIER_H +#define _ASM_RISCV_BARRIER_H + +#ifndef __ASSEMBLY__ + +#define nop () __asm__ __volatile__ ("nop") + +#define RISCV_FENCE (p, s) \ + __asm__ __volatile__ ("fence " #p "," #s : : : "memory") + +/* These barriers need to enforce ordering on both devices or memory. */ +#define mb () RISCV_FENCE(iorw,iorw) +#define rmb () RISCV_FENCE(ir,ir) +#define wmb () RISCV_FENCE(ow,ow) + +/* These barriers do not need to enforce ordering on devices, just memory. */ +#define smp_mb () RISCV_FENCE(rw,rw) +#define smp_rmb () RISCV_FENCE(r,r) +#define smp_wmb () RISCV_FENCE(w,w) + +/* +* These fences exist to enforce ordering around the relaxed AMOs. The +* documentation defines that +* "
arch/riscv/include/asm/barrier.h line 54
Quoted 10 lines
arch/riscv/include/asm/barrier.h new file +10
-0+* atomic_fetch_add(); +* is equivalent to: +* smp_mb__before_atomic(); +* atomic_fetch_add_relaxed(); +* smp_mb__after_atomic(); +* " +* So we emit full fences on both sides. +*/ +#define __smb_mb__before_atomic () smp_mb() +#define __smb_mb__after_atomic () smp_mb()
Now I'm confused, because you're also spitting out .aqrl for those afaict. Do you really need full barriers *and* .aqrl, or am I misunderstanding something here?
arch/riscv/include/asm/barrier.h line 61
Quoted 7 lines
arch/riscv/include/asm/barrier.h new file +7
-0+ +/* +* These barriers prevent accesses performed outside a spinlock from being moved +* inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only +* enforce release consistency, we need full fences here. +*/ +#define smb_mb__before_spinlock () smp_mb()
We killed this macro, so you don't need to define it.
Quoted 63 lines
arch/riscv/include/asm/barrier.h new file +7
-0+#define smb_mb__after_spinlock () smp_mb() + +#include <asm-generic/barrier.h> + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_BARRIER_H */ arch/riscv/include/asm/bitops.h new file +50
-0@@ -0,0 +1,218 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_BITOPS_H +#define _ASM_RISCV_BITOPS_H + +#ifndef _LINUX_BITOPS_H +#error "Only <linux/bitops.h> can be included directly" +#endif /* _LINUX_BITOPS_H */ + +#include <linux/compiler.h> +#include <linux/irqflags.h> +#include <asm/barrier.h> +#include <asm/bitsperlong.h> + +#ifndef smp_mb__before_clear_bit +#define smp_mb__before_clear_bit () smp_mb() +#define smp_mb__after_clear_bit () smp_mb() +#endif /* smp_mb__before_clear_bit */ + +#include <asm-generic/bitops/__ffs.h> +#include <asm-generic/bitops/ffz.h> +#include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/__fls.h> +#include <asm-generic/bitops/fls64.h> +#include <asm-generic/bitops/find.h> +#include <asm-generic/bitops/sched.h> +#include <asm-generic/bitops/ffs.h> + +#include <asm-generic/bitops/hweight.h> + +#if (BITS_PER_LONG ==64 ) +#define __AMO (op) "amo" #op ".d" +#elif (BITS_PER_LONG ==32 ) +#define __AMO (op) "amo" #op ".w" +#else +#error "Unexpected BITS_PER_LONG" +#endif + +#define __test_and_op_bit_ord (op, mod, nr, addr, ord) \
arch/riscv/include/asm/bitops.h line 60
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+({ \ +unsigned long __res, __mask; \ + __mask =BIT_MASK (nr); \ + __asm__ __volatile__ ( \ + __AMO(op) #ord " %0, %2, %1" \ + :"=r" (__res),"+A" (addr[BIT_WORD (nr)]) \ + :"r" (mod (__mask)) \ + :"memory" ); \ + ((__res & __mask) !=0 ); \ +})
This looks broken to me -- the value-returning test bitops need to be fully ordered.
Quoted 57 lines
arch/riscv/include/asm/bitops.h new file +57
-0+#ifndef _ASM_RISCV_CMPXCHG_H +#define _ASM_RISCV_CMPXCHG_H + +#include <linux/bug.h> + +#include <asm/barrier.h> + +#define __xchg (new, ptr, size, asm_or) \ +({ \ + __typeof__(ptr) __ptr = (ptr); \ + __typeof__(new) __new = (new); \ + __typeof__(*(ptr)) __ret; \ + switch (size) { \ + case 4: \ + __asm__ __volatile__ ( \ + "amoswap.w" #asm_or " %0, %2, %1" \ + : "=r" (__ret), "+A" (*__ptr) \ + : "r" (__new) \ + : "memory"); \ + break; \ + case 8: \ + __asm__ __volatile__ ( \ + "amoswap.d" #asm_or " %0, %2, %1" \ + : "=r" (__ret), "+A" (*__ptr) \ + : "r" (__new) \ + : "memory"); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + __ret; \ +}) + +#define xchg (ptr, x) (__xchg((x), (ptr), sizeof(*(ptr)), .aqrl)) + +#define xchg32 (ptr, x) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ + xchg((ptr), (x)); \ +}) + +#define xchg64 (ptr, x) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + xchg((ptr), (x)); \ +}) + +/* +* Atomic compare and exchange. Compare OLD with MEM, if identical, +* store NEW in MEM. Return the initial value in MEM. Success is +* indicated by comparing RETURN with OLD. +*/ +#define __cmpxchg (ptr, old, new, size, lrb, scb) \ +({ \ + __typeof__(ptr) __ptr = (ptr); \ + __typeof__(*(ptr)) __old = (old); \ + __typeof__(*(ptr)) __new = (new); \
arch/riscv/include/asm/bitops.h line 127
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+ __typeof__(*(ptr)) __ret; \ + registerunsigned int __rc; \ +switch (size) { \ +case 4 : \ + __asm__ __volatile__ ( \ + "0:" \ + "lr.w" #scb " %0, %2\n" \ + "bne %0, %z3, 1f\n" \ + "sc.w" #lrb " %1, %z4, %2\n" \ + "bnez %1, 0b\n" \
You don't have an AMO for these?
Quoted 22 lines
arch/riscv/include/asm/bitops.h new file +22
-0+ "1:" \ + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ + : "rJ" (__old), "rJ" (__new) \ + : "memory"); \ + break; \ + case 8: \ + __asm__ __volatile__ ( \ + "0:" \ + "lr.d" #scb " %0, %2\n" \ + "bne %0, %z3, 1f\n" \ + "sc.d" #lrb " %1, %z4, %2\n" \ + "bnez %1, 0b\n" \ + "1:" \ + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ + : "rJ" (__old), "rJ" (__new) \ + : "memory"); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + __ret; \ +})
[...]
Quoted 4 lines
arch/riscv/include/asm/bitops.h new file +4
-0+#ifndef _ASM_RISCV_SPINLOCK_H +#define _ASM_RISCV_SPINLOCK_H + +#include <linux/kernel.h>
arch/riscv/include/asm/bitops.h
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+#include <asm/current.h> + +/* +* Simple spin lock operations. These provide no fairness guarantees. +*/ + +/* FIXME: Replace this with a ticket lock, like MIPS. */ + +#define arch_spin_lock_flags (lock, flags) arch_spin_lock(lock) +#define arch_spin_is_locked (x) ((x)->lock != 0)
Missing READ_ONCE.
Quoted 31 lines
arch/riscv/include/asm/bitops.h new file +31
-0+ +static inline void arch_spin_unlock (arch_spinlock_t *lock) +{ + __asm__ __volatile__ ( +"amoswap.w.rl x0, x0, %0" + :"=A" (lock->lock) + ::"memory" ); +} + +static inline int arch_spin_trylock (arch_spinlock_t *lock) +{ +int tmp =1 , busy; + + __asm__ __volatile__ ( +"amoswap.w.aq %0, %2, %1" + :"=r" (busy),"+A" (lock->lock) + :"r" (tmp) + :"memory" ); + +return !busy; +} + +static inline void arch_spin_lock (arch_spinlock_t *lock) +{ +while (1 ) { +if (arch_spin_is_locked (lock)) +continue ; + +if (arch_spin_trylock (lock)) +break ; + }
arch/riscv/include/asm/bitops.h
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+} + +static inline void arch_spin_unlock_wait (arch_spinlock_t *lock) +{ +smp_rmb (); +do { +cpu_relax (); + }while (arch_spin_is_locked (lock)); +smp_acquire__after_ctrl_dep (); +}
We killed this one too, so please drop it.
Quoted 29 lines
arch/riscv/include/asm/bitops.h new file +29
-0+/***********************************************************/ + +static inline int arch_read_can_lock (arch_rwlock_t *lock) +{ +return lock->lock >=0 ; +} + +static inline int arch_write_can_lock (arch_rwlock_t *lock) +{ +return lock->lock ==0 ; +} + +static inline void arch_read_lock (arch_rwlock_t *lock) +{ +int tmp; + + __asm__ __volatile__( +"1: lr.w %1, %0\n" +" bltz %1, 1b\n" +" addi %1, %1, 1\n" +" sc.w.aq %1, %1, %0\n" +" bnez %1, 1b\n" + :"+A" (lock->lock),"=&r" (tmp) + ::"memory" ); +} + +static inline void arch_write_lock (arch_rwlock_t *lock) +{ +int tmp;
arch/riscv/include/asm/bitops.h
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+ + __asm__ __volatile__( +"1: lr.w %1, %0\n" +" bnez %1, 1b\n" +" li %1, -1\n" +" sc.w.aq %1, %1, %0\n" +" bnez %1, 1b\n" + :"+A" (lock->lock),"=&r" (tmp) + ::"memory" ); +}
I think you have the same starvation issues as we have on arm64 here. I strongly recommend moving over to qrwlock :)
Quoted 6 lines
arch/riscv/include/asm/bitops.h new file +6
-0+#ifndef _ASM_RISCV_TLBFLUSH_H +#define _ASM_RISCV_TLBFLUSH_H + +#ifdef CONFIG_MMU + +/* Flush entire local TLB */
arch/riscv/include/asm/bitops.h
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+static inline void local_flush_tlb_all (void ) +{ + __asm__ __volatile__ ("sfence.vma" : : :"memory" ); +} + +/* Flush one page from local TLB */ +static inline void local_flush_tlb_page (unsigned long addr) +{ + __asm__ __volatile__ ("sfence.vma %0" : :"r" (addr) :"memory" ); +}
Is this serialised against prior updates to the page table (set_pte) and also against subsequent instruction fetch?
Will
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Palmer Dabbelt
maintainerRe: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 4 lines · On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected] wrote:
Hi Palmer,
Some late comments on this which you might want to address as you get the chance.
Sorry, this disappeared into my inbox. I've replied in-line to all your comments, but in the interest of making sure I didn't lose the message again the code contained here has been minimally tested. All the commits live on a branch now, so hopefully I won't lose it this time :).
Quoted 25 lines · Palmer Dabbelt
Quoted 24 lines
This contains all the code that directly interfaces with the RISC-V memory model. While this code corforms to the current RISC-V ISA specifications (user 2.2 and priv 1.10), the memory model is somewhat underspecified in those documents. There is a working group that hopes to produce a formal memory model by the end of the year, but my understanding is that the basic definitions we're relying on here won't change significantly.
Reviewed-by Arnd Bergmann <[email protected]>Signed-off-by Palmer Dabbelt <[email protected]>--- arch/riscv/include/asm/atomic.h | 375 ++++++++++++++++++++++++++++++++ arch/riscv/include/asm/barrier.h | 68 ++++++ arch/riscv/include/asm/bitops.h | 218 +++++++++++++++++++ arch/riscv/include/asm/cacheflush.h | 39 ++++ arch/riscv/include/asm/cmpxchg.h | 134 ++++++++++++ arch/riscv/include/asm/io.h | 303 ++++++++++++++++++++++++++ arch/riscv/include/asm/spinlock.h | 165 ++++++++++++++ arch/riscv/include/asm/spinlock_types.h | 33 +++ arch/riscv/include/asm/tlb.h | 24 ++ arch/riscv/include/asm/tlbflush.h | 64 ++++++ 10 files changed, 1423 insertions(+) create mode 100644 arch/riscv/include/asm/atomic.h create mode 100644 arch/riscv/include/asm/barrier.h
Quoted 8 lines
Quoted 8 lines
create mode 100644 arch/riscv/include/asm/bitops.h create mode 100644 arch/riscv/include/asm/cacheflush.h create mode 100644 arch/riscv/include/asm/cmpxchg.h create mode 100644 arch/riscv/include/asm/io.h create mode 100644 arch/riscv/include/asm/spinlock.h create mode 100644 arch/riscv/include/asm/spinlock_types.h create mode 100644 arch/riscv/include/asm/tlb.h create mode 100644 arch/riscv/include/asm/tlbflush.h
I'm snipping out some parts, because it's long. I've also dropped some CCs, as it's old and I think I had a few too many people at the time (the patches were all joined together).
Quoted 18 lines
Quoted 18 lines
(quoted diff) +18
-0+#define ATOMIC_OP(op, asm_op, c_op, I, asm_type, c_type, prefix) \ +static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ +{ \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type " zero, %1, %0" \ + : "+A" (v->counter) \ + : "r" (I) \ + : "memory"); \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS(op, asm_op, c_op, I) \ + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) +#else +#define ATOMIC_OPS(op, asm_op, c_op, I) \ + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) \ + ATOMIC_OP (op, asm_op, c_op, I, d, long, 64) +#endif
Quoted 8 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ +ATOMIC_OPS(add, add, +, i) +ATOMIC_OPS(sub, add, +, -i) +ATOMIC_OPS(and, and, &, i) +ATOMIC_OPS( or, or, |, i) +ATOMIC_OPS(xor, xor, ^, i)What is the point in the
c_opparameter to these things?
I guess there isn't one, it just lingered from a handful of refactorings. It's used in some of the other functions if we need to do a C operation after the atomic. How does this look?
commit 5db229491a205ad0e1aa18287e3b342176c62d30 (HEAD -> staging-mm)
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:35:37 2017 -0800
RISC-V: Remove c_op from ATOMIC_OP
This was an unused macro parameter.
arch/riscv/include/asm/atomic.h +8 -8
@@ -50,30 +50,30 @@ static __always_inline void atomic64_set(atomic64_t *v, long i)* have the AQ or RL bits set. These don't return anything, so there's only * one version to worry about. */ -#define ATOMIC_OP (op, asm_op, c_op,I , asm_type, c_type, prefix) \ -static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ -{ \ - __asm__ __volatile__ ( \ - "amo" #asm_op "." #asm_type " zero, %1, %0" \ - : "+A" (v->counter) \ - : "r" (I) \ - : "memory"); \ +#define ATOMIC_OP (op, asm_op,I , asm_type, c_type, prefix) \ +static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ +{ \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type " zero, %1, %0" \ + : "+A" (v->counter) \ + : "r" (I) \ + : "memory"); \
}
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, asm_op, c_op, I) \
- ATOMIC_OP (op, asm_op, c_op, I, w, int, )
+#define ATOMIC_OPS(op, asm_op, I) \
+ ATOMIC_OP (op, asm_op, I, w, int, )
#else
-#define ATOMIC_OPS(op, asm_op, c_op, I) \
- ATOMIC_OP (op, asm_op, c_op, I, w, int, ) \
- ATOMIC_OP (op, asm_op, c_op, I, d, long, 64)
+#define ATOMIC_OPS(op, asm_op, I) \
+ ATOMIC_OP (op, asm_op, I, w, int, ) \
+ ATOMIC_OP (op, asm_op, I, d, long, 64)
#endif
-ATOMIC_OPS(add, add, +, i)
-ATOMIC_OPS(sub, add, +, -i)
-ATOMIC_OPS(and, and, &, i) -ATOMIC_OPS( or, or, |, i) -ATOMIC_OPS(xor, xor, ^, i) +ATOMIC_OPS(add, add, i) +ATOMIC_OPS(sub, add, -i) +ATOMIC_OPS(and, and, i) +ATOMIC_OPS( or, or, i) +ATOMIC_OPS(xor, xor, i)
#undef ATOMIC_OP
#undef ATOMIC_OPS
Quoted 50 lines
Quoted 30 lines
(quoted diff) +29
-0+/* + * Atomic ops that have ordered, relaxed, acquire, and relese variants. + * There's two flavors of these: the arithmatic ops have both fetch and return + * versions, while the logical ops only have fetch versions. + */ +#define ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \ +{ \ + register c_type ret; \ + __asm__ __volatile__ ( \ + "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \ + : "+A" (v->counter), "=r" (ret) \ + : "r" (I) \ + : "memory"); \ + return ret; \ +} + +#define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \ +static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \ +{ \ + return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \ +} + +#ifdef CONFIG_GENERIC_ATOMIC64 +#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) +#else +#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \Review
Quoted 10 lines
(quoted diff) +10
-0+ ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, d, long, 64) \ + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) +#endif + +ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) +ATOMIC_OPS(add, add, +, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;
Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0
I haven't. We don't quite have a formal memory model specification yet. I've added Daniel Lustig, who is creating that model. He should have a better idea
Quoted 9 lines
Quoted 6 lines
+/*
+ * atomic_{cmp,}xchg is required to have exactly the same ordering semantics as
+ * {cmp,}xchg and the operations that return, so they need a barrier. We just
+ * use the other implementations directly.
+ */We also have relaxed/acquire/release versions of cmpxchg and xchg, if you want to implement them.
Ah, I didn't know (or had forgotten) about that. I've added a FIXME, I think the cmpxchg stuff could use a bit of love anyway so I'll look into it in a bit.
Quoted 56 lines
Quoted 56 lines
arch/riscv/include/asm/barrier.h new file +50
-0@@ -0,0 +1,68 @@ +/* +* Based on arch/arm/include/asm/barrier.h +* +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2013 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 version 2 as +* published by the Free Software Foundation. +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _ASM_RISCV_BARRIER_H +#define _ASM_RISCV_BARRIER_H + +#ifndef __ASSEMBLY__ + +#define nop () __asm__ __volatile__ ("nop") + +#define RISCV_FENCE (p, s) \ + __asm__ __volatile__ ("fence " #p "," #s : : : "memory") + +/* These barriers need to enforce ordering on both devices or memory. */ +#define mb () RISCV_FENCE(iorw,iorw) +#define rmb () RISCV_FENCE(ir,ir) +#define wmb () RISCV_FENCE(ow,ow) + +/* These barriers do not need to enforce ordering on devices, just memory. */ +#define smp_mb () RISCV_FENCE(rw,rw) +#define smp_rmb () RISCV_FENCE(r,r) +#define smp_wmb () RISCV_FENCE(w,w) + +/* +* These fences exist to enforce ordering around the relaxed AMOs. The +* documentation defines that +* " +* atomic_fetch_add(); +* is equivalent to: +* smp_mb__before_atomic(); +* atomic_fetch_add_relaxed(); +* smp_mb__after_atomic(); +* "
Quoted 8 lines
arch/riscv/include/asm/barrier.h line 54
Quoted 4 lines
arch/riscv/include/asm/barrier.h new file +4
-0+* So we emit full fences on both sides. +*/ +#define __smb_mb__before_atomic () smp_mb() +#define __smb_mb__after_atomic () smp_mb()Now I'm confused, because you're also spitting out .aqrl for those afaict. Do you really need full barriers *and* .aqrl, or am I misunderstanding something here?
Here's the section of atomic_t.txt that I was reading
The barriers:
smp_mb__{before,after}_atomic() only apply to the RMW ops and can be used to augment/upgrade the ordering inherent to the used atomic op. These barriers provide a full smp_mb().
These helper barriers exist because architectures have varying implicit ordering on their SMP atomic primitives. For example our TSO architectures provide full ordered atomics and these barriers are no-ops.
Thus:
atomic_fetch_add();
is equivalent to:
smp_mb__before_atomic();
atomic_fetch_add_relaxed();
smp_mb__after_atomic(); However the atomic_fetch_add() might be implemented more efficiently.
so I think what we've got there is correct: the barriers go with atomic_fetch_add_relaxed(), not atomic_fetch_add(). asm-generic/barrier.h has
#ifndef __smp_mb__before_atomic #define __smp_mb__before_atomic() __smp_mb() #endif #ifndef __smp_mb__after_atomic #define __smp_mb__after_atomic() __smp_mb() #endif
so I think we can just drop these entirely. How does this look?
commit da682f7ee5d2af4aae7026ef40b5b5fb8e103938
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:49:42 2017 -0800
RISC-V: Remove __smp_bp__{before,after}_atomic
These duplicate the asm-generic definitions are therefor aren't useful.
arch/riscv/include/asm/barrier.h +0 -0
@@ -39,21 +39,6 @@
#define smp_wmb() RISCV_FENCE(w,w)
/*
- * These fences exist to enforce ordering around the relaxed AMOs. The
- * documentation defines that
- * "
- * atomic_fetch_add();
- * is equivalent to:
- * smp_mb__before_atomic(); - * atomic_fetch_add_relaxed(); - * smp_mb__after_atomic();
- * "
- * So we emit full fences on both sides.
- */
-#define __smb_mb__before_atomic() smp_mb()
-#define __smb_mb__after_atomic() smp_mb()
-
-/*
* These barriers prevent accesses performed outside a spinlock from being moved
* inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only
* enforce release consistency, we need full fences here.
Quoted 9 lines
arch/riscv/include/asm/barrier.h line 61
Quoted 7 lines
arch/riscv/include/asm/barrier.h new file +7
-0+ +/* +* These barriers prevent accesses performed outside a spinlock from being moved +* inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only +* enforce release consistency, we need full fences here. +*/ +#define smb_mb__before_spinlock () smp_mb()We killed this macro, so you don't need to define it.
Thanks!
commit 382a1f8b33a04fc0f991e062f70f4c65ca888bca
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:50:37 2017 -0800
RISC-V: Remove smb_mb__{before,after}_spinlock()
These are obselete.
arch/riscv/include/asm/barrier.h +0 -0
@@ -38,14 +38,6 @@
#define smp_rmb() RISCV_FENCE(r,r)
#define smp_wmb() RISCV_FENCE(w,w)
-/*
- * These barriers prevent accesses performed outside a spinlock from being moved
- * inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only
- * enforce release consistency, we need full fences here.
- */
-#define smb_mb__before_spinlock() smp_mb()
-#define smb_mb__after_spinlock() smp_mb()
-
#include <asm-generic/barrier.h>
#endif /* __ASSEMBLY__ */
Quoted 61 lines
Quoted 61 lines
arch/riscv/include/asm/bitops.h new file +55
-0@@ -0,0 +1,218 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_BITOPS_H +#define _ASM_RISCV_BITOPS_H + +#ifndef _LINUX_BITOPS_H +#error "Only <linux/bitops.h> can be included directly" +#endif /* _LINUX_BITOPS_H */ + +#include <linux/compiler.h> +#include <linux/irqflags.h> +#include <asm/barrier.h> +#include <asm/bitsperlong.h> + +#ifndef smp_mb__before_clear_bit +#define smp_mb__before_clear_bit () smp_mb() +#define smp_mb__after_clear_bit () smp_mb() +#endif /* smp_mb__before_clear_bit */ + +#include <asm-generic/bitops/__ffs.h> +#include <asm-generic/bitops/ffz.h> +#include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/__fls.h> +#include <asm-generic/bitops/fls64.h> +#include <asm-generic/bitops/find.h> +#include <asm-generic/bitops/sched.h> +#include <asm-generic/bitops/ffs.h> + +#include <asm-generic/bitops/hweight.h> + +#if (BITS_PER_LONG ==64 ) +#define __AMO (op) "amo" #op ".d" +#elif (BITS_PER_LONG ==32 ) +#define __AMO (op) "amo" #op ".w" +#else +#error "Unexpected BITS_PER_LONG" +#endif + +#define __test_and_op_bit_ord (op, mod, nr, addr, ord) \ +({ \ + unsigned long __res, __mask; \ + __mask = BIT_MASK(nr); \ + __asm__ __volatile__ ( \ + __AMO(op) #ord " %0, %2, %1" \
Quoted 8 lines
arch/riscv/include/asm/bitops.h line 60
Quoted 5 lines
arch/riscv/include/asm/bitops.h new file +5
-0+ : "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \ + : "r" (mod(__mask)) \ + : "memory"); \ + ((__res & __mask) !=0 ); \ +})This looks broken to me -- the value-returning test bitops need to be fully ordered.
Yep, you're right -- I just mis-read atomic_ops.rst (and re-misread it the first time when I went to check again). I think this should do it
commit 9951b6ed76bffb714517d81d9ffceb0eb1796229
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 12:06:06 2017 -0800
RISC-V: __test_and_op_bit_ord should be strongly ordered
I mis-read the documentation.
arch/riscv/include/asm/bitops.h +0 -0
@@ -67,7 +67,7 @@
: "memory");
#define __test_and_op_bit(op, mod, nr, addr) \
- __test_and_op_bit_ord(op, mod, nr, addr, )
+ __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
#define __op_bit(op, mod, nr, addr) \ __op_bit_ord(op, mod, nr, addr, )
Quoted 14 lines
Quoted 14 lines
arch/riscv/include/asm/bitops.h new file +14
-0+/* +* Atomic compare and exchange. Compare OLD with MEM, if identical, +* store NEW in MEM. Return the initial value in MEM. Success is +* indicated by comparing RETURN with OLD. +*/ +#define __cmpxchg (ptr, old, new, size, lrb, scb) \ +({ \ + __typeof__(ptr) __ptr = (ptr); \ + __typeof__(*(ptr)) __old = (old); \ + __typeof__(*(ptr)) __new = (new); \ + __typeof__(*(ptr)) __ret; \ + register unsigned int __rc; \ + switch (size) { \ + case 4: \
Quoted 8 lines
arch/riscv/include/asm/bitops.h line 80
Quoted 6 lines
arch/riscv/include/asm/bitops.h new file +6
-0+ __asm__ __volatile__ ( \ + "0:" \ + "lr.w" #scb " %0, %2\n" \ + "bne %0, %z3, 1f\n" \ + "sc.w" #lrb " %1, %z4, %2\n" \ + "bnez %1, 0b\n" \You don't have an AMO for these?
The RISC-V ISA has no explicit compare-and-swap AMO. There's a blurb about this in the spec.
Quoted 25 lines
Quoted 22 lines
arch/riscv/include/asm/bitops.h new file +22
-0+ "1:" \ + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ + : "rJ" (__old), "rJ" (__new) \ + : "memory"); \ + break; \ + case 8: \ + __asm__ __volatile__ ( \ + "0:" \ + "lr.d" #scb " %0, %2\n" \ + "bne %0, %z3, 1f\n" \ + "sc.d" #lrb " %1, %z4, %2\n" \ + "bnez %1, 0b\n" \ + "1:" \ + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ + : "rJ" (__old), "rJ" (__new) \ + : "memory"); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + __ret; \ +})[...]
Quoted 16 lines
Quoted 4 lines
arch/riscv/include/asm/bitops.h new file +4
-0+#ifndef _ASM_RISCV_SPINLOCK_H +#define _ASM_RISCV_SPINLOCK_H + +#include <linux/kernel.h> arch/riscv/include/asm/bitops.h
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+#include <asm/current.h> + +/* +* Simple spin lock operations. These provide no fairness guarantees. +*/ + +/* FIXME: Replace this with a ticket lock, like MIPS. */ + +#define arch_spin_lock_flags (lock, flags) arch_spin_lock(lock) +#define arch_spin_is_locked (x) ((x)->lock != 0)Missing
READ_ONCE.
Thanks!
commit 64e80b0bf3898a88de09f4e12090b002b57efede
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 12:18:49 2017 -0800
RISC-V: Add READ_ONCE in arch_spin_is_locked()
arch/riscv/include/asm/spinlock.h +0 -0
@@ -25,7 +25,7 @@
/* FIXME: Replace this with a ticket lock, like MIPS. */
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-#define arch_spin_is_locked(x) ((x)->lock != 0)
+#define arch_spin_is_locked(x) (READ_ONCE((x)->lock) != 0)
static inline void arch_spin_unlock(arch_spinlock_t *lock) {
Quoted 10 lines
arch/riscv/include/asm/bitops.h
Quoted 8 lines
arch/riscv/include/asm/bitops.h new file +8
-0+static inline void arch_spin_unlock_wait (arch_spinlock_t *lock) +{ +smp_rmb (); +do { +cpu_relax (); + }while (arch_spin_is_locked (lock)); +smp_acquire__after_ctrl_dep (); +}We killed this one too, so please drop it.
Thanks -- we've got a patch in the queue for this.
Quoted 55 lines
Quoted 30 lines
arch/riscv/include/asm/bitops.h new file +29
-0+/***********************************************************/ + +static inline int arch_read_can_lock (arch_rwlock_t *lock) +{ +return lock->lock >=0 ; +} + +static inline int arch_write_can_lock (arch_rwlock_t *lock) +{ +return lock->lock ==0 ; +} + +static inline void arch_read_lock (arch_rwlock_t *lock) +{ +int tmp; + + __asm__ __volatile__( +"1: lr.w %1, %0\n" +" bltz %1, 1b\n" +" addi %1, %1, 1\n" +" sc.w.aq %1, %1, %0\n" +" bnez %1, 1b\n" + :"+A" (lock->lock),"=&r" (tmp) + ::"memory" ); +} + +static inline void arch_write_lock (arch_rwlock_t *lock) +{ +int tmp;arch/riscv/include/asm/bitops.h
Quoted 10 lines
arch/riscv/include/asm/bitops.h new file +10
-0+ + __asm__ __volatile__( +"1: lr.w %1, %0\n" +" bnez %1, 1b\n" +" li %1, -1\n" +" sc.w.aq %1, %1, %0\n" +" bnez %1, 1b\n" + :"+A" (lock->lock),"=&r" (tmp) + ::"memory" ); +}I think you have the same starvation issues as we have on arm64 here. I strongly recommend moving over to qrwlock :)
Quoted 11 lines
arch/riscv/include/asm/bitops.h new file +11
-0+#ifndef _ASM_RISCV_TLBFLUSH_H +#define _ASM_RISCV_TLBFLUSH_H + +#ifdef CONFIG_MMU + +/* Flush entire local TLB */ +static inline void local_flush_tlb_all (void ) +{ + __asm__ __volatile__ ("sfence.vma" : : :"memory" ); +} +
Quoted 8 lines
arch/riscv/include/asm/bitops.h
Quoted 5 lines
arch/riscv/include/asm/bitops.h new file +5
-0+/* Flush one page from local TLB */ +static inline void local_flush_tlb_page (unsigned long addr) +{ + __asm__ __volatile__ ("sfence.vma %0" : :"r" (addr) :"memory" ); +}Is this serialised against prior updates to the page table (
set_pte) and also against subsequent instruction fetch?
This is a store -> (load, store) fence. The ordering is between stores that touch paging data structures and the implicit loads that come from any memory access when paging is enabled. As far as I can tell, it does not enforce any instruction fetch ordering constraints.
Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Hi Palmer,
Quoted 15 lines · Palmer Dabbelt
Quoted 8 lines · On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected] wrote:
Review
Quoted 5 lines · Palmer Dabbelt
(quoted diff) +5
-0+ATOMIC_OPS(add, add, +, i) +ATOMIC_OPS(sub, add, +, -i) +ATOMIC_OPS(and, and, &, i) +ATOMIC_OPS( or, or, |, i) +ATOMIC_OPS(xor, xor, ^, i)What is the point in the
c_opparameter to these things?I guess there isn't one, it just lingered from a handful of refactorings. It's used in some of the other functions if we need to do a C operation after the atomic. How does this look?
commit
5db229491a205ad0e1aa18287e3b342176c62d30(HEAD -> staging-mm)
Quoted 8 lines
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:35:37 2017 -0800RISC-V: Remove
c_opfromATOMIC_OPThis was an unused macro parameter.
Signed-off-by Palmer Dabbelt <[email protected]>
You can do the same thing for FETCH_OP, I think.
Quoted 14 lines
Quoted 14 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) +ATOMIC_OPS(add, add, +, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;
Quoted 8 lines
Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0I haven't. We don't quite have a formal memory model specification yet. I've added Daniel Lustig, who is creating that model. He should have a better idea
Thanks. You really do need to ensure that, as it's heavily relied upon.
Quoted 55 lines
Quoted 15 lines
Quoted 15 lines
(quoted diff) +15
-0+/* These barriers do not need to enforce ordering on devices, just memory. */ +#define smp_mb() RISCV_FENCE(rw,rw) +#define smp_rmb() RISCV_FENCE(r,r) +#define smp_wmb() RISCV_FENCE(w,w) + +/* + * These fences exist to enforce ordering around the relaxed AMOs. The + * documentation defines that + * " + * atomic_fetch_add(); + * is equivalent to: + * smp_mb__before_atomic(); + * atomic_fetch_add_relaxed(); + * smp_mb__after_atomic(); + * "Quoted 8 lines
Review
Quoted 4 lines
+ * So we emit full fences on both sides.
+ */(quoted diff) +2
-0+#define __smb_mb__before_atomic() smp_mb() +#define __smb_mb__after_atomic() smp_mb()Now I'm confused, because you're also spitting out .aqrl for those afaict. Do you really need full barriers *and* .aqrl, or am I misunderstanding something here?
Here's the section of atomic_t.txt that I was reading
The barriers:
smp_mb__{before,after}_atomic() only apply to the RMW ops and can be used to augment/upgrade the ordering inherent to the used atomic op. These barriers provide a full smp_mb(). These helper barriers exist because architectures have varying implicit ordering on their SMP atomic primitives. For example our TSO architectures provide full ordered atomics and these barriers are no-ops. Thus: atomic_fetch_add(); is equivalent to: smp_mb__before_atomic(); atomic_fetch_add_relaxed(); smp_mb__after_atomic();However the
atomic_fetch_add()might be implemented more efficiently.so I think what we've got there is correct: the barriers go with
atomic_fetch_add_relaxed(), notatomic_fetch_add().asm-generic/barrier.hhas#ifndef __smp_mb__before_atomic #define __smp_mb__before_atomic() __smp_mb() #endif #ifndef __smp_mb__after_atomic #define __smp_mb__after_atomic() __smp_mb() #endifso I think we can just drop these entirely. How does this look?
commit
da682f7ee5d2af4aae7026ef40b5b5fb8e103938
Quoted 8 lines
Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:49:42 2017 -0800RISC-V: Remove __smp_bp__{before,after}_atomic
These duplicate the asm-generic definitions are therefor aren't useful.
Signed-off-by Palmer Dabbelt <[email protected]>
Yes, that looks good to me. I was misunderstanding things, but you're right that you don't need to do anything special for this.
Quoted 27 lines
Quoted 9 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ +/* + * These barriers prevent accesses performed outside a spinlock from being moved + * inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only + * enforce release consistency, we need full fences here. + */ +#define smb_mb__before_spinlock() smp_mb()We killed this macro, so you don't need to define it.
Thanks!
commit
382a1f8b33a04fc0f991e062f70f4c65ca888bcaAuthor: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:50:37 2017 -0800RISC-V: Remove smb_mb__{before,after}_spinlock()
These are obselete.
Signed-off-by Palmer Dabbelt <[email protected]>arch/riscv/include/asm/barrier.h +0
-0
arch/riscv/include/asm/barrier.h line 47
Quoted 10 lines
arch/riscv/include/asm/barrier.h +0
-7@@ -38,14 +38,6 @@#define smp_rmb () RISCV_FENCE(r,r)#define smp_wmb () RISCV_FENCE(w,w) -/* -* These barriers prevent accesses performed outside a spinlock from being moved -* inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only -* enforce release consistency, we need full fences here. -*/ -#define smb_mb__before_spinlock () smp_mb() -#define smb_mb__after_spinlock () smp_mb()
You might still need the __after version, particularly if your lock operation has only acquire semantics. The __before version has been removed.
Quoted 33 lines
arch/riscv/include/asm/barrier.h +0
-0>>+#define __test_and_op_bit_ord(op, mod, nr, addr, ord) \ >>+({ \ >>+ unsigned long __res, __mask; \Quoted 11 lines
Review
Quoted 8 lines
(quoted diff) +8
-0+ __mask = BIT_MASK(nr); \ + __asm__ __volatile__ ( \ + __AMO(op) #ord " %0, %2, %1" \ + : "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \ + : "r" (mod(__mask)) \ + : "memory"); \ + ((__res & __mask) != 0); \ +})This looks broken to me -- the value-returning test bitops need to be fully ordered.
Yep, you're right -- I just mis-read
atomic_ops.rst(and re-misread it the first time when I went to check again). I think this should do itcommit
9951b6ed76bffb714517d81d9ffceb0eb1796229Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 12:06:06 2017 -0800RISC-V:
__test_and_op_bit_ordshould be strongly orderedI mis-read the documentation.
Signed-off-by Palmer Dabbelt <[email protected]>arch/riscv/include/asm/bitops.h +0
-0
arch/riscv/include/asm/bitops.h line 70
Quoted 5 lines
arch/riscv/include/asm/bitops.h +1
-1@@ -67,7 +67,7 @@ : "memory");#define __test_and_op_bit (op, mod, nr, addr) \ - __test_and_op_bit_ord(op, mod, nr, addr, ) + __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
Yes, modulo my earlier comment and litmus test.
Quoted 5 lines
arch/riscv/include/asm/bitops.h +0
-0>>+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) >>+#define arch_spin_is_locked(x) ((x)->lock != 0)Quoted 2 lines
Missing
READ_ONCE.
Quoted 8 lines
Thanks!
commit
64e80b0bf3898a88de09f4e12090b002b57efedeAuthor: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 12:18:49 2017 -0800RISC-V: Add
READ_ONCEinarch_spin_is_locked()Signed-off-by Palmer Dabbelt <[email protected]>
Also looks good.
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static inline void arch_read_lock(arch_rwlock_t *lock) +{ + int tmp; + + __asm__ __volatile__( + "1: lr.w %1, %0\n" + " bltz %1, 1b\n" + " addi %1, %1, 1\n" + " sc.w.aq %1, %1, %0\n" + " bnez %1, 1b\n" + : "+A" (lock->lock), "=&r" (tmp) + :: "memory"); +} + +static inline void arch_write_lock(arch_rwlock_t *lock) +{ + int tmp; + + __asm__ __volatile__( + "1: lr.w %1, %0\n" + " bnez %1, 1b\n" + " li %1, -1\n"
Quoted 8 lines
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ " sc.w.aq %1, %1, %0\n" + " bnez %1, 1b\n" + : "+A" (lock->lock), "=&r" (tmp) + :: "memory"); +}I think you have the same starvation issues as we have on arm64 here. I strongly recommend moving over to qrwlock :)
I still strongly recommend this!
Quoted 21 lines
Quoted 12 lines
Quoted 12 lines
(quoted diff) +11
-0+#ifndef _ASM_RISCV_TLBFLUSH_H +#define _ASM_RISCV_TLBFLUSH_H + +#ifdef CONFIG_MMU + +/* Flush entire local TLB */ +static inline void local_flush_tlb_all(void) +{ + __asm__ __volatile__ ("sfence.vma" : : : "memory"); +} +Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+/* Flush one page from local TLB */ +static inline void local_flush_tlb_page(unsigned long addr) +{ + __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"); +}Is this serialised against prior updates to the page table (
set_pte) and also against subsequent instruction fetch?
Quoted 4 lines
This is a store -> (load, store) fence. The ordering is between stores that touch paging data structures and the implicit loads that come from any memory access when paging is enabled. As far as I can tell, it does not enforce any instruction fetch ordering constraints.
That sounds pretty suspicious to me. You need to ensure that speculative instruction fetch doesn't fetch instructions from the old mapping. Also, store -> (load, store) fences don't generally order the page table walk, which is what you need to order here.
Will
Palmer Dabbelt
maintainerRe: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 21 lines · On Wed, 15 Nov 2017 10:06:01 PST (-0800), [email protected] wrote:
Hi Palmer,
Quoted 18 lines · Palmer Dabbelt
Quoted 8 lines · On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected] wrote:
Review
Quoted 5 lines · Palmer Dabbelt
(quoted diff) +5
-0+ATOMIC_OPS(add, add, +, i) +ATOMIC_OPS(sub, add, +, -i) +ATOMIC_OPS(and, and, &, i) +ATOMIC_OPS( or, or, |, i) +ATOMIC_OPS(xor, xor, ^, i)What is the point in the
c_opparameter to these things?I guess there isn't one, it just lingered from a handful of refactorings. It's used in some of the other functions if we need to do a C operation after the atomic. How does this look?
commit
5db229491a205ad0e1aa18287e3b342176c62d30(HEAD -> staging-mm)Author: Palmer Dabbelt <[email protected]> Date: Tue Nov 14 11:35:37 2017 -0800
Quoted 7 lines
Quoted 5 lines
RISC-V: Remove
c_opfromATOMIC_OPThis was an unused macro parameter.
Signed-off-by Palmer Dabbelt <[email protected]>You can do the same thing for
FETCH_OP, I think.
I agree. I think I got them all this time.
commit be88c8a5f714569b56fffcc9f2d3bc673bdaf16b
Author: Palmer Dabbelt <[email protected]> Date: Wed Nov 15 10:19:15 2017 -0800
Remove c_op from more places
arch/riscv/include/asm/atomic.h +1 -1
@@ -83,7 +83,7 @@ ATOMIC_OPS(xor, xor, i)* There's two flavors of these: the arithmatic ops have both fetch and return * versions, while the logical ops only have fetch versions. */ -#define ATOMIC_FETCH_OP (op, asm_op, c_op,I , asm_or, c_or, asm_type, c_type, prefix) \ +#define ATOMIC_FETCH_OP (op, asm_op,I , asm_or, c_or, asm_type, c_type, prefix) \
static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \
{ \
register c_type ret; \@@ -103,13 +103,13 @@ static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, ato
#ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \
+ ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, )
#else
#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \
+ ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \
- ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, d, long, 64) \
+ ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, d, long, 64) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64)#endif
@@ -126,28 +126,28 @@ ATOMIC_OPS(sub, add, +, -i, .aqrl, )
#undef ATOMIC_OPS
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w, int, )
+#define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \
+ ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, )
#else
-#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \
- ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, d, long, 64)
+#define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \
+ ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, ) \
+ ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, d, long, 64)
#endif
-ATOMIC_OPS(and, and, &, i, , _relaxed) -ATOMIC_OPS(and, and, &, i, .aq , _acquire) -ATOMIC_OPS(and, and, &, i, .rl , _release) -ATOMIC_OPS(and, and, &, i, .aqrl, ) +ATOMIC_OPS(and, and, i, , _relaxed) +ATOMIC_OPS(and, and, i, .aq , _acquire) +ATOMIC_OPS(and, and, i, .rl , _release)
+ATOMIC_OPS(and, and, i, .aqrl, )
-ATOMIC_OPS( or, or, |, i, , _relaxed) -ATOMIC_OPS( or, or, |, i, .aq , _acquire) -ATOMIC_OPS( or, or, |, i, .rl , _release) -ATOMIC_OPS( or, or, |, i, .aqrl, ) +ATOMIC_OPS( or, or, i, , _relaxed) +ATOMIC_OPS( or, or, i, .aq , _acquire) +ATOMIC_OPS( or, or, i, .rl , _release) +ATOMIC_OPS( or, or, i, .aqrl, )
-ATOMIC_OPS(xor, xor, ^, i, , _relaxed) -ATOMIC_OPS(xor, xor, ^, i, .aq , _acquire) -ATOMIC_OPS(xor, xor, ^, i, .rl , _release) -ATOMIC_OPS(xor, xor, ^, i, .aqrl, ) +ATOMIC_OPS(xor, xor, i, , _relaxed) +ATOMIC_OPS(xor, xor, i, .aq , _acquire) +ATOMIC_OPS(xor, xor, i, .rl , _release)
+ATOMIC_OPS(xor, xor, i, .aqrl, )
#undef ATOMIC_OPS
@@ -182,13 +182,13 @@ ATOMIC_OPS(add_negative, add, <, 0) #undef ATOMIC_OP
#undef ATOMIC_OPS
-#define ATOMIC_OP(op, func_op, c_op, I, c_type, prefix) \
+#define ATOMIC_OP(op, func_op, I, c_type, prefix) \
static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v) \
{ \
atomic##prefix##_##func_op(I, v); \
}-#define ATOMIC_FETCH_OP(op, func_op, c_op, I, c_type, prefix) \
+#define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \
static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \
{ \
return atomic##prefix##_fetch_##func_op(I, v); \@@ -202,16 +202,16 @@ static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t
#ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS(op, asm_op, c_op, I) \
- ATOMIC_OP (op, asm_op, c_op, I, int, ) \
- ATOMIC_FETCH_OP (op, asm_op, c_op, I, int, ) \
+ ATOMIC_OP (op, asm_op, I, int, ) \
+ ATOMIC_FETCH_OP (op, asm_op, I, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, )
#else
#define ATOMIC_OPS(op, asm_op, c_op, I) \
- ATOMIC_OP (op, asm_op, c_op, I, int, ) \
- ATOMIC_FETCH_OP (op, asm_op, c_op, I, int, ) \
+ ATOMIC_OP (op, asm_op, I, int, ) \
+ ATOMIC_FETCH_OP (op, asm_op, I, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \
- ATOMIC_OP (op, asm_op, c_op, I, long, 64) \
- ATOMIC_FETCH_OP (op, asm_op, c_op, I, long, 64) \
+ ATOMIC_OP (op, asm_op, I, long, 64) \
+ ATOMIC_FETCH_OP (op, asm_op, I, long, 64) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64)#endif
Quoted 20 lines
Quoted 20 lines
Quoted 19 lines
Review
Quoted 5 lines
(quoted diff) +4
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) +ATOMIC_OPS(add, add, +, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0
Quoted 5 lines
Quoted 3 lines
I haven't. We don't quite have a formal memory model specification yet. I've added Daniel Lustig, who is creating that model. He should have a better idea
Thanks. You really do need to ensure that, as it's heavily relied upon.
I know it's the case for our current processors, and I'm pretty sure it's the case for what's formally specified, but we'll have to wait for the spec in order to prove it.
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static inline void arch_read_lock(arch_rwlock_t *lock) +{ + int tmp; + + __asm__ __volatile__( + "1: lr.w %1, %0\n" + " bltz %1, 1b\n" + " addi %1, %1, 1\n" + " sc.w.aq %1, %1, %0\n" + " bnez %1, 1b\n" + : "+A" (lock->lock), "=&r" (tmp) + :: "memory"); +} + +static inline void arch_write_lock(arch_rwlock_t *lock) +{ + int tmp; + + __asm__ __volatile__( + "1: lr.w %1, %0\n" + " bnez %1, 1b\n" + " li %1, -1\n"Quoted 8 lines
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ " sc.w.aq %1, %1, %0\n" + " bnez %1, 1b\n" + : "+A" (lock->lock), "=&r" (tmp) + :: "memory"); +}I think you have the same starvation issues as we have on arm64 here. I strongly recommend moving over to qrwlock :)
Quoted 1 line
I still strongly recommend this!
I agree. I think we can replace both of these locks with the generic versions -- they're a lot better than ours. It's on the TODO list.
Quoted 27 lines
Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
(quoted diff) +11
-0+#ifndef _ASM_RISCV_TLBFLUSH_H +#define _ASM_RISCV_TLBFLUSH_H + +#ifdef CONFIG_MMU + +/* Flush entire local TLB */ +static inline void local_flush_tlb_all(void) +{ + __asm__ __volatile__ ("sfence.vma" : : : "memory"); +} +Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+/* Flush one page from local TLB */ +static inline void local_flush_tlb_page(unsigned long addr) +{ + __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"); +}Is this serialised against prior updates to the page table (
set_pte) and also against subsequent instruction fetch?Quoted 4 lines
This is a store -> (load, store) fence. The ordering is between stores that touch paging data structures and the implicit loads that come from any memory access when paging is enabled. As far as I can tell, it does not enforce any instruction fetch ordering constraints.
Quoted 4 lines
That sounds pretty suspicious to me. You need to ensure that speculative instruction fetch doesn't fetch instructions from the old mapping. Also, store -> (load, store) fences don't generally order the page table walk, which is what you need to order here.
It's the specific type of store -> (load, store) fence that orders page table walking. "sfence.vma" orders between the page table walker and the store buffer on a single core, as opposed to "fence w,rw" which would order between the memory stages of two different cores.
I'll have to check with a memory model guy for sure, but I don't think "sfence.vma" enforces anything WRT the instruction stream. If that's the case, this should do it
commit 4fa4374b3c73fc0022e51e648e8c9285829f6155
Author: Palmer Dabbelt <[email protected]> Date: Wed Nov 15 10:28:16 2017 -0800
fence.i on TLB flushes
arch/riscv/include/asm/tlbflush.h +0 -0
@@ -17,16 +17,28 @@
#ifdef CONFIG_MMU
-/* Flush entire local TLB */
+/*
+ * Flush entire local TLB. We need the fence.i to ensure newly mapped pages
+ * are fetched correctly.
+ */
static inline void local_flush_tlb_all(void)
{
- __asm__ __volatile__ ("sfence.vma" : : : "memory");
+ __asm__ __volatile__ (
+ "sfence.vma\n\t"
+ "fence.i"
+ : : : "memory"
+ );
}
/* Flush one page from local TLB */
static inline void local_flush_tlb_page(unsigned long addr) {
- __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory");
+ __asm__ __volatile__ (
+ "sfence.vma %0\n\t"
+ "fence.i"
+ : : "r" (addr)
+ : "memory"
+ );
}
#ifndef CONFIG_SMP
Thanks!
RE: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 30 lines · On Wed, 15 Nov 2017 10:06:01 PST (-0800), [email protected] wrote:
Quoted 29 lines · Palmer Dabbelt
Quoted 2 lines · On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected] wrote:
Quoted 1 line · Palmer Dabbelt
Hi Palmer,
Quoted 22 lines
Quoted 14 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) ATOMIC_OPS(add, add, ++, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0I haven't. We don't quite have a formal memory model specification yet. I've added Daniel Lustig, who is creating that model. He should have a better idea
Quoted 5 lines
Quoted 1 line
Thanks. You really do need to ensure that, as it's heavily relied upon.
I know it's the case for our current processors, and I'm pretty sure it's the case for what's formally specified, but we'll have to wait for the spec in order to prove it.
I think Will is right. In the current spec, using .aqrl converts an RCpc load or store into an RCsc load or store, but the acquire(-RCsc) annotation still only applies to the load part of the atomic, and the release(-RCsc) annotation applies only to the store part of the atomic.
Why is that? Picture an machine which implements AMOs using something that looks more like an LR/SC under the covers, or one that uses cache line locking, or anything else along those same lines. In some such machines, there could be a window between lock/reserve and unlock/store-conditional where other later stores could squeeze into, and that would break Will's example among others.
It's likely the same reasoning that causes ARM to use a trailing dmb here, rather than just using ldaxr/stlxr. Is that right Will? I know that's LL/SC and this particular cases uses AMOADD, but it's the same principle. Well, at least according to how we have it in the current memory model draft.
Also, RISC-V currently prefers leading fence mappings, so I think the result here, for atomic_add_return() for example, should be this:
fence rw,rw
amoadd.aq ...
Note that at this point, I think you could even elide the .rl. If I'm reading it right it looks like the ARM mapping does this too (well, the reverse: ARM elides the "a" in ldaxr due to the trailing dmb making it redundant).
Does that seem reasonable to you all?
Dan
Re: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 52 lines · Daniel Lustig
Quoted 30 lines · On Wed, 15 Nov 2017 10:06:01 PST (-0800), [email protected] wrote:
Quoted 29 lines · Palmer Dabbelt
Quoted 2 lines · On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected] wrote:
Quoted 1 line · Palmer Dabbelt
Hi Palmer,
Quoted 22 lines
Quoted 14 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) ATOMIC_OPS(add, add, ++, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0I haven't. We don't quite have a formal memory model specification yet. I've added Daniel Lustig, who is creating that model. He should have a better idea
Quoted 5 lines
Quoted 1 line
Thanks. You really do need to ensure that, as it's heavily relied upon.
I know it's the case for our current processors, and I'm pretty sure it's the case for what's formally specified, but we'll have to wait for the spec in order to prove it.
I think Will is right. In the current spec, using .aqrl converts an RCpc load or store into an RCsc load or store, but the acquire(-RCsc) annotation still only applies to the load part of the atomic, and the release(-RCsc) annotation applies only to the store part of the atomic.
Why is that? Picture an machine which implements AMOs using something that looks more like an LR/SC under the covers, or one that uses cache line locking, or anything else along those same lines. In some such machines, there could be a window between lock/reserve and unlock/store-conditional where other later stores could squeeze into, and that would break Will's example among others.
It's likely the same reasoning that causes ARM to use a trailing dmb here, rather than just using ldaxr/stlxr. Is that right Will? I know that's LL/SC and this particular cases uses AMOADD, but it's the same principle. Well, at least according to how we have it in the current memory model draft.
Quoted 6 lines
Also, RISC-V currently prefers leading fence mappings, so I think the result here, for
atomic_add_return()for example, should be this:fence rw,rw
amoadd.aq ...
Hmm.. if atomic_add_return() is implemented like that, how about the following case:
{x=0, y=0}
P1:
r1 = atomic_add_return(&x, 1); // r1 == 0, x will 1 afterwards
WRITE_ONCE(y, 1);
P2:
r2 = READ_ONCE(y); // r2 = 1
smp_rmb();
r3 = atomic_read(&x); // r3 = 0?, could this result in r1 == 1 && r2 == 1 && r3 == 0? Given you said .aq only effects the load part of AMO, and I don't see anything here preventing the reordering between store of y and the store part of the AMO on P1.
Note: we don't allow (r1 == 1 && r2 == 1 && r3 == 0) in above case for linux kernel. Please see Documentation/atomic_t.txt:
"Fully ordered primitives are ordered against everything prior and everything subsequent. Therefore a fully ordered primitive is like having an smp_mb() before and an smp_mb() after the primitive."
Regards,
Boqun
Quoted 7 lines
Note that at this point, I think you could even elide the .rl. If I'm reading it right it looks like the ARM mapping does this too (well, the reverse: ARM elides the "a" in ldaxr due to the trailing dmb making it redundant).
Does that seem reasonable to you all?
Dan
RE: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 94 lines
-----Original Message-----
From: Boqun Feng [mailto:[email protected]]
Sent: Wednesday, November 15, 2017 5:19 PM
To: Daniel Lustig <[email protected]>
Cc: Palmer Dabbelt <[email protected]>; [email protected]; Arnd Bergmann <[email protected]>; Olof Johansson <[email protected]>; linux- [email protected]; [email protected]; [email protected]
Subject: Re: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking CodeQuoted 3 lines · Daniel Lustig
Quoted 3 lines · On Wed, 15 Nov 2017 10:06:01 PST (-0800), [email protected] wrote:
Quoted 2 lines · Palmer Dabbelt
Quoted 1 line
On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected]
Quoted 19 lines · wrote:
Quoted 19 lines
Quoted 19 lines
Quoted 1 line
Quoted 1 line · Palmer Dabbelt
Hi Palmer,
Quoted 15 lines
Quoted 15 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) ATOMIC_OPS(add, +add, ++, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0I haven't. We don't quite have a formal memory model specification
yet.
Quoted 14 lines
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
I've added Daniel Lustig, who is creating that model. He should have a better idea
Thanks. You really do need to ensure that, as it's heavily relied upon.
I know it's the case for our current processors, and I'm pretty sure it's the case for what's formally specified, but we'll have to wait for the spec in order to prove it.
I think Will is right. In the current spec, using .aqrl converts an RCpc load or store into an RCsc load or store, but the acquire(-RCsc) annotation still only applies to the load part of the atomic, and the release(-RCsc) annotation applies only to the store part of the atomic.
Quoted 5 lines
Why is that? Picture an machine which implements AMOs using something that looks more like an LR/SC under the covers, or one that uses cache line locking, or anything else along those same lines. In some such machines, there could be a window between lock/reserve and unlock/store-conditional where other later stores could squeeze into, and
that would break Will's example among others.
Quoted 5 lines
It's likely the same reasoning that causes ARM to use a trailing dmb here, rather than just using ldaxr/stlxr. Is that right Will? I know that's LL/SC and this particular cases uses AMOADD, but it's the same principle. Well, at least according to how we have it in the current memory
model draft.
Quoted 7 lines
Also, RISC-V currently prefers leading fence mappings, so I think the result here, for
atomic_add_return()for example, should be this:fence rw,rw
amoadd.aq ...Hmm.. if
atomic_add_return()is implemented like that, how about the following case:{x=0, y=0} P1: r1 = atomic_add_return(&x, 1); // r1 == 0, x will 1 afterwards WRITE_ONCE(y, 1); P2: r2 = READ_ONCE(y); // r2 = 1 smp_rmb(); r3 = atomic_read(&x); // r3 = 0?, could this result in r1 == 1 && r2 == 1 && r3 == 0? Given you said .aq only effects the load part of AMO, and I don't see anything here preventing the reordering between store of y and the store part of the AMO on P1.
Quoted 6 lines
Note: we don't allow (r1 == 1 && r2 == 1 && r3 == 0) in above case for linux kernel. Please see
Documentation/atomic_t.txt:"Fully ordered primitives are ordered against everything prior and everything subsequent. Therefore a fully ordered primitive is like having an
smp_mb()before and ansmp_mb()after the primitive."
Yes, you're right Boqun. Good catch, and sorry for over-optimizing too quickly.
In that case, maybe we should just start out having a fence on both sides for now, and then we'll discuss offline whether we want to change the model's behavior here.
Dan
Re: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 97 lines · Daniel Lustig
Quoted 97 lines
-----Original Message-----
From: Boqun Feng [mailto:[email protected]]
Sent: Wednesday, November 15, 2017 5:19 PM
To: Daniel Lustig <[email protected]>
Cc: Palmer Dabbelt <[email protected]>; [email protected]; Arnd Bergmann <[email protected]>; Olof Johansson <[email protected]>; linux- [email protected]; [email protected]; [email protected]
Subject: Re: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking CodeQuoted 3 lines · Daniel Lustig
Quoted 3 lines · On Wed, 15 Nov 2017 10:06:01 PST (-0800), [email protected] wrote:
Quoted 2 lines · Palmer Dabbelt
Quoted 1 line
On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected]
Quoted 19 lines · wrote:
Quoted 19 lines
Quoted 19 lines
Quoted 1 line
Quoted 1 line · Palmer Dabbelt
Hi Palmer,
Quoted 15 lines
Quoted 15 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) ATOMIC_OPS(add, +add, ++, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0I haven't. We don't quite have a formal memory model specification
yet.
Quoted 14 lines
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
I've added Daniel Lustig, who is creating that model. He should have a better idea
Thanks. You really do need to ensure that, as it's heavily relied upon.
I know it's the case for our current processors, and I'm pretty sure it's the case for what's formally specified, but we'll have to wait for the spec in order to prove it.
I think Will is right. In the current spec, using .aqrl converts an RCpc load or store into an RCsc load or store, but the acquire(-RCsc) annotation still only applies to the load part of the atomic, and the release(-RCsc) annotation applies only to the store part of the atomic.
Quoted 5 lines
Why is that? Picture an machine which implements AMOs using something that looks more like an LR/SC under the covers, or one that uses cache line locking, or anything else along those same lines. In some such machines, there could be a window between lock/reserve and unlock/store-conditional where other later stores could squeeze into, and
that would break Will's example among others.
Quoted 5 lines
It's likely the same reasoning that causes ARM to use a trailing dmb here, rather than just using ldaxr/stlxr. Is that right Will? I know that's LL/SC and this particular cases uses AMOADD, but it's the same principle. Well, at least according to how we have it in the current memory
model draft.
Quoted 7 lines
Also, RISC-V currently prefers leading fence mappings, so I think the result here, for
atomic_add_return()for example, should be this:fence rw,rw
amoadd.aq ...Hmm.. if
atomic_add_return()is implemented like that, how about the following case:{x=0, y=0} P1: r1 = atomic_add_return(&x, 1); // r1 == 0, x will 1 afterwards WRITE_ONCE(y, 1); P2: r2 = READ_ONCE(y); // r2 = 1 smp_rmb(); r3 = atomic_read(&x); // r3 = 0?, could this result in r1 == 1 && r2 == 1 && r3 == 0? Given you said .aq only effects the load part of AMO, and I don't see anything here preventing the reordering between store of y and the store part of the AMO on P1.
Note: we don't allow (r1 == 1 && r2 == 1 && r3 == 0) in above case for linux kernel. Please see
Documentation/atomic_t.txt:
Quoted 7 lines
Quoted 3 lines
"Fully ordered primitives are ordered against everything prior and everything subsequent. Therefore a fully ordered primitive is like having an
smp_mb()before and ansmp_mb()after the primitive."Yes, you're right Boqun. Good catch, and sorry for over-optimizing too quickly.
In that case, maybe we should just start out having a fence on both sides for
Actually, given your architecture is RCsc rather than RCpc, so I think maybe you could follow the way that ARM uses(i.e. relaxed load + release store + a full barrier). You can see the commit log of 8e86f0b409a4 ("arm64: atomics: fix use of acquire + release for full barrier semantics") for the reasoning:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8e86f0b409a44193f1587e87b69c5dcf8f65be67
Quoted 3 lines
now, and then we'll discuss offline whether we want to change the model's behavior here.
Sounds great! Any estimation when we can see that(maybe a draft)?
Regards,
Boqun
Quoted 1 line
Dan
RE: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 11 lines
Quoted 2 lines
In that case, maybe we should just start out having a fence on both sides for
Actually, given your architecture is RCsc rather than RCpc, so I think maybe you could follow the way that ARM uses(i.e. relaxed load + release store + a full barrier). You can see the commit log of
8e86f0b409a4("arm64: atomics: fix use of acquire + release for full barrier semantics") for the reasoning:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/co
mmit/?id=8e86f0b409a44193f1587e87b69c5dcf8f65be67
OK I'm catching up now...and I have to say, that is clever! Thanks for the corrections. It would definitely be good to avoid the double fence. Let me think this over a bit more.
One subtle point about RCpc vs. RCsc, though: see below.
Quoted 2 lines
Sounds great! Any estimation when we can see that(maybe a draft)?
The latest should be November 28-30, coinciding with the next RISC-V workshop. Possibly even sooner. We just recently resolved a big debate that's been holding us up for a while, and so now it's just a matter of me writing it all up so it's understandable.
In the meantime, though, let me quickly and informally summarize some of the highlights, in case it helps unblock any further review here:
- The model is now (other-)multi-copy atomic
- .aq and .rl alone mean RCpc
- .aqrl means RCsc
- .aq applies only to the read part of an RMW
- .rl applies only to the write part of an RMW
- Syntactic dependencies are now respected
I recognize this isn't enough detail to do it proper justice, but we'll get the full model out as soon as we can.
Quoted 5 lines
Regards,
BoqunQuoted 1 line
Dan
Re: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Hi Daniel,
Quoted 26 lines · Daniel Lustig
Quoted 11 lines
Quoted 2 lines
In that case, maybe we should just start out having a fence on both sides for
Actually, given your architecture is RCsc rather than RCpc, so I think maybe you could follow the way that ARM uses(i.e. relaxed load + release store + a full barrier). You can see the commit log of
8e86f0b409a4("arm64: atomics: fix use of acquire + release for full barrier semantics") for the reasoning:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/co
mmit/?id=8e86f0b409a44193f1587e87b69c5dcf8f65be67OK I'm catching up now...and I have to say, that is clever! Thanks for the corrections. It would definitely be good to avoid the double fence. Let me think this over a bit more.
One subtle point about RCpc vs. RCsc, though: see below.
Quoted 2 lines
Sounds great! Any estimation when we can see that(maybe a draft)?
The latest should be November 28-30, coinciding with the next RISC-V workshop. Possibly even sooner. We just recently resolved a big debate that's been holding us up for a while, and so now it's just a matter of me writing it all up so it's understandable.
Quoted 6 lines
In the meantime, though, let me quickly and informally summarize some of the highlights, in case it helps unblock any further review here:
- The model is now (other-)multi-copy atomic
- .aq and .rl alone mean RCpc
- .aqrl means RCsc
That presents you with an interesting choice when implementing locks: do you use .aqrl for lock and unlokc and elide smp_mb__after_spinlock, or do you use .aq/.rl for lock/unlock respectively and emit a fence for smp_mb__after_spinlock?
Quoted 3 lines
- .aq applies only to the read part of an RMW
- .rl applies only to the write part of an RMW
- Syntactic dependencies are now respected
Thanks for the update, even this brief summary is better than the current architecture document ;)
Quoted 2 lines
I recognize this isn't enough detail to do it proper justice, but we'll get the full model out as soon as we can.
Ok, I'll bite! Do you forbid LB?
Will
RE: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Quoted 37 lines
From: Will Deacon [mailto:[email protected]]
Hi Daniel,Quoted 19 lines · Daniel Lustig
Quoted 11 lines
Quoted 2 lines
In that case, maybe we should just start out having a fence on both sides for
Actually, given your architecture is RCsc rather than RCpc, so I think maybe you could follow the way that ARM uses(i.e. relaxed load
+ release store + a full barrier). You can see the commit log of8e86f0b409a4
("arm64: atomics: fix use of acquire + release for full barrier semantics") for the reasoning:Quoted 3 lines
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/c
o
mmit/?id=8e86f0b409a44193f1587e87b69c5dcf8f65be67OK I'm catching up now...and I have to say, that is clever! Thanks for the corrections. It would definitely be good to avoid the double fence. Let me think this over a bit more.
Quoted 6 lines
One subtle point about RCpc vs. RCsc, though: see below.
Quoted 2 lines
Sounds great! Any estimation when we can see that(maybe a draft)?
The latest should be November 28-30, coinciding with the next RISC-V
workshop.
Quoted 7 lines
Possibly even sooner. We just recently resolved a big debate that's been holding us up for a while, and so now it's just a matter of me writing it all up so it's understandable.
In the meantime, though, let me quickly and informally summarize some of the highlights, in case it helps unblock any further review here:
Quoted 8 lines
Quoted 3 lines
- The model is now (other-)multi-copy atomic
- .aq and .rl alone mean RCpc
- .aqrl means RCscThat presents you with an interesting choice when implementing locks: do you use .aqrl for lock and unlokc and elide
smp_mb__after_spinlock, or do you use .aq/.rl for lock/unlock respectively and emit a fence forsmp_mb__after_spinlock?
Good question, and I should probably do my homework before weighing in strongly either way.
Quoted 5 lines
Quoted 4 lines
- .aq applies only to the read part of an RMW
- .rl applies only to the write part of an RMW
- Syntactic dependencies are now respected
Quoted 7 lines
Thanks for the update, even this brief summary is better than the current architecture document ;)
Quoted 2 lines
I recognize this isn't enough detail to do it proper justice, but we'll get the full model out as soon as we can.
Ok, I'll bite! Do you forbid LB?
This was definitely one of the topics we debated. In the end, we chose to allow LB but forbid LB+deps or stronger. CPUs may not produce LB all that often, but we didn't see a super strong need to rule it out either. Out-of-thin-air is covered now that we enforce dependencies. Also, GPUs do produce LB, and that's relevant to our (NVIDIA's) use case at least.
I'm happy to keep answering other questions too.
Dan
Palmer Dabbelt
maintainerRE: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
In reply to Daniel LustigQuoted 41 lines · Daniel Lustig
Quoted 30 lines · On Wed, 15 Nov 2017 10:06:01 PST (-0800), [email protected] wrote:
Quoted 29 lines · Palmer Dabbelt
Quoted 2 lines · On Tue, 24 Oct 2017 07:10:33 PDT (-0700), [email protected] wrote:
Quoted 1 line · Palmer Dabbelt
Hi Palmer,
Quoted 22 lines
Quoted 14 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ATOMIC_OPS(add, add, +, i, , _relaxed) +ATOMIC_OPS(add, add, +, i, .aq , _acquire) ATOMIC_OPS(add, add, ++, i, .rl , _release) +ATOMIC_OPS(add, add, +, i, .aqrl, )Have you checked that .aqrl is equivalent to "ordered", since there are interpretations where that isn't the case. Specifically:
// all variables zero at start of time
P0:WRITE_ONCE(x)= 1;atomic_add_return(y, 1);WRITE_ONCE(z)= 1;Quoted 4 lines
P1:
READ_ONCE(z)// reads 1smp_rmb();READ_ONCE(x)// must not read 0I haven't. We don't quite have a formal memory model specification yet. I've added Daniel Lustig, who is creating that model. He should have a better idea
Quoted 5 lines
Quoted 1 line
Thanks. You really do need to ensure that, as it's heavily relied upon.
I know it's the case for our current processors, and I'm pretty sure it's the case for what's formally specified, but we'll have to wait for the spec in order to prove it.
I think Will is right. In the current spec, using .aqrl converts an RCpc load or store into an RCsc load or store, but the acquire(-RCsc) annotation still only applies to the load part of the atomic, and the release(-RCsc) annotation applies only to the store part of the atomic.
Quoted 5 lines
Why is that? Picture an machine which implements AMOs using something that looks more like an LR/SC under the covers, or one that uses cache line locking, or anything else along those same lines. In some such machines, there could be a window between lock/reserve and unlock/store-conditional where other later stores could squeeze into, and that would break Will's example among others.
I'm not sure I understand this. My brand new mental model here is that
amoadd.w.aqrl Rout, Rinc, Raddr
is exactly the same as
0:
lr.w.aq Rout, Raddr
add Rout, Rout, Rinc
sc.w.rl Rtmp, Raddr
bnez Rtmp, 0b
but I don't see how that allows the WRITE_ONCE(z) to appear before the WRITE_ONCE(x). I get it appearing before the SC, but not the LR. Am I misunderstanding acquire/release here? My model for that is that that .aq doesn't let accesses from after (in program order) be observed before, while .rl doesn't let accesses from before move after.
Either way, I think that's still broken, as given the above sequence we could observe
READ_ONCE(y); // -> 0, the add hasn't happened
smp_rmb();
READ_ONCE(z); // -> 1, the write has happened
which is bad.
Quoted 8 lines
It's likely the same reasoning that causes ARM to use a trailing dmb here, rather than just using ldaxr/stlxr. Is that right Will? I know that's LL/SC and this particular cases uses AMOADD, but it's the same principle. Well, at least according to how we have it in the current memory model draft.
Also, RISC-V currently prefers leading fence mappings, so I think the result here, for
atomic_add_return()for example, should be this:
Quoted 8 lines
fence rw,rw
amoadd.aq ...Note that at this point, I think you could even elide the .rl. If I'm reading it right it looks like the ARM mapping does this too (well, the reverse: ARM elides the "a" in ldaxr due to the trailing dmb making it redundant).
Does that seem reasonable to you all?
Well, it's kind of a bummer on my end -- we're going to have to change a lot of stuff to add an extra fence, and it appears that .aqrl is pretty useless. I'm also not convinced this is even valid, it'd map to
fence rw,rw
0:
lr.w.aq Rout, Raddr
add Rout, Rout, Rinc
sc.w Rtmp, Raddr
bnez Rtmp, 0b
which would still allow a subsequent store to be made visible before the 'sc.w', with or without a .rl. Doesn't this mean we need
fence rw,rw
amo.w ...
fence rw,rw
which seems pretty heavy-handed. FWIW, this is exactly how our current hardware interprets amo.w.aqrl -- not really an argument for anything, we're just super conservative because there's no formal spec.
It looks like we're still safe for the _acquire and _release versions. From Documentation/atomic_t.txt:
{}_relaxed: unordered
{}_acquire: the R of the RMW (or atomic_read) is an ACQUIRE {}_release: the W of the RMW (or atomic_set) is a RELEASE
So it's just the ordered ones that are broken. I'm assuming this means our cmpxchg is broken as well
0:
lr.w.aqrl Rold, Raddr
bne Rcomp, Rold, 1f
sc.w.aqrl Rtmp, Rnew, Raddr
bnez Rtmp, 0b
1:
because sc.w.aqrl would be the same as sc.w.rl, so it's just the same as the amoadd case above.
Hopefully I'm just crazy here, I should probably get some sleep at some point :)... I just scanned over some more mail that went by, let's just double-fence for now.
Palmer Dabbelt
maintainerPATCH v9 6/12 RISC-V: Generic library routines and assembly
In reply to Palmer DabbeltThis patch contains code that is more specific to the RISC-V ISA than it is to Linux. It contains string and math operations, C wrappers for various assembly instructions, stack walking code, and uaccess.
--- arch/riscv/include/asm/asm.h | 76 +++++ arch/riscv/include/asm/csr.h | 132 ++++++++ arch/riscv/include/asm/linkage.h | 20 ++ arch/riscv/include/asm/string.h | 26 ++ arch/riscv/include/asm/uaccess.h | 513 ++++++++++++++++++++++++++++++++ arch/riscv/include/asm/word-at-a-time.h | 55 ++++ arch/riscv/kernel/stacktrace.c | 177 +++++++++++ arch/riscv/lib/memcpy.S | 115 +++++++ arch/riscv/lib/memset.S | 120 ++++++++ arch/riscv/lib/uaccess.S | 117 ++++++++ arch/riscv/lib/udivdi3.S | 38 +++ 11 files changed, 1389 insertions(+) create mode 100644 arch/riscv/include/asm/asm.h create mode 100644 arch/riscv/include/asm/csr.h create mode 100644 arch/riscv/include/asm/linkage.h create mode 100644 arch/riscv/include/asm/string.h create mode 100644 arch/riscv/include/asm/uaccess.h create mode 100644 arch/riscv/include/asm/word-at-a-time.h create mode 100644 arch/riscv/kernel/stacktrace.c create mode 100644 arch/riscv/lib/memcpy.S create mode 100644 arch/riscv/lib/memset.S create mode 100644 arch/riscv/lib/uaccess.S create mode 100644 arch/riscv/lib/udivdi3.S
arch/riscv/include/asm/asm.h new file +76 -0
@@ -0,0 +1,76 @@ +/* +* Copyright (C) 2015 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_ASM_H +#define _ASM_RISCV_ASM_H + +#ifdef __ASSEMBLY__ +#define __ASM_STR (x) x +#else +#define __ASM_STR (x) #x +#endif + +#if __riscv_xlen ==64 +#define __REG_SEL (a, b) __ASM_STR(a) +#elif __riscv_xlen ==32 +#define __REG_SEL (a, b) __ASM_STR(b) +#else +#error "Unexpected __riscv_xlen" +#endif + +#define REG_L __REG_SEL(ld, lw) +#define REG_S __REG_SEL(sd, sw) +#define SZREG __REG_SEL(8, 4) +#define LGREG __REG_SEL(3, 2) + +#if __SIZEOF_POINTER__ ==8 +#ifdef __ASSEMBLY__ +#define RISCV_PTR .dword +#define RISCV_SZPTR 8 +#define RISCV_LGPTR 3 +#else +#define RISCV_PTR ".dword" +#define RISCV_SZPTR "8" +#define RISCV_LGPTR "3" +#endif +#elif __SIZEOF_POINTER__ ==4 +#ifdef __ASSEMBLY__ +#define RISCV_PTR .word +#define RISCV_SZPTR 4 +#define RISCV_LGPTR 2 +#else +#define RISCV_PTR ".word" +#define RISCV_SZPTR "4" +#define RISCV_LGPTR "2" +#endif +#else +#error "Unexpected __SIZEOF_POINTER__" +#endif + +#if (__SIZEOF_INT__ ==4 ) +#define INT __ASM_STR(.word) +#define SZINT __ASM_STR(4) +#define LGINT __ASM_STR(2) +#else +#error "Unexpected __SIZEOF_INT__" +#endif + +#if (__SIZEOF_SHORT__ ==2 ) +#define SHORT __ASM_STR(.half) +#define SZSHORT __ASM_STR(2) +#define LGSHORT __ASM_STR(1) +#else +#error "Unexpected __SIZEOF_SHORT__" +#endif + +#endif /* _ASM_RISCV_ASM_H */
arch/riscv/include/asm/csr.h new file +132 -0
132 lines not on this page · raw message
arch/riscv/include/asm/linkage.h new file +20 -0
@@ -0,0 +1,20 @@ +/* +* Copyright (C) 2015 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_LINKAGE_H +#define _ASM_RISCV_LINKAGE_H + +#define __ALIGN .balign 4 +#define __ALIGN_STR ".balign 4" + +#endif /* _ASM_RISCV_LINKAGE_H */
arch/riscv/include/asm/string.h new file +26 -0
@@ -0,0 +1,26 @@ +/* +* Copyright (C) 2013 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_STRING_H +#define _ASM_RISCV_STRING_H + +#include <linux/types.h> +#include <linux/linkage.h> + +#define __HAVE_ARCH_MEMSET +extern asmlinkage void *memset(void *, int, size_t); + +#define __HAVE_ARCH_MEMCPY +extern asmlinkage void *memcpy(void *, const void *, size_t); + +#endif /* _ASM_RISCV_STRING_H */
arch/riscv/include/asm/uaccess.h new file +513 -0
513 lines not on this page · raw message
arch/riscv/include/asm/word-at-a-time.h new file +55 -0
55 lines not on this page · raw message
arch/riscv/kernel/stacktrace.c new file +177 -0
177 lines not on this page · raw message
arch/riscv/lib/memcpy.S new file +115 -0
115 lines not on this page · raw message
arch/riscv/lib/memset.S new file +120 -0
120 lines not on this page · raw message
arch/riscv/lib/uaccess.S new file +117 -0
117 lines not on this page · raw message
arch/riscv/lib/udivdi3.S new file +38 -0
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016-2017 Free Software Foundation, 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 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. + */ + + .globl __udivdi3 +__udivdi3: + mv a2, a1 + mv a1, a0 + li a0, -1 + beqz a2, .L5 + li a3, 1 + bgeu a2, a1, .L2 +.L1: + blez a2, .L2 + slli a2, a2, 1 + slli a3, a3, 1 + bgtu a1, a2, .L1 +.L2: + li a0, 0 +.L3: + bltu a1, a2, .L4 + sub a1, a1, a2 + or a0, a0, a3 +.L4: + srli a3, a3, 1 + srli a2, a2, 1 + bnez a3, .L3 +.L5: + ret
Signature · 1 line
2.13.5
Palmer Dabbelt
maintainerPATCH v9 7/12 RISC-V: ELF and module implementation
In reply to Palmer DabbeltThis patch contains the code that interfaces with ELF objects on RISC-V systems, the vast majority of which is present to load kernel modules.
--- arch/riscv/include/asm/compat.h | 29 ++++++++++++++ arch/riscv/include/asm/elf.h | 84 +++++++++++++++++++++++++++++++++++++++++ arch/riscv/include/asm/hwcap.h | 37 ++++++++++++++++++ arch/riscv/mm/extable.c | 37 ++++++++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 arch/riscv/include/asm/compat.h create mode 100644 arch/riscv/include/asm/elf.h create mode 100644 arch/riscv/include/asm/hwcap.h create mode 100644 arch/riscv/mm/extable.c
arch/riscv/include/asm/compat.h new file +29 -0
@@ -0,0 +1,29 @@ +/* +* Copyright (C) 2012 ARM Ltd. +* +* 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. +* +* 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 <http://www.gnu.org/licenses/>. +*/ +#ifndef __ASM_COMPAT_H +#define __ASM_COMPAT_H +#ifdef CONFIG_COMPAT + +#if defined(CONFIG_64BIT ) +#define COMPAT_UTS_MACHINE "riscv64\0\0" +#elif defined(CONFIG_32BIT ) +#define COMPAT_UTS_MACHINE "riscv32\0\0" +#else +#error "Unknown RISC-V base ISA" +#endif + +#endif /*CONFIG_COMPAT*/ +#endif /*__ASM_COMPAT_H*/
arch/riscv/include/asm/elf.h new file +84 -0
84 lines not on this page · raw message
arch/riscv/include/asm/hwcap.h new file +37 -0
@@ -0,0 +1,37 @@ +/* +* Copied from arch/arm64/include/asm/hwcap.h +* +* Copyright (C) 2012 ARM Ltd. +* 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 version 2 as +* published by the Free Software Foundation. +* +* 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 <http://www.gnu.org/licenses/>. +*/ +#ifndef __ASM_HWCAP_H +#define __ASM_HWCAP_H + +#include <uapi/asm/hwcap.h> + +#ifndef __ASSEMBLY__ +/* +* This yields a mask that user programs can use to figure out what +* instruction set this cpu supports. +*/ +#define ELF_HWCAP (elf_hwcap) + +enum { +CAP_HWCAP =1 , +}; + +extern unsigned long elf_hwcap; +#endif +#endif
arch/riscv/mm/extable.c new file +37 -0
@@ -0,0 +1,37 @@ +/* +* Copyright (C) 2009 Sunplus Core Technology Co., Ltd. +* Lennox Wu <[email protected]> +* Chen Liqin <[email protected]> +* Copyright (C) 2013 Regents of the University of California +* +* 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 <linux/extable.h> +#include <linux/module.h> +#include <linux/uaccess.h> + +int fixup_exception (struct pt_regs *regs) +{ +const struct exception_table_entry *fixup; + + fixup =search_exception_tables (regs->sepc); +if (fixup) { + regs->sepc = fixup->fixup; +return 1 ; + } +return 0 ; +}
Signature · 1 line
2.13.5
Palmer Dabbelt
maintainerPATCH v9 8/12 RISC-V: Task implementation
In reply to Palmer DabbeltThis patch contains the implementation of tasks on RISC-V, most of which is involved in task switching.
--- arch/riscv/include/asm/asm-offsets.h | 1 + arch/riscv/include/asm/current.h | 45 ++++ arch/riscv/include/asm/kprobes.h | 22 ++ arch/riscv/include/asm/processor.h | 97 ++++++++ arch/riscv/include/asm/switch_to.h | 69 ++++++ arch/riscv/include/asm/thread_info.h | 94 +++++++ arch/riscv/kernel/asm-offsets.c | 322 ++++++++++++++++++++++++ arch/riscv/kernel/entry.S | 464 +++++++++++++++++++++++++++++++++++ arch/riscv/kernel/process.c | 129 ++++++++++ 9 files changed, 1243 insertions(+) create mode 100644 arch/riscv/include/asm/asm-offsets.h create mode 100644 arch/riscv/include/asm/current.h create mode 100644 arch/riscv/include/asm/kprobes.h create mode 100644 arch/riscv/include/asm/processor.h create mode 100644 arch/riscv/include/asm/switch_to.h create mode 100644 arch/riscv/include/asm/thread_info.h create mode 100644 arch/riscv/kernel/asm-offsets.c create mode 100644 arch/riscv/kernel/entry.S create mode 100644 arch/riscv/kernel/process.c
arch/riscv/include/asm/asm-offsets.h new file +1 -0
@@ -0,0 +1 @@ +#include <generated/asm-offsets.h>
arch/riscv/include/asm/current.h new file +45 -0
45 lines not on this page · raw message
arch/riscv/include/asm/kprobes.h new file +22 -0
@@ -0,0 +1,22 @@ +/* +* Copied from arch/arm64/include/asm/kprobes.h +* +* Copyright (C) 2013 Linaro Limited +* 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 version 2 as +* published by the Free Software Foundation. +* +* 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. +*/ + +#ifndef _RISCV_KPROBES_H +#define _RISCV_KPROBES_H + +#include <asm-generic/kprobes.h> + +#endif /* _RISCV_KPROBES_H */
arch/riscv/include/asm/processor.h new file +97 -0
97 lines not on this page · raw message
arch/riscv/include/asm/switch_to.h new file +69 -0
69 lines not on this page · raw message
arch/riscv/include/asm/thread_info.h new file +94 -0
94 lines not on this page · raw message
arch/riscv/kernel/asm-offsets.c new file +322 -0
322 lines not on this page · raw message
arch/riscv/kernel/entry.S new file +464 -0
464 lines not on this page · raw message
arch/riscv/kernel/process.c new file +129 -0
129 lines not on this page · raw message
Signature · 1 line
2.13.5
Palmer Dabbelt
maintainerPATCH v9 9/12 RISC-V: Device, timer, IRQs, and the SBI
In reply to Palmer DabbeltThis patch contains code that interfaces with devices that are mandated by the RISC-V supervisor specification and that don't have explicit drivers anywhere else in the tree. This includes the staticly defined interrupts, the CSR-mapped timer, and virtualized SBI devices.
--- arch/riscv/include/asm/delay.h | 28 +++++++++ arch/riscv/include/asm/dma-mapping.h | 38 ++++++++++++ arch/riscv/include/asm/irq.h | 28 +++++++++ arch/riscv/include/asm/irqflags.h | 63 ++++++++++++++++++++ arch/riscv/include/asm/pci.h | 48 +++++++++++++++ arch/riscv/include/asm/sbi.h | 100 +++++++++++++++++++++++++++++++ arch/riscv/include/asm/timex.h | 59 +++++++++++++++++++ arch/riscv/lib/delay.c | 110 +++++++++++++++++++++++++++++++++++ arch/riscv/mm/ioremap.c | 92 +++++++++++++++++++++++++++++ 9 files changed, 566 insertions(+) create mode 100644 arch/riscv/include/asm/delay.h create mode 100644 arch/riscv/include/asm/dma-mapping.h create mode 100644 arch/riscv/include/asm/irq.h create mode 100644 arch/riscv/include/asm/irqflags.h create mode 100644 arch/riscv/include/asm/pci.h create mode 100644 arch/riscv/include/asm/sbi.h create mode 100644 arch/riscv/include/asm/timex.h create mode 100644 arch/riscv/lib/delay.c create mode 100644 arch/riscv/mm/ioremap.c
arch/riscv/include/asm/delay.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* Copyright (C) 2009 Chen Liqin <[email protected]> +* Copyright (C) 2016 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_DELAY_H +#define _ASM_RISCV_DELAY_H + +extern unsigned long riscv_timebase; + +#define udelay udelay +extern void udelay (unsigned long usecs); + +#define ndelay ndelay +extern void ndelay (unsigned long nsecs); + +extern void __delay (unsigned long cycles); + +#endif /* _ASM_RISCV_DELAY_H */
arch/riscv/include/asm/dma-mapping.h new file +38 -0
@@ -0,0 +1,38 @@ +/* +* Copyright (C) 2003-2004 Hewlett-Packard Co +* David Mosberger-Tang <[email protected]> +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2016 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. +* +* 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 <http://www.gnu.org/licenses/>. +*/ +#ifndef __ASM_RISCV_DMA_MAPPING_H +#define __ASM_RISCV_DMA_MAPPING_H + +/* Use ops->dma_mapping_error (if it exists) or assume success */ +// #undef DMA_ERROR_CODE + +static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) +{ +return &dma_noop_ops; +} + +static inline bool dma_capable (struct device *dev,dma_addr_t addr,size_t size) +{ +if (!dev->dma_mask) +return false; + +return addr + size -1 <= *dev->dma_mask; +} + +#endif /* __ASM_RISCV_DMA_MAPPING_H */
arch/riscv/include/asm/irq.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* 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. +*/ + +#ifndef _ASM_RISCV_IRQ_H +#define _ASM_RISCV_IRQ_H + +#define NR_IRQS 0 + +#define INTERRUPT_CAUSE_SOFTWARE 1 +#define INTERRUPT_CAUSE_TIMER 5 +#define INTERRUPT_CAUSE_EXTERNAL 9 + +void riscv_timer_interrupt (void ); + +#include <asm-generic/irq.h> + +#endif /* _ASM_RISCV_IRQ_H */
arch/riscv/include/asm/irqflags.h new file +63 -0
63 lines not on this page · raw message
arch/riscv/include/asm/pci.h new file +48 -0
48 lines not on this page · raw message
arch/riscv/include/asm/sbi.h new file +100 -0
100 lines not on this page · raw message
arch/riscv/include/asm/timex.h new file +59 -0
59 lines not on this page · raw message
arch/riscv/lib/delay.c new file +110 -0
110 lines not on this page · raw message
arch/riscv/mm/ioremap.c new file +92 -0
92 lines not on this page · raw message
Signature · 1 line
2.13.5
Palmer Dabbelt
maintainerPATCH v9 10/12 RISC-V: Paging and MMU
In reply to Palmer DabbeltThis patch contains code to manage the RISC-V MMU, including definitions of the page tables and the page walking code.
--- arch/riscv/include/asm/mmu_context.h | 69 ++++++ arch/riscv/include/asm/page.h | 130 ++++++++++ arch/riscv/include/asm/pgalloc.h | 124 ++++++++++ arch/riscv/include/asm/pgtable-32.h | 25 ++ arch/riscv/include/asm/pgtable-64.h | 84 +++++++ arch/riscv/include/asm/pgtable-bits.h | 48 ++++ arch/riscv/include/asm/pgtable.h | 430 ++++++++++++++++++++++++++++++++++ arch/riscv/mm/fault.c | 282 ++++++++++++++++++++++ 8 files changed, 1192 insertions(+) create mode 100644 arch/riscv/include/asm/mmu_context.h create mode 100644 arch/riscv/include/asm/page.h create mode 100644 arch/riscv/include/asm/pgalloc.h create mode 100644 arch/riscv/include/asm/pgtable-32.h create mode 100644 arch/riscv/include/asm/pgtable-64.h create mode 100644 arch/riscv/include/asm/pgtable-bits.h create mode 100644 arch/riscv/include/asm/pgtable.h create mode 100644 arch/riscv/mm/fault.c
arch/riscv/include/asm/mmu_context.h new file +69 -0
@@ -0,0 +1,69 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_MMU_CONTEXT_H +#define _ASM_RISCV_MMU_CONTEXT_H + +#include <asm-generic/mm_hooks.h> + +#include <linux/mm.h> +#include <linux/sched.h> +#include <asm/tlbflush.h> + +static inline void enter_lazy_tlb (struct mm_struct *mm, +struct task_struct *task) +{ +} + +/* Initialize context-related info for a new mm_struct */ +static inline int init_new_context (struct task_struct *task, +struct mm_struct *mm) +{ +return 0 ; +} + +static inline void destroy_context (struct mm_struct *mm) +{ +} + +static inline pgd_t *current_pgdir (void ) +{ +return pfn_to_virt (csr_read (sptbr) &SPTBR_PPN ); +} + +static inline void set_pgdir (pgd_t *pgd) +{ +csr_write (sptbr,virt_to_pfn (pgd) |SPTBR_MODE ); +} + +static inline void switch_mm (struct mm_struct *prev, +struct mm_struct *next,struct task_struct *task) +{ +if (likely (prev != next)) { +set_pgdir (next->pgd); +local_flush_tlb_all (); + } +} + +static inline void activate_mm (struct mm_struct *prev, +struct mm_struct *next) +{ +switch_mm (prev, next,NULL ); +} + +static inline void deactivate_mm (struct task_struct *task, +struct mm_struct *mm) +{ +} + +#endif /* _ASM_RISCV_MMU_CONTEXT_H */
arch/riscv/include/asm/page.h new file +130 -0
130 lines not on this page · raw message
arch/riscv/include/asm/pgalloc.h new file +124 -0
124 lines not on this page · raw message
arch/riscv/include/asm/pgtable-32.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _ASM_RISCV_PGTABLE_32_H +#define _ASM_RISCV_PGTABLE_32_H + +#include <asm-generic/pgtable-nopmd.h> +#include <linux/const.h> + +/* Size of region mapped by a page global directory */ +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE - 1)) + +#endif /* _ASM_RISCV_PGTABLE_32_H */
arch/riscv/include/asm/pgtable-64.h new file +84 -0
84 lines not on this page · raw message
arch/riscv/include/asm/pgtable-bits.h new file +48 -0
48 lines not on this page · raw message
arch/riscv/include/asm/pgtable.h new file +430 -0
430 lines not on this page · raw message
arch/riscv/mm/fault.c new file +282 -0
282 lines not on this page · raw message
Signature · 6 lines
2.13.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Palmer Dabbelt
maintainerPATCH v9 11/12 RISC-V: User-facing API
In reply to Palmer DabbeltThis patch contains code that is in some way visible to the user:
including via system calls, the VDSO, module loading and signal handling. It also contains some generic code that is ABI visible.
--- arch/riscv/include/asm/mmu.h | 26 +++ arch/riscv/include/asm/ptrace.h | 118 ++++++++++++ arch/riscv/include/asm/syscall.h | 102 +++++++++++ arch/riscv/include/asm/unistd.h | 16 ++ arch/riscv/include/asm/vdso.h | 41 +++++ arch/riscv/include/uapi/asm/Kbuild | 27 +++ arch/riscv/include/uapi/asm/auxvec.h | 24 +++ arch/riscv/include/uapi/asm/bitsperlong.h | 25 +++ arch/riscv/include/uapi/asm/byteorder.h | 23 +++ arch/riscv/include/uapi/asm/elf.h | 83 +++++++++ arch/riscv/include/uapi/asm/hwcap.h | 36 ++++ arch/riscv/include/uapi/asm/ptrace.h | 90 +++++++++ arch/riscv/include/uapi/asm/sigcontext.h | 30 +++ arch/riscv/include/uapi/asm/siginfo.h | 24 +++ arch/riscv/include/uapi/asm/ucontext.h | 45 +++++ arch/riscv/kernel/cpufeature.c | 61 +++++++ arch/riscv/kernel/module.c | 217 ++++++++++++++++++++++ arch/riscv/kernel/ptrace.c | 125 +++++++++++++ arch/riscv/kernel/riscv_ksyms.c | 15 ++ arch/riscv/kernel/signal.c | 292 ++++++++++++++++++++++++++++++ arch/riscv/kernel/sys_riscv.c | 49 +++++ arch/riscv/kernel/syscall_table.c | 25 +++ arch/riscv/kernel/vdso/.gitignore | 2 + arch/riscv/kernel/vdso/Makefile | 63 +++++++ arch/riscv/kernel/vdso/rt_sigreturn.S | 24 +++ arch/riscv/kernel/vdso/vdso.S | 27 +++ arch/riscv/kernel/vdso/vdso.lds.S | 77 ++++++++ 27 files changed, 1687 insertions(+) create mode 100644 arch/riscv/include/asm/mmu.h create mode 100644 arch/riscv/include/asm/ptrace.h create mode 100644 arch/riscv/include/asm/syscall.h create mode 100644 arch/riscv/include/asm/unistd.h create mode 100644 arch/riscv/include/asm/vdso.h create mode 100644 arch/riscv/include/uapi/asm/Kbuild create mode 100644 arch/riscv/include/uapi/asm/auxvec.h create mode 100644 arch/riscv/include/uapi/asm/bitsperlong.h create mode 100644 arch/riscv/include/uapi/asm/byteorder.h create mode 100644 arch/riscv/include/uapi/asm/elf.h create mode 100644 arch/riscv/include/uapi/asm/hwcap.h create mode 100644 arch/riscv/include/uapi/asm/ptrace.h create mode 100644 arch/riscv/include/uapi/asm/sigcontext.h create mode 100644 arch/riscv/include/uapi/asm/siginfo.h create mode 100644 arch/riscv/include/uapi/asm/ucontext.h create mode 100644 arch/riscv/kernel/cpufeature.c create mode 100644 arch/riscv/kernel/module.c create mode 100644 arch/riscv/kernel/ptrace.c create mode 100644 arch/riscv/kernel/riscv_ksyms.c create mode 100644 arch/riscv/kernel/signal.c create mode 100644 arch/riscv/kernel/sys_riscv.c create mode 100644 arch/riscv/kernel/syscall_table.c create mode 100644 arch/riscv/kernel/vdso/.gitignore create mode 100644 arch/riscv/kernel/vdso/Makefile create mode 100644 arch/riscv/kernel/vdso/rt_sigreturn.S create mode 100644 arch/riscv/kernel/vdso/vdso.S create mode 100644 arch/riscv/kernel/vdso/vdso.lds.S
arch/riscv/include/asm/mmu.h new file +26 -0
@@ -0,0 +1,26 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + + +#ifndef _ASM_RISCV_MMU_H +#define _ASM_RISCV_MMU_H + +#ifndef __ASSEMBLY__ + +typedef struct { +void *vdso; +}mm_context_t ; + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_MMU_H */
arch/riscv/include/asm/ptrace.h new file +118 -0
118 lines not on this page · raw message
arch/riscv/include/asm/syscall.h new file +102 -0
102 lines not on this page · raw message
arch/riscv/include/asm/unistd.h new file +16 -0
@@ -0,0 +1,16 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#define __ARCH_HAVE_MMU +#define __ARCH_WANT_SYS_CLONE +#include <uapi/asm/unistd.h>
arch/riscv/include/asm/vdso.h new file +41 -0
41 lines not on this page · raw message
arch/riscv/include/uapi/asm/Kbuild new file +27 -0
@@ -0,0 +1,27 @@ +# UAPI Header export list +include include/uapi/asm-generic/Kbuild.asm + +generic-y += setup.h +generic-y += unistd.h +generic-y += errno.h +generic-y += fcntl.h +generic-y += ioctl.h +generic-y += ioctls.h +generic-y += ipcbuf.h +generic-y += mman.h +generic-y += msgbuf.h +generic-y += param.h +generic-y += poll.h +generic-y += posix_types.h +generic-y += resource.h +generic-y += sembuf.h +generic-y += shmbuf.h +generic-y += signal.h +generic-y += socket.h +generic-y += sockios.h +generic-y += stat.h +generic-y += statfs.h +generic-y += swab.h +generic-y += termbits.h +generic-y += termios.h +generic-y += types.h
arch/riscv/include/uapi/asm/auxvec.h new file +24 -0
@@ -0,0 +1,24 @@ +/* +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2015 Regents of the University of California +* +* 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. +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _UAPI_ASM_RISCV_AUXVEC_H +#define _UAPI_ASM_RISCV_AUXVEC_H + +/* vDSO location */ +#define AT_SYSINFO_EHDR 33 + +#endif /* _UAPI_ASM_RISCV_AUXVEC_H */
arch/riscv/include/uapi/asm/bitsperlong.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2015 Regents of the University of California +* +* 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. +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _UAPI_ASM_RISCV_BITSPERLONG_H +#define _UAPI_ASM_RISCV_BITSPERLONG_H + +#define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8) + +#include <asm-generic/bitsperlong.h> + +#endif /* _UAPI_ASM_RISCV_BITSPERLONG_H */
arch/riscv/include/uapi/asm/byteorder.h new file +23 -0
@@ -0,0 +1,23 @@ +/* +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2015 Regents of the University of California +* +* 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. +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _UAPI_ASM_RISCV_BYTEORDER_H +#define _UAPI_ASM_RISCV_BYTEORDER_H + +#include <linux/byteorder/little_endian.h> + +#endif /* _UAPI_ASM_RISCV_BYTEORDER_H */
arch/riscv/include/uapi/asm/elf.h new file +83 -0
83 lines not on this page · raw message
arch/riscv/include/uapi/asm/hwcap.h new file +36 -0
@@ -0,0 +1,36 @@ +/* +* Copied from arch/arm64/include/asm/hwcap.h +* +* Copyright (C) 2012 ARM Ltd. +* 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 version 2 as +* published by the Free Software Foundation. +* +* 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 <http://www.gnu.org/licenses/>. +*/ +#ifndef __UAPI_ASM_HWCAP_H +#define __UAPI_ASM_HWCAP_H + +/* +* Linux saves the floating-point registers according to the ISA Linux is +* executing on, as opposed to the ISA the user program is compiled for. This +* is necessary for a handful of esoteric use cases: for example, userpsace +* threading libraries must be able to examine the actual machine state in +* order to fully reconstruct the state of a thread. +*/ +#define COMPAT_HWCAP_ISA_I (1 << ('I' - 'A')) +#define COMPAT_HWCAP_ISA_M (1 << ('M' - 'A')) +#define COMPAT_HWCAP_ISA_A (1 << ('A' - 'A')) +#define COMPAT_HWCAP_ISA_F (1 << ('F' - 'A')) +#define COMPAT_HWCAP_ISA_D (1 << ('D' - 'A')) +#define COMPAT_HWCAP_ISA_C (1 << ('C' - 'A')) + +#endif
arch/riscv/include/uapi/asm/ptrace.h new file +90 -0
90 lines not on this page · raw message
arch/riscv/include/uapi/asm/sigcontext.h new file +30 -0
@@ -0,0 +1,30 @@ +/* +* Copyright (C) 2012 Regents of the University of California +* +* 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. +*/ + +#ifndef _UAPI_ASM_RISCV_SIGCONTEXT_H +#define _UAPI_ASM_RISCV_SIGCONTEXT_H + +#include <asm/ptrace.h> + +/* +* Signal context structure +* +* This contains the context saved before a signal handler is invoked; +* it is restored by sys_sigreturn / sys_rt_sigreturn. +*/ +struct sigcontext { +struct user_regs_struct sc_regs; +union __riscv_fp_state sc_fpregs; +}; + +#endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
arch/riscv/include/uapi/asm/siginfo.h new file +24 -0
@@ -0,0 +1,24 @@ +/* +* Copyright (C) 2012 ARM Ltd. +* Copyright (C) 2016 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. +* +* 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 <http://www.gnu.org/licenses/>. +*/ +#ifndef __ASM_SIGINFO_H +#define __ASM_SIGINFO_H + +#define __ARCH_SI_PREAMBLE_SIZE (__SIZEOF_POINTER__ == 4 ? 12 : 16) + +#include <asm-generic/siginfo.h> + +#endif
arch/riscv/include/uapi/asm/ucontext.h new file +45 -0
45 lines not on this page · raw message
arch/riscv/kernel/cpufeature.c new file +61 -0
61 lines not on this page · raw message
arch/riscv/kernel/module.c new file +217 -0
217 lines not on this page · raw message
arch/riscv/kernel/ptrace.c new file +125 -0
125 lines not on this page · raw message
arch/riscv/kernel/riscv_ksyms.c new file +15 -0
@@ -0,0 +1,15 @@ +/* +* Copyright (C) 2017 Zihao Yu +* +* 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 <linux/export.h> +#include <linux/uaccess.h> + +/* +* Assembly functions that may be used (directly or indirectly) by modules +*/ +EXPORT_SYMBOL (__copy_user);
arch/riscv/kernel/signal.c new file +292 -0
292 lines not on this page · raw message
arch/riscv/kernel/sys_riscv.c new file +49 -0
49 lines not on this page · raw message
arch/riscv/kernel/syscall_table.c new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2009 Arnd Bergmann <[email protected]> +* Copyright (C) 2012 Regents of the University of California +* +* 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 <linux/linkage.h> +#include <linux/syscalls.h> +#include <asm-generic/syscalls.h> + +#undef __SYSCALL +#define __SYSCALL (nr, call) [nr] = (call), + +void *sys_call_table[__NR_syscalls] = { + [0 ... __NR_syscalls -1 ] = sys_ni_syscall, +#include <asm/unistd.h> +};
arch/riscv/kernel/vdso/.gitignore new file +2 -0
@@ -0,0 +1,2 @@ +vdso.lds +*.tmp
arch/riscv/kernel/vdso/Makefile new file +63 -0
63 lines not on this page · raw message
arch/riscv/kernel/vdso/rt_sigreturn.S new file +24 -0
@@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 Regents of the University of California + * + * 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 <linux/linkage.h> +#include <asm/unistd.h> + + .text +ENTRY(__vdso_rt_sigreturn) + .cfi_startproc + .cfi_signal_frame + li a7, __NR_rt_sigreturn + scall + .cfi_endproc +ENDPROC(__vdso_rt_sigreturn)
arch/riscv/kernel/vdso/vdso.S new file +27 -0
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 Regents of the University of California + * + * 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 <linux/init.h> +#include <linux/linkage.h> +#include <asm/page.h> + + __PAGE_ALIGNED_DATA + + .globl vdso_start, vdso_end + .balign PAGE_SIZE +vdso_start: + .incbin "arch/riscv/kernel/vdso/vdso.so" + .balign PAGE_SIZE +vdso_end: + + .previous
arch/riscv/kernel/vdso/vdso.lds.S new file +77 -0
77 lines not on this page · raw message
Signature · 1 line
2.13.5
Palmer Dabbelt
maintainerPATCH v9 12/12 RISC-V: Build Infrastructure
In reply to Palmer DabbeltThis patch contains all the build infrastructure that actually enables the RISC-V port. This includes Makefiles, linker scripts, and Kconfig files. It also contains the only top-level change, which adds RISC-V to the list of architectures that need a sed run to produce the ARCH variable when building locally.
--- Makefile | 3 +- arch/riscv/Kconfig | 310 ++++++++++++++++++++++++++++++++++++++++ arch/riscv/Makefile | 72 ++++++++++ arch/riscv/configs/defconfig | 0 arch/riscv/include/asm/Kbuild | 61 ++++++++ arch/riscv/kernel/.gitignore | 1 + arch/riscv/kernel/Makefile | 33 +++++ arch/riscv/kernel/vmlinux.lds.S | 92 ++++++++++++ arch/riscv/lib/Makefile | 6 + arch/riscv/mm/Makefile | 4 + 10 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/Kconfig create mode 100644 arch/riscv/Makefile create mode 100644 arch/riscv/configs/defconfig create mode 100644 arch/riscv/include/asm/Kbuild create mode 100644 arch/riscv/kernel/.gitignore create mode 100644 arch/riscv/kernel/Makefile create mode 100644 arch/riscv/kernel/vmlinux.lds.S create mode 100644 arch/riscv/lib/Makefile create mode 100644 arch/riscv/mm/Makefile
Makefile +2 -1
@@ -225,7 +225,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/riscv.*/riscv/) # Cross compiling and selecting different set of gcc/bin-utils # ---------------------------------------------------------------------------
arch/riscv/Kconfig new file +310 -0
310 lines not on this page · raw message
arch/riscv/Makefile new file +72 -0
72 lines not on this page · raw message
arch/riscv/configs/defconfig new file +0 -0
arch/riscv/include/asm/Kbuild new file +61 -0
61 lines not on this page · raw message
arch/riscv/kernel/.gitignore new file +1 -0
@@ -0,0 +1 @@ +/vmlinux.lds
arch/riscv/kernel/Makefile new file +33 -0
@@ -0,0 +1,33 @@ +# +# Makefile for the RISC-V Linux kernel +# + +extra-y += head.o +extra-y += vmlinux.lds + +obj-y += cpu.o +obj-y += cpufeature.o +obj-y += entry.o +obj-y += irq.o +obj-y += process.o +obj-y += ptrace.o +obj-y += reset.o +obj-y += setup.o +obj-y += signal.o +obj-y += syscall_table.o +obj-y += sys_riscv.o +obj-y += time.o +obj-y += traps.o +obj-y += riscv_ksyms.o +obj-y += stacktrace.o +obj-y += vdso.o +obj-y += cacheinfo.o +obj-y += vdso/ + +CFLAGS_setup.o := -mcmodel=medany + +obj-$(CONFIG_SMP) += smpboot.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_MODULES) += module.o + +clean:
arch/riscv/kernel/vmlinux.lds.S new file +92 -0
92 lines not on this page · raw message
arch/riscv/lib/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +lib-y += delay.o +lib-y += memcpy.o +lib-y += memset.o +lib-y += uaccess.o + +lib-$(CONFIG_32BIT) += udivdi3.o
arch/riscv/mm/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +obj-y += init.o +obj-y += fault.o +obj-y += extable.o +obj-y += ioremap.o
Signature · 6 lines
2.13.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 5 lines · Palmer Dabbelt
As per suggestions on our v8 patch set, I've split the core architecture code out from our drivers and would like to submit this patch set to be included into linux-next, with the goal being to be merged in during the next merge window. This patch set is based on 4.14-rc2, but if it's better to have it based on something else then I can change it around.
-rc2 is good, just don't rebase it any more. I'd suggest that at the point this becomes part of linux-next, you stop modifying the patches further and move to adding any additional changes as patches on top.
Quoted 4 lines
* I cleaned up the defconfigs -- there's actually now just one, and it's empty. For now I think we're OK with what the kernel sets as defaults, but I anticipate we'll begin to expand this as people start to use the port more.
The kernel defaults are not really as sensible as one would hope. Maybe go through your previous defconfig once more and pick up the items that made sense.
Arnd
Palmer Dabbelt
maintainerQuoted 10 lines · Arnd Bergmann
Quoted 5 lines · Palmer Dabbelt
As per suggestions on our v8 patch set, I've split the core architecture code out from our drivers and would like to submit this patch set to be included into linux-next, with the goal being to be merged in during the next merge window. This patch set is based on 4.14-rc2, but if it's better to have it based on something else then I can change it around.
-rc2 is good, just don't rebase it any more. I'd suggest that at the point this becomes part of linux-next, you stop modifying the patches further and move to adding any additional changes as patches on top.
Sounds good. I've gotten a kernel.org account now, so I've gone ahead and signed a "for-linux-next" tag that contains this patch set. I'm going to treat what's here as an official pull request into linux-next and therefor I won't be rewriting history any more. If I understand everything correctly, once I'm in linux-next I'm meant to update that tag with commits that are ready to go?
Is there anything further I should do in order to get that tag merged into linux-next?
Quoted 8 lines
Quoted 4 lines
* I cleaned up the defconfigs -- there's actually now just one, and it's empty. For now I think we're OK with what the kernel sets as defaults, but I anticipate we'll begin to expand this as people start to use the port more.
The kernel defaults are not really as sensible as one would hope. Maybe go through your previous defconfig once more and pick up the items that made sense.
I was a bit surprised at the defaults: for example, I'd expect things like CONFIG_PCI and CONFIG_NET to be enabled by default. I guess I just assumed that since technically we have a working kernel without those that it was fine to just stick with the defaults. Looking at our old defconfig, I'd pick
CONFIG_PCI=y
CONFIG_NAMESPACES=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_DEVTMPFS=y
CONFIG_EXT2_FS=y
CONFIG_TMPFS=y
does that seem reasonable?
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 12 lines · Palmer Dabbelt
Quoted 10 lines · Arnd Bergmann
Quoted 5 lines · Palmer Dabbelt
As per suggestions on our v8 patch set, I've split the core architecture code out from our drivers and would like to submit this patch set to be included into linux-next, with the goal being to be merged in during the next merge window. This patch set is based on 4.14-rc2, but if it's better to have it based on something else then I can change it around.
-rc2 is good, just don't rebase it any more. I'd suggest that at the point this becomes part of linux-next, you stop modifying the patches further and move to adding any additional changes as patches on top.
Quoted 8 lines
Sounds good. I've gotten a kernel.org account now, so I've gone ahead and signed a "for-linux-next" tag that contains this patch set. I'm going to treat what's here as an official pull request into linux-next and therefor I won't be rewriting history any more. If I understand everything correctly, once I'm in linux-next I'm meant to update that tag with commits that are ready to go?
Is there anything further I should do in order to get that tag merged into linux-next?
Please be aware that Stephen has announced that there won't be any linux-next trees until the end of the month, which will be the kernel summit in Prague.
https://lkml.org/lkml/2017/9/29/13
It may be worth sending him a request to include your tree when he returns, I assume there will be a long email backlog and he might miss it otherwise.
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
* I cleaned up the defconfigs -- there's actually now just one, and it's empty. For now I think we're OK with what the kernel sets as defaults, but I anticipate we'll begin to expand this as people start to use the port more.
Quoted 8 lines
Quoted 3 lines
The kernel defaults are not really as sensible as one would hope. Maybe go through your previous defconfig once more and pick up the items that made sense.
I was a bit surprised at the defaults: for example, I'd expect things like
CONFIG_PCIandCONFIG_NETto be enabled by default. I guess I just assumed that since technically we have a working kernel without those that it was fine to just stick with the defaults.
Some of the defaults are really pretty random and are only like this for historic reasons.
Quoted 11 lines
Looking at our old defconfig, I'd pick
CONFIG_PCI=y
CONFIG_NAMESPACES=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_DEVTMPFS=y
CONFIG_EXT2_FS=y
CONFIG_TMPFS=y
Quoted 1 line
does that seem reasonable?
Mostly yes, but please disable ext2 and use ext4 instead.
Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html