Skip to contentSkip to conversation

RISC-V Linux Port v9

PATCH In review Palmer Dabbelt 7 participants 34 messages Sep 27, 2017 – Jul 31, 2018

Subsystems (10)
lore
Share & tools
lore

Palmer Dabbelt

author maintainer
#0 lore raw

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.

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

author maintainer
#1 lore raw

PATCH 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
index 6671f375f7fc..715e0e534d18 100644
@@ -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
author maintainer
#2 lore raw

PATCH v9 2/12 lib: Add shared copies of some GCC library routines

In reply to Palmer Dabbelt

Many 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
new file mode 100644
index 000000000000..32e1e0f4b2d0
@@ -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
index b1445b22a6de..a2b6745324ab 100644
@@ -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
index dafa79613fb4..5ad444501f2d 100644
@@ -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
new file mode 100644
index 000000000000..49a53505c8e3
@@ -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
author maintainer
#3 lore raw

PATCH v9 3/12 dt-bindings: RISC-V CPU Bindings

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..adf7b7af5dc3
@@ -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
reviewer
#4 lore raw

Re: [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.

#5 lore raw

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

author maintainer
#6 lore raw

Re: [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.

author maintainer
#7 lore raw

PATCH v9 4/12 RISC-V: Init and Halt Code

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..c3e13764a943
@@ -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
new file mode 100644
index 000000000000..e8f0d1110d74
@@ -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
new file mode 100644
index 000000000000..328718e8026e
@@ -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
new file mode 100644
index 000000000000..2a53d26ffdd6
@@ -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
reviewer
#8 lore raw

Re: [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.

author maintainer
#9 lore raw

Re: [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() ((struct thread_info *)get_current())
#define raw_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/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.

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 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).

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 new mmgrab() 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!

reviewer
#10 lore raw

Re: [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/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.

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);

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 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).

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 new mmgrab() 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.

author maintainer
#11 lore raw

PATCH v9 5/12 RISC-V: Atomic and Locking Code

In reply to 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.

---
 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
new file mode 100644
index 000000000000..e2e37c57cbeb
@@ -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
new file mode 100644
index 000000000000..0595585013b0
@@ -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)
+{
+	asm volatile ("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
new file mode 100644
index 000000000000..83ac4ac9e2ac
@@ -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
new file mode 100644
index 000000000000..c229509288ea
@@ -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
#12 lore raw

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.

---
 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 +66 -0
new file mode 100644
index 000000000000..e2e37c57cbeb
@@ -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 1
smp_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
new file mode 100644
index 000000000000..183534b7c39b
@@ -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
new file mode 100644
index 000000000000..7c281ef1d583
@@ -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;					\
+	register unsigned 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

author maintainer
#13 lore raw

Re: [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.

---
 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_op parameter 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
index e2e37c57cbeb..a76a094c18f9 100644
@@ -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 1
smp_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
new file mode 100644
index 000000000000..183534b7c39b
@@ -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
index 183534b7c39b..455ee16127fb 100644
@@ -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
index 455ee16127fb..773c4e039cd7 100644
@@ -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
new file mode 100644
index 000000000000..7c281ef1d583
@@ -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
index 7c281ef1d583..f30daf26f08f 100644
@@ -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
index b3b394ffaf7e..fb80782f8567 100644
@@ -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.

#14 lore raw

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_op parameter 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 -0800

RISC-V: Remove c_op from ATOMIC_OP

This was an unused macro parameter.

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 1
smp_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

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(), 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

Quoted 8 lines
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.

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 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
index 455ee16127fb..773c4e039cd7 100644

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 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
index 7c281ef1d583..f30daf26f08f 100644

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 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()

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

author maintainer
#15 lore raw

Re: [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_op parameter 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_op from ATOMIC_OP

This was an unused macro parameter.

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
index 77a7fc55daab..1982c865ba59 100644
@@ -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 1
smp_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
index 5ee4ae370b5e..cda08a9734c5 100644
@@ -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!

#16 lore raw

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 1
smp_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 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

#17 lore raw

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 1
smp_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 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

#18 lore raw

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 Code

Quoted 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 1
smp_rmb();
READ_ONCE(x) // must not read 0

I 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 an smp_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

#19 lore raw

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 Code

Quoted 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 1
smp_rmb();
READ_ONCE(x) // must not read 0

I 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 an smp_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

#20 lore raw

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,
Boqun

Quoted 1 line

Dan

#21 lore raw

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=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.

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

#22 lore raw

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 of 8e86f0b409a4
("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=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.

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 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?

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

author maintainer
#23 lore raw

RE: [patches] Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code

In reply to Daniel Lustig
Quoted 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 1
smp_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 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.

author maintainer
#24 lore raw

PATCH v9 6/12 RISC-V: Generic library routines and assembly

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..6cbbb6a68d76
@@ -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
new file mode 100644
index 000000000000..b7b304ca89c4
@@ -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
new file mode 100644
index 000000000000..9210fcf4ff52
@@ -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
new file mode 100644
index 000000000000..cb01ae5b181a
@@ -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
author maintainer
#25 lore raw

PATCH v9 7/12 RISC-V: ELF and module implementation

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..044aecff8854
@@ -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
new file mode 100644
index 000000000000..8a4ed7bbcbea
@@ -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
new file mode 100644
index 000000000000..11bb9417123b
@@ -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
author maintainer
#26 lore raw

PATCH v9 8/12 RISC-V: Task implementation

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..d370ee36a182
@@ -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
new file mode 100644
index 000000000000..c7eb010d1528
@@ -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
author maintainer
#27 lore raw

PATCH v9 9/12 RISC-V: Device, timer, IRQs, and the SBI

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..cbb0c9eb96cb
@@ -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
new file mode 100644
index 000000000000..3eec1000196d
@@ -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
new file mode 100644
index 000000000000..4dee9d4c13c0
@@ -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
author maintainer
#28 lore raw

PATCH v9 10/12 RISC-V: Paging and MMU

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..de1fc1631fc4
@@ -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
new file mode 100644
index 000000000000..d61974b74182
@@ -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
author maintainer
#29 lore raw

PATCH v9 11/12 RISC-V: User-facing API

In reply to Palmer Dabbelt

This 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
new file mode 100644
index 000000000000..66805cba9a27
@@ -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
new file mode 100644
index 000000000000..9f250ed007cd
@@ -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
new file mode 100644
index 000000000000..5ded96b06352
@@ -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
new file mode 100644
index 000000000000..1376515547cd
@@ -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
new file mode 100644
index 000000000000..0b3cb52fd29d
@@ -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
new file mode 100644
index 000000000000..4ca38af2cd32
@@ -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
new file mode 100644
index 000000000000..f333221c9ab2
@@ -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
new file mode 100644
index 000000000000..ed7372b277fa
@@ -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
new file mode 100644
index 000000000000..f96849aac662
@@ -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
new file mode 100644
index 000000000000..23cc81ec9e94
@@ -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
new file mode 100644
index 000000000000..4e30dc5fb593
@@ -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
new file mode 100644
index 000000000000..97c2d69d0289
@@ -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
new file mode 100644
index 000000000000..f5aa3d72acfb
@@ -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
new file mode 100644
index 000000000000..7055de5f9174
@@ -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
author maintainer
#30 lore raw

PATCH v9 12/12 RISC-V: Build Infrastructure

In reply to Palmer Dabbelt

This 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
index d1119941261c..08ffcb172bec 100644
@@ -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
new file mode 100644
index 000000000000..e69de29bb2d1
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
new file mode 100644
index 000000000000..b51634f6a7cd
@@ -0,0 +1 @@
+/vmlinux.lds
arch/riscv/kernel/Makefile new file +33 -0
new file mode 100644
index 000000000000..ab8baf7bd142
@@ -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
new file mode 100644
index 000000000000..596c2ca40d63
@@ -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
new file mode 100644
index 000000000000..81f7d9ce6d88
@@ -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
#31 lore raw
In reply to Palmer Dabbelt
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

author maintainer
#32 lore raw
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.

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

#33 lore raw
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_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.

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