Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1684722 > unrolled thread
| Started by | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| First post | 2017-07-11 04:00 +0200 |
| Last post | 2017-07-11 22:00 +0200 |
| Articles | 20 on this page of 32 — 7 participants |
Back to article view | Back to linux.kernel
RISC-V Linux Port v5 Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 17/17] RISC-V: Build Infastructure Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
Re: [PATCH 17/17] RISC-V: Build Infastructure Michael Ellerman <mpe@ellerman.id.au> - 2017-07-11 08:40 +0200
Re: [PATCH 17/17] RISC-V: Build Infastructure Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 18:30 +0200
Re: [PATCH 17/17] RISC-V: Build Infastructure Michael Ellerman <mpe@ellerman.id.au> - 2017-07-12 12:50 +0200
[PATCH 06/17] irqchip: RISC-V Local Interrupt Controller Driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 07/17] irqchip: New RISC-V PLIC Driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 02/17] pci: Add a generic, weakly-linked pcibios_align_resource Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 08/17] tty: New RISC-V SBI console driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Michael Ellerman <mpe@ellerman.id.au> - 2017-07-11 08:30 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 18:30 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Michael Ellerman <mpe@ellerman.id.au> - 2017-07-12 13:10 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-12 18:30 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Michael Ellerman <mpe@ellerman.id.au> - 2017-07-13 14:10 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver James Hogan <james.hogan@imgtec.com> - 2017-07-13 14:40 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-14 00:00 +0200
Re: [PATCH 08/17] tty: New RISC-V SBI console driver Michael Ellerman <mpe@ellerman.id.au> - 2017-07-14 07:10 +0200
[PATCH 12/17] RISC-V: ELF and module implementation Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 15/17] RISC-V: Paging and MMU Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 04/17] MAINTAINERS: Add RISC-V Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 05/17] clocksource: New RISC-V SBI timer driver Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
[PATCH 03/17] pci: Add a generic, weakly-linked pcibios_fixup_bus Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
Re: [PATCH 03/17] pci: Add a generic, weakly-linked pcibios_fixup_bus "Luis R. Rodriguez" <mcgrof@kernel.org> - 2017-07-11 21:00 +0200
[PATCH 01/17] lib: Add shared copies of some GCC library routines Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
Re: [PATCH 01/17] lib: Add shared copies of some GCC library routines Randy Dunlap <rdunlap@infradead.org> - 2017-07-11 04:10 +0200
Re: [PATCH 01/17] lib: Add shared copies of some GCC library routines Stephen Rothwell <sfr@canb.auug.org.au> - 2017-07-11 04:10 +0200
[PATCH 14/17] RISC-V: Device, timer, IRQs, and the SBI Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 04:00 +0200
Re: [PATCH 16/17] RISC-V: User-facing API Christoph Hellwig <hch@infradead.org> - 2017-07-11 15:50 +0200
Re: [PATCH 16/17] RISC-V: User-facing API James Hogan <james.hogan@imgtec.com> - 2017-07-11 16:10 +0200
Re: [patches] Re: [PATCH 16/17] RISC-V: User-facing API Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 19:30 +0200
Re: RISC-V Linux Port v5 "Luis R. Rodriguez" <mcgrof@kernel.org> - 2017-07-11 20:40 +0200
Re: RISC-V Linux Port v5 Palmer Dabbelt <palmer@dabbelt.com> - 2017-07-11 22:00 +0200
Page 1 of 2 [1] 2 Next page →
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | RISC-V Linux Port v5 |
| Message-ID | <u1SD0-4hH-1@gated-at.bofh.it> |
Thanks to everyone who has participated in the review process so far. I've based this patch set on the current master. Things have really started to calmn 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 cooresponding 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. Like last time, in case one gets eaten by the mailing list this is also available as a git tree on our Git Hub https://github.com/riscv/riscv-linux/tree/riscv-for-submission-arch-v5 Thanks to everyone who has helped review our port! [PATCH 01/17] lib: Add shared copies of some GCC library routines [PATCH 02/17] pci: Add a generic, weakly-linked [PATCH 03/17] pci: Add a generic, weakly-linked pcibios_fixup_bus [PATCH 04/17] MAINTAINERS: Add RISC-V [PATCH 05/17] clocksource: New RISC-V SBI timer driver [PATCH 06/17] irqchip: RISC-V Local Interrupt Controller Driver [PATCH 07/17] irqchip: New RISC-V PLIC Driver [PATCH 08/17] tty: New RISC-V SBI console driver [PATCH 09/17] RISC-V: Init and Halt Code [PATCH 10/17] RISC-V: Atomic and Locking Code [PATCH 11/17] RISC-V: Generic library routines and assembly [PATCH 12/17] RISC-V: ELF and module implementation [PATCH 13/17] RISC-V: Task implementation [PATCH 14/17] RISC-V: Device, timer, IRQs, and the SBI [PATCH 15/17] RISC-V: Paging and MMU [PATCH 16/17] RISC-V: User-facing API [PATCH 17/17] RISC-V: Build Infastructure
[toc] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 17/17] RISC-V: Build Infastructure |
| Message-ID | <u1SD0-4hH-3@gated-at.bofh.it> |
| In reply to | #1684722 |
This patch contains all the build infastructure 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.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
Makefile | 3 +-
arch/riscv/Kconfig | 294 ++++++++++++++++++++++++++++++
arch/riscv/Makefile | 64 +++++++
arch/riscv/configs/freedom-u500_defconfig | 52 ++++++
arch/riscv/configs/spike32_defconfig | 50 +++++
arch/riscv/configs/spike64_defconfig | 46 +++++
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 +
12 files changed, 705 insertions(+), 1 deletion(-)
create mode 100644 arch/riscv/Kconfig
create mode 100644 arch/riscv/Makefile
create mode 100644 arch/riscv/configs/freedom-u500_defconfig
create mode 100644 arch/riscv/configs/spike32_defconfig
create mode 100644 arch/riscv/configs/spike64_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
diff --git a/Makefile b/Makefile
index 06ef9947cf7c..1a68b7b9b627 100644
--- a/Makefile
+++ b/Makefile
@@ -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
# ---------------------------------------------------------------------------
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
new file mode 100644
index 000000000000..366f5f2cf106
--- /dev/null
+++ b/arch/riscv/Kconfig
@@ -0,0 +1,294 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+config RISCV
+ def_bool y
+ select OF
+ select OF_EARLY_FLATTREE
+ select OF_IRQ
+ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+ select ARCH_WANT_FRAME_POINTERS
+ select CLONE_BACKWARDS
+ select COMMON_CLK
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CPU_DEVICES
+ select GENERIC_IRQ_SHOW
+ select GENERIC_PCI_IOMAP
+ select GENERIC_STRNCPY_FROM_USER
+ select GENERIC_STRNLEN_USER
+ select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_ATOMIC64 if !64BIT || !ISA_A
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select HAVE_MEMBLOCK
+ select HAVE_DMA_API_DEBUG
+ select HAVE_DMA_CONTIGUOUS
+ select HAVE_GENERIC_DMA_COHERENT
+ select IRQ_DOMAIN
+ select NO_BOOTMEM
+ select ISA_A if SMP
+ select SYSRISCV_ATOMIC if !ISA_A
+ select SPARSE_IRQ
+ select SYSCTL_EXCEPTION_TRACE
+ select HAVE_ARCH_TRACEHOOK
+ select MODULES_USE_ELF_RELA if MODULES
+ select THREAD_INFO_IN_TASK
+ select RISCV_IRQ_INTC
+ select RISCV_TIMER
+
+config MMU
+ def_bool y
+
+# even on 32-bit, physical (and DMA) addresses are > 32-bits
+config ARCH_PHYS_ADDR_T_64BIT
+ def_bool y
+
+config ARCH_DMA_ADDR_T_64BIT
+ def_bool y
+
+config STACKTRACE_SUPPORT
+ def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+ select GENERIC_BUG_RELATIVE_POINTERS if 64BIT
+
+config GENERIC_BUG_RELATIVE_POINTERS
+ bool
+
+config GENERIC_CALIBRATE_DELAY
+ def_bool y
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config PGTABLE_LEVELS
+ int
+ default 3 if 64BIT
+ default 2
+
+config HAVE_KPROBES
+ def_bool n
+
+config DMA_NOOP_OPS
+ def_bool y
+
+menu "Platform type"
+
+config SMP
+ bool "Symmetric Multi-Processing"
+ help
+ This enables support for systems with more than one CPU. If
+ you say N here, the kernel will run on single and
+ multiprocessor machines, but will use only one CPU of a
+ multiprocessor machine. If you say Y here, the kernel will run
+ on many, but not all, single processor machines. On a single
+ processor machine, the kernel will run faster if you say N
+ here.
+
+ If you don't know what to do here, say N.
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-32)"
+ range 2 32
+ depends on SMP
+ default "8"
+
+config CPU_SUPPORTS_32BIT_KERNEL
+ bool
+config CPU_SUPPORTS_64BIT_KERNEL
+ bool
+
+choice
+ prompt "Base ISA"
+ default ARCH_RV64I
+
+config ARCH_RV32I
+ bool "RV32I"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select 32BIT
+ select GENERIC_ASHLDI3
+ select GENERIC_ASHRDI3
+ select GENERIC_LSHRDI3
+
+config ARCH_RV64I
+ bool "RV64I"
+ select CPU_SUPPORTS_64BIT_KERNEL
+ select 64BIT
+
+endchoice
+
+choice
+ prompt "CPU Tuning"
+ default TUNE_GENERIC
+
+config TUNE_GENERIC
+ bool "generic"
+
+endchoice
+
+config ISA_C
+ bool "Emit compressed instructions when building Linux"
+ default n
+ help
+ Adds "C" to the ISA subsets that the toolchain is allowed to emit
+ when building Linux, which results in compressed instructions in the
+ Linux binary.
+
+ If you don't know what to do here, say Y.
+
+config ISA_A
+ bool "Emit atomic instructions when building Linux"
+ default y
+ help
+ Adds "A" to the ISA subsets that the toolchain is allowed to emit
+ when building Linux, which results in atomic instructions in the
+ Linux binary.
+
+ If you don't know what to do here, say Y.
+
+endmenu
+
+menu "Kernel type"
+
+choice
+ prompt "Kernel code model"
+ default 64BIT
+
+config 32BIT
+ bool "32-bit kernel"
+ depends on CPU_SUPPORTS_32BIT_KERNEL
+ help
+ Select this option to build a 32-bit kernel.
+
+config 64BIT
+ bool "64-bit kernel"
+ depends on CPU_SUPPORTS_64BIT_KERNEL
+ help
+ Select this option to build a 64-bit kernel.
+
+endchoice
+
+source "mm/Kconfig"
+
+source "kernel/Kconfig.preempt"
+
+source "kernel/Kconfig.hz"
+
+endmenu
+
+menu "Bus support"
+
+config PCI
+ bool "PCI support"
+ select PCI_MSI
+ help
+ This feature enables support for PCI bus system. If you say Y
+ here, the kernel will include drivers and infrastructure code
+ to support PCI bus devices.
+
+ If you don't know what to do here, say Y.
+
+config PCI_DOMAINS
+ def_bool PCI
+
+config PCI_DOMAINS_GENERIC
+ def_bool PCI
+
+source "drivers/pci/Kconfig"
+
+endmenu
+
+source "init/Kconfig"
+
+source "kernel/Kconfig.freezer"
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+menu "Power management options"
+
+source kernel/power/Kconfig
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+menu "Kernel hacking"
+
+config CMDLINE_BOOL
+ bool "Built-in kernel command line"
+ default n
+ help
+ For most platforms, it is firmware or second stage bootloader
+ that by default specifies the kernel command line options.
+ However, it might be necessary or advantageous to either override
+ the default kernel command line or add a few extra options to it.
+ For such cases, this option allows hardcoding command line options
+ directly into the kernel.
+
+ For that, choose 'Y' here and fill in the extra boot parameters
+ in CONFIG_CMDLINE.
+
+ The built-in options will be concatenated to the default command
+ line if CMDLINE_OVERRIDE is set to 'N'. Otherwise, the default
+ command line will be ignored and replaced by the built-in string.
+
+config CMDLINE
+ string "Built-in kernel command string"
+ depends on CMDLINE_BOOL
+ default ""
+ help
+ Supply command-line options at build time by entering them here.
+
+config CMDLINE_OVERRIDE
+ bool "Built-in command line overrides bootloader arguments"
+ default n
+ depends on CMDLINE_BOOL
+ help
+ Set this option to 'Y' to have the kernel ignore the bootloader
+ or firmware command line. Instead, the built-in command line
+ will be used exclusively.
+
+ If you don't know what to do here, say N.
+
+config EARLY_PRINTK
+ bool "Early printk"
+ default n
+ help
+ This option enables special console drivers which allow the kernel
+ to print messages very early in the bootup process.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. For normal operation
+ it is not recommended because it looks ugly and doesn't cooperate
+ with klogd/syslogd or the X server. You should normally N here,
+ unless you want to debug such a crash.
+
+
+source "lib/Kconfig.debug"
+
+config CMDLINE_BOOL
+ bool
+endmenu
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
new file mode 100644
index 000000000000..66c4a5e383f9
--- /dev/null
+++ b/arch/riscv/Makefile
@@ -0,0 +1,64 @@
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+LDFLAGS :=
+OBJCOPYFLAGS := -O binary
+LDFLAGS_vmlinux :=
+KBUILD_AFLAGS_MODULE += -fPIC
+KBUILD_CFLAGS_MODULE += -fPIC
+
+KBUILD_DEFCONFIG = spike64_defconfig
+
+export BITS
+ifeq ($(CONFIG_ARCH_RV64I),y)
+ BITS := 64
+ UTS_MACHINE := riscv64
+
+ KBUILD_CFLAGS += -mabi=lp64
+ KBUILD_AFLAGS += -mabi=lp64
+ KBUILD_MARCH = rv64im
+ LDFLAGS += -melf64lriscv
+else
+ BITS := 32
+ UTS_MACHINE := riscv32
+
+ KBUILD_CFLAGS += -mabi=ilp32
+ KBUILD_AFLAGS += -mabi=ilp32
+ KBUILD_MARCH = rv32im
+ LDFLAGS += -melf32lriscv
+endif
+
+KBUILD_CFLAGS += -Wall
+
+ifeq ($(CONFIG_ISA_A),y)
+ KBUILD_ARCH_A = a
+endif
+ifeq ($(CONFIG_ISA_C),y)
+ KBUILD_ARCH_C = c
+endif
+
+KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C)
+
+KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C)
+KBUILD_CFLAGS += -mno-save-restore
+
+# GCC versions that support the "-mstrict-align" option default to allowing
+# unaligned accesses. While unaligned accesses are explicitly allowed in the
+# RISC-V ISA, they're emulated by machine mode traps on all extant
+# architectures. It's faster to have GCC emit only aligned accesses.
+KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
+
+head-y := arch/riscv/kernel/head.o
+
+core-y += arch/riscv/kernel/ arch/riscv/mm/
+
+libs-y += arch/riscv/lib/
+
+all: vmlinux
diff --git a/arch/riscv/configs/freedom-u500_defconfig b/arch/riscv/configs/freedom-u500_defconfig
new file mode 100644
index 000000000000..b580dc5c8feb
--- /dev/null
+++ b/arch/riscv/configs/freedom-u500_defconfig
@@ -0,0 +1,52 @@
+CONFIG_DEFAULT_HOSTNAME="ucbvax"
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+# CONFIG_FHANDLE is not set
+CONFIG_NAMESPACES=y
+# CONFIG_SGETMASK_SYSCALL is not set
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_COMPACTION is not set
+CONFIG_HZ_100=y
+CONFIG_PCI_MSI=y
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_OF=y
+# CONFIG_BLK_DEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+# CONFIG_SYSFS is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_PRINTK_TIME=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_TTY=y
diff --git a/arch/riscv/configs/spike32_defconfig b/arch/riscv/configs/spike32_defconfig
new file mode 100644
index 000000000000..cf3431e94311
--- /dev/null
+++ b/arch/riscv/configs/spike32_defconfig
@@ -0,0 +1,50 @@
+CONFIG_64BIT=n
+CONFIG_32BIT=y
+CONFIG_ARCH_RV64I=n
+CONFIG_ARCH_RV32I=y
+CONFIG_PCI=y
+CONFIG_DEFAULT_HOSTNAME="ucbvax"
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+# CONFIG_FHANDLE is not set
+CONFIG_NAMESPACES=y
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+# CONFIG_SYSFS is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_TTY=y
diff --git a/arch/riscv/configs/spike64_defconfig b/arch/riscv/configs/spike64_defconfig
new file mode 100644
index 000000000000..5ad6644df541
--- /dev/null
+++ b/arch/riscv/configs/spike64_defconfig
@@ -0,0 +1,46 @@
+CONFIG_PCI=y
+CONFIG_DEFAULT_HOSTNAME="ucbvax"
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+# CONFIG_FHANDLE is not set
+CONFIG_NAMESPACES=y
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+# CONFIG_SYSFS is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_TTY=y
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
new file mode 100644
index 000000000000..18158be62a2b
--- /dev/null
+++ b/arch/riscv/include/asm/Kbuild
@@ -0,0 +1,61 @@
+generic-y += bugs.h
+generic-y += cacheflush.h
+generic-y += checksum.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += dma-contiguous.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += exec.h
+generic-y += fb.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += irq_work.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += kvm_para.h
+generic-y += local.h
+generic-y += mm-arch-hooks.h
+generic-y += mman.h
+generic-y += module.h
+generic-y += msgbuf.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += sembuf.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.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 += topology.h
+generic-y += trace_clock.h
+generic-y += types.h
+generic-y += unaligned.h
+generic-y += user.h
+generic-y += vga.h
+generic-y += vmlinux.lds.h
+generic-y += xor.h
diff --git a/arch/riscv/kernel/.gitignore b/arch/riscv/kernel/.gitignore
new file mode 100644
index 000000000000..b51634f6a7cd
--- /dev/null
+++ b/arch/riscv/kernel/.gitignore
@@ -0,0 +1 @@
+/vmlinux.lds
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
new file mode 100644
index 000000000000..ab8baf7bd142
--- /dev/null
+++ b/arch/riscv/kernel/Makefile
@@ -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:
diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..ece84991609c
--- /dev/null
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#define LOAD_OFFSET PAGE_OFFSET
+#include <asm/vmlinux.lds.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+jiffies = jiffies_64;
+
+SECTIONS
+{
+ /* Beginning of code and text segment */
+ . = LOAD_OFFSET;
+ _start = .;
+ __init_begin = .;
+ HEAD_TEXT_SECTION
+ INIT_TEXT_SECTION(PAGE_SIZE)
+ INIT_DATA_SECTION(16)
+ /* we have to discard exit text and such at runtime, not link time */
+ .exit.text :
+ {
+ EXIT_TEXT
+ }
+ .exit.data :
+ {
+ EXIT_DATA
+ }
+ PERCPU_SECTION(L1_CACHE_BYTES)
+ __init_end = .;
+
+ .text : {
+ _text = .;
+ _stext = .;
+ TEXT_TEXT
+ SCHED_TEXT
+ CPUIDLE_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ ENTRY_TEXT
+ IRQENTRY_TEXT
+ *(.fixup)
+ _etext = .;
+ }
+
+ /* Start of data section */
+ _sdata = .;
+ RO_DATA_SECTION(L1_CACHE_BYTES)
+ .srodata : {
+ *(.srodata*)
+ }
+
+ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
+ .sdata : {
+ __global_pointer$ = . + 0x800;
+ *(.sdata*)
+ /* End of data section */
+ _edata = .;
+ *(.sbss*)
+ }
+
+ BSS_SECTION(0, 0, 0)
+
+ EXCEPTION_TABLE(0x10)
+ NOTES
+
+ .rel.dyn : {
+ *(.rel.dyn*)
+ }
+
+ _end = .;
+
+ STABS_DEBUG
+ DWARF_DEBUG
+
+ DISCARDS
+}
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
new file mode 100644
index 000000000000..596c2ca40d63
--- /dev/null
+++ b/arch/riscv/lib/Makefile
@@ -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
diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile
new file mode 100644
index 000000000000..81f7d9ce6d88
--- /dev/null
+++ b/arch/riscv/mm/Makefile
@@ -0,0 +1,4 @@
+obj-y += init.o
+obj-y += fault.o
+obj-y += extable.o
+obj-y += ioremap.o
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2017-07-11 08:40 +0200 |
| Subject | Re: [PATCH 17/17] RISC-V: Build Infastructure |
| Message-ID | <u1WZX-7e0-15@gated-at.bofh.it> |
| In reply to | #1684723 |
Palmer Dabbelt <palmer@dabbelt.com> writes:
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> new file mode 100644
> index 000000000000..366f5f2cf106
> --- /dev/null
> +++ b/arch/riscv/Kconfig
> @@ -0,0 +1,294 @@
...
> +
> +config EARLY_PRINTK
> + bool "Early printk"
> + default n
> + help
> + This option enables special console drivers which allow the kernel
> + to print messages very early in the bootup process.
> +
> + This is useful for kernel debugging when your machine crashes very
> + early before the console code is initialized. For normal operation
> + it is not recommended because it looks ugly and doesn't cooperate
> + with klogd/syslogd or the X server. You should normally N here,
> + unless you want to debug such a crash.
Looks like you copied this text from x86? I think the comment about it
being ugly refers to the VGA early console which you don't have, so
that's not really accurate.
And the part about it not cooperating with klogs/syslogd is true, early
printk output doesn't go to syslog. But if you turn EARLY_PRINTK off
then early printk output goes nowhere at all:
#ifdef CONFIG_EARLY_PRINTK
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);
#else
static inline __printf(1, 2) __cold
void early_printk(const char *s, ...) { }
#endif
So if you have a functional early console (which I think you do) then
you might be better off just making this def_bool y.
cheers
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 18:30 +0200 |
| Subject | Re: [PATCH 17/17] RISC-V: Build Infastructure |
| Message-ID | <u26cV-4Ed-15@gated-at.bofh.it> |
| In reply to | #1684803 |
On Mon, 10 Jul 2017 23:31:18 PDT (-0700), mpe@ellerman.id.au wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
>> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
>> new file mode 100644
>> index 000000000000..366f5f2cf106
>> --- /dev/null
>> +++ b/arch/riscv/Kconfig
>> @@ -0,0 +1,294 @@
> ...
>> +
>> +config EARLY_PRINTK
>> + bool "Early printk"
>> + default n
>> + help
>> + This option enables special console drivers which allow the kernel
>> + to print messages very early in the bootup process.
>> +
>> + This is useful for kernel debugging when your machine crashes very
>> + early before the console code is initialized. For normal operation
>> + it is not recommended because it looks ugly and doesn't cooperate
>> + with klogd/syslogd or the X server. You should normally N here,
>> + unless you want to debug such a crash.
>
> Looks like you copied this text from x86? I think the comment about it
> being ugly refers to the VGA early console which you don't have, so
> that's not really accurate.
>
> And the part about it not cooperating with klogs/syslogd is true, early
> printk output doesn't go to syslog. But if you turn EARLY_PRINTK off
> then early printk output goes nowhere at all:
>
> #ifdef CONFIG_EARLY_PRINTK
> extern asmlinkage __printf(1, 2)
> void early_printk(const char *fmt, ...);
> #else
> static inline __printf(1, 2) __cold
> void early_printk(const char *s, ...) { }
> #endif
>
>
> So if you have a functional early console (which I think you do) then
> you might be better off just making this def_bool y.
I think that's best. The SBI's EARLY_PRINTK support is quite clean, so I don't
see any reason to disable it. How does this look?
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 366f5f2cf106..cc274bbc29a7 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -268,18 +268,7 @@ config CMDLINE_OVERRIDE
If you don't know what to do here, say N.
config EARLY_PRINTK
- bool "Early printk"
- default n
- help
- This option enables special console drivers which allow the kernel
- to print messages very early in the bootup process.
-
- This is useful for kernel debugging when your machine crashes very
- early before the console code is initialized. For normal operation
- it is not recommended because it looks ugly and doesn't cooperate
- with klogd/syslogd or the X server. You should normally N here,
- unless you want to debug such a crash.
-
+ def_bool y
source "lib/Kconfig.debug"
[toc] | [prev] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2017-07-12 12:50 +0200 |
| Subject | Re: [PATCH 17/17] RISC-V: Build Infastructure |
| Message-ID | <u2nnr-76E-1@gated-at.bofh.it> |
| In reply to | #1685195 |
Palmer Dabbelt <palmer@dabbelt.com> writes: > On Mon, 10 Jul 2017 23:31:18 PDT (-0700), mpe@ellerman.id.au wrote: ... >> So if you have a functional early console (which I think you do) then >> you might be better off just making this def_bool y. > > I think that's best. The SBI's EARLY_PRINTK support is quite clean, so I don't > see any reason to disable it. How does this look? LGTM. cheers > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > index 366f5f2cf106..cc274bbc29a7 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -268,18 +268,7 @@ config CMDLINE_OVERRIDE > If you don't know what to do here, say N. > > config EARLY_PRINTK > - bool "Early printk" > - default n > - help > - This option enables special console drivers which allow the kernel > - to print messages very early in the bootup process. > - > - This is useful for kernel debugging when your machine crashes very > - early before the console code is initialized. For normal operation > - it is not recommended because it looks ugly and doesn't cooperate > - with klogd/syslogd or the X server. You should normally N here, > - unless you want to debug such a crash. > - > + def_bool y > > source "lib/Kconfig.debug"
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 06/17] irqchip: RISC-V Local Interrupt Controller Driver |
| Message-ID | <u1SD1-4hH-13@gated-at.bofh.it> |
| In reply to | #1684722 |
This patch adds a driver that manages the local interrupts on each
RISC-V hart, as specifiec by the RISC-V supervisor level ISA manual.
The local interrupt controller manages software interrupts, timer
interrupts, and hardware interrupts (which are routed via the
platform level interrupt controller). Per-hart local interrupt
controllers are found on all RISC-V systems.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
drivers/irqchip/Kconfig | 14 +++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-riscv-intc.c | 213 +++++++++++++++++++++++++++++++++++++++
3 files changed, 228 insertions(+)
create mode 100644 drivers/irqchip/irq-riscv-intc.c
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index f1fd5f44d1d4..7923d3fa8fae 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -306,3 +306,17 @@ config QCOM_IRQ_COMBINER
help
Say yes here to add support for the IRQ combiner devices embedded
in Qualcomm Technologies chips.
+
+config RISCV_INTC
+ def_bool y if RISCV
+ #bool "RISC-V Interrupt Controller"
+ depends on RISCV
+ default y
+ help
+ This enables support for the local interrupt controller found in
+ standard RISC-V systems. The local interrupt controller handles
+ timer interrupts, software interrupts, and hardware interrupts.
+ Without a local interrupt controller the system will be unable to
+ handle any interrupts, including those passed via the PLIC.
+
+ If you don't know what to do here, say Y.
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e88d856cc09c..b1aa9114afc4 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
+obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
new file mode 100644
index 000000000000..96ae020cf1d5
--- /dev/null
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -0,0 +1,213 @@
+/*
+ * 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/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/ftrace.h>
+#include <linux/of.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptrace.h>
+#include <asm/sbi.h>
+#include <asm/smp.h>
+
+struct riscv_irq_data {
+ struct irq_chip chip;
+ struct irq_domain *domain;
+ int hart;
+ char name[20];
+};
+DEFINE_PER_CPU(struct riscv_irq_data, riscv_irq_data);
+
+static void riscv_software_interrupt(void)
+{
+#ifdef CONFIG_SMP
+ irqreturn_t ret;
+
+ ret = handle_ipi();
+
+ WARN_ON(ret == IRQ_NONE);
+#else
+ /*
+ * We currently only use software interrupts to pass inter-processor
+ * interrupts, so if a non-SMP system gets a software interrupt then we
+ * don't know what to do.
+ */
+ pr_warning("Software Interrupt without CONFIG_SMP\n");
+#endif
+}
+
+asmlinkage void __irq_entry do_IRQ(unsigned int cause, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ struct irq_domain *domain;
+
+ irq_enter();
+
+ /*
+ * There are three classes of interrupt: timer, software, and
+ * external devices. We dispatch between them here. External
+ * device interrupts use the generic IRQ mechanisms.
+ */
+ switch (cause) {
+ case INTERRUPT_CAUSE_TIMER:
+ riscv_timer_interrupt();
+ break;
+ case INTERRUPT_CAUSE_SOFTWARE:
+ riscv_software_interrupt();
+ break;
+ default:
+ domain = per_cpu(riscv_irq_data, smp_processor_id()).domain;
+ generic_handle_irq(irq_find_mapping(domain, cause));
+ break;
+ }
+
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+static int riscv_irqdomain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct riscv_irq_data *data = d->host_data;
+
+ irq_set_chip_and_handler(irq, &data->chip, handle_simple_irq);
+ irq_set_chip_data(irq, data);
+ irq_set_noprobe(irq);
+ irq_set_affinity(irq, cpumask_of(data->hart));
+
+ return 0;
+}
+
+static const struct irq_domain_ops riscv_irqdomain_ops = {
+ .map = riscv_irqdomain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+/*
+ * On RISC-V systems local interrupts are masked or unmasked by writing the SIE
+ * (Supervisor Interrupt Enable) CSR. As CSRs can only be written on the local
+ * hart, these functions can only be called on the hart that corresponds to the
+ * IRQ chip. They are only called internally to this module, so they BUG_ON if
+ * this condition is violated rather than attempting to handle the error by
+ * forwarding to the target hart, as that's already expected to have been done.
+ */
+static void riscv_irq_mask(struct irq_data *d)
+{
+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
+
+ BUG_ON(smp_processor_id() != data->hart);
+ csr_clear(sie, 1 << (long)d->hwirq);
+}
+
+static void riscv_irq_unmask(struct irq_data *d)
+{
+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
+
+ BUG_ON(smp_processor_id() != data->hart);
+ csr_set(sie, 1 << (long)d->hwirq);
+}
+
+/* Callbacks for twiddling SIE on another hart. */
+static void riscv_irq_enable_helper(void *d)
+{
+ riscv_irq_unmask(d);
+}
+
+static void riscv_irq_disable_helper(void *d)
+{
+ riscv_irq_mask(d);
+}
+
+static void riscv_irq_enable(struct irq_data *d)
+{
+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
+
+ /*
+ * It's only possible to write SIE on the current hart. This jumps
+ * over to the target hart if it's not the current one. It's invalid
+ * to write SIE on a hart that's not currently running.
+ */
+ if (data->hart == smp_processor_id())
+ riscv_irq_unmask(d);
+ else if (cpu_online(data->hart))
+ smp_call_function_single(data->hart,
+ riscv_irq_enable_helper,
+ d,
+ true);
+ else
+ WARN_ON_ONCE(1);
+}
+
+static void riscv_irq_disable(struct irq_data *d)
+{
+ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
+
+ /*
+ * It's only possible to write SIE on the current hart. This jumps
+ * over to the target hart if it's not the current one. It's invalid
+ * to write SIE on a hart that's not currently running.
+ */
+ if (data->hart == smp_processor_id())
+ riscv_irq_mask(d);
+ else if (cpu_online(data->hart))
+ smp_call_function_single(data->hart,
+ riscv_irq_disable_helper,
+ d,
+ true);
+ else
+ WARN_ON_ONCE(1);
+}
+
+static int riscv_intc_init(struct device_node *node, struct device_node *parent)
+{
+ int hart;
+ struct riscv_irq_data *data;
+
+ if (parent)
+ return 0;
+
+ hart = riscv_of_processor_hart(node->parent);
+ if (hart < 0)
+ return -EIO;
+
+ data = &per_cpu(riscv_irq_data, hart);
+ snprintf(data->name, sizeof(data->name), "riscv,cpu_intc,%d", hart);
+ data->hart = hart;
+ data->chip.name = data->name;
+ data->chip.irq_mask = riscv_irq_mask;
+ data->chip.irq_unmask = riscv_irq_unmask;
+ data->chip.irq_enable = riscv_irq_enable;
+ data->chip.irq_disable = riscv_irq_disable;
+ data->domain = irq_domain_add_linear(
+ node,
+ 8*sizeof(uintptr_t),
+ &riscv_irqdomain_ops,
+ data);
+ if (!data->domain)
+ goto error_add_linear;
+ pr_info("%s: %d local interrupts mapped\n",
+ data->name, 8*(int)sizeof(uintptr_t));
+ return 0;
+
+error_add_linear:
+ pr_warning("%s: unable to add IRQ domain\n",
+ data->name);
+ return -(ENXIO);
+
+}
+
+IRQCHIP_DECLARE(riscv, "riscv,cpu-intc", riscv_intc_init);
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 07/17] irqchip: New RISC-V PLIC Driver |
| Message-ID | <u1SD1-4hH-15@gated-at.bofh.it> |
| In reply to | #1684722 |
This patch adds a driver for the Platform Level Interrupt Controller
(PLIC) specified as part of the RISC-V supervisor level ISA manual.
The PLIC connocts global interrupt sources to the local interrupt
controller on each hart. A PLIC is present on all RISC-V systems.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
drivers/irqchip/Kconfig | 13 ++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-riscv-plic.c | 370 +++++++++++++++++++++++++++++++++++++++
3 files changed, 384 insertions(+)
create mode 100644 drivers/irqchip/irq-riscv-plic.c
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7923d3fa8fae..ae5e27f090ec 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -307,6 +307,19 @@ config QCOM_IRQ_COMBINER
Say yes here to add support for the IRQ combiner devices embedded
in Qualcomm Technologies chips.
+config RISCV_PLIC
+ bool "Platform-Level Interrupt Controller"
+ depends on RISCV
+ default y
+ help
+ This enables support for the PLIC chip found in standard RISC-V
+ systems. The PLIC controls devices interrupts and connects them to
+ each core's local interrupt controller. Aside from timer and
+ software interrupts, all other interrupt sources (MSI, GPIO, etc)
+ are subordinate to the PLIC.
+
+ If you don't know what to do here, say Y.
+
config RISCV_INTC
def_bool y if RISCV
#bool "RISC-V Interrupt Controller"
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index b1aa9114afc4..7880c9cec40e 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -78,4 +78,5 @@ obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
+obj-$(CONFIG_RISCV_PLIC) += irq-riscv-plic.o
obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
diff --git a/drivers/irqchip/irq-riscv-plic.c b/drivers/irqchip/irq-riscv-plic.c
new file mode 100644
index 000000000000..e326f239eea7
--- /dev/null
+++ b/drivers/irqchip/irq-riscv-plic.c
@@ -0,0 +1,370 @@
+/*
+ * 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/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+/*
+ * From the RISC-V Privlidged Spec v1.10:
+ *
+ * Global interrupt sources are assigned small unsigned integer identifiers,
+ * beginning at the value 1. An interrupt ID of 0 is reserved to mean “no
+ * interrupt”. Interrupt identifiers are also used to break ties when two or
+ * more interrupt sources have the same assigned priority. Smaller values of
+ * interrupt ID take precedence over larger values of interrupt ID.
+ *
+ * While the RISC-V supervisor spec doesn't define the maximum number of
+ * devices supported by the PLIC, the largest number supported by devices
+ * marked as 'riscv,plic0' (which is the only device type this driver supports,
+ * and is the only extant PLIC as of now) is 1024. As mentioned above, device
+ * 0 is defined to be non-existant so this device really only supports 1023
+ * devices.
+ */
+#define MAX_DEVICES 1024
+#define MAX_CONTEXTS 15872
+
+/*
+ * The PLIC consists of memory-mapped control registers, with a memory map as
+ * follows:
+ *
+ * base + 0x000000: Reserved (interrupt source 0 does not exist)
+ * base + 0x000004: Interrupt source 1 priority
+ * base + 0x000008: Interrupt source 2 priority
+ * ...
+ * base + 0x000FFC: Interrupt source 1023 priority
+ * base + 0x001000: Pending 0
+ * base + 0x001FFF: Pending
+ * base + 0x002000: Enable bits for sources 0-31 on context 0
+ * base + 0x002004: Enable bits for sources 32-63 on context 0
+ * ...
+ * base + 0x0020FC: Enable bits for sources 992-1023 on context 0
+ * base + 0x002080: Enable bits for sources 0-31 on context 1
+ * ...
+ * base + 0x002100: Enable bits for sources 0-31 on context 2
+ * ...
+ * base + 0x1F1F80: Enable bits for sources 992-1023 on context 15871
+ * base + 0x1F1F84: Reserved
+ * ... (higher context IDs would fit here, but wouldn't fit
+ * inside the per-context priority vector)
+ * base + 0x1FFFFC: Reserved
+ * base + 0x200000: Priority threshold for context 0
+ * base + 0x200004: Claim/complete for context 0
+ * base + 0x200008: Reserved
+ * ...
+ * base + 0x200FFC: Reserved
+ * base + 0x201000: Priority threshold for context 1
+ * base + 0x201004: Claim/complete for context 1
+ * ...
+ * base + 0xFFE000: Priority threshold for context 15871
+ * base + 0xFFE004: Claim/complete for context 15871
+ * base + 0xFFF008: Reserved
+ * ...
+ * base + 0xFFFFFC: Reserved
+ */
+
+/* Each interrupt source has a priority register associated with it. */
+#define PRIORITY_BASE 0
+#define PRIORITY_PER_ID 4
+
+/*
+ * Each hart context has a vector of interupt enable bits associated with it.
+ * There's one bit for each interrupt source. */
+#define ENABLE_BASE 0x2000
+#define ENABLE_PER_HART 0x80
+
+/*
+ * Each hart context has a set of control registers associated with it. Right
+ * now there's only two: a source priority threshold over which the hart will
+ * take an interrupt, and a register to claim interrupts.
+ */
+#define CONTEXT_BASE 0x200000
+#define CONTEXT_PER_HART 0x1000
+#define CONTEXT_THRESHOLD 0
+#define CONTEXT_CLAIM 4
+
+/*
+ * PLIC devices are named like 'riscv,plic0,%llx', this is enough space to
+ * store that name.
+ */
+#define PLIC_DATA_NAME_SIZE 30
+
+struct plic_handler {
+ bool present;
+ int contextid;
+ struct plic_data *data;
+};
+
+struct plic_data {
+ struct irq_chip chip;
+ struct irq_domain *domain;
+ u32 ndev;
+ void __iomem *reg;
+ int handlers;
+ struct plic_handler *handler;
+ char name[PLIC_DATA_NAME_SIZE];
+ spinlock_t lock;
+};
+
+/* Addressing helper functions. */
+static inline
+void __iomem *plic_enable_vector(struct plic_data *data, int contextid)
+{
+ return data->reg + ENABLE_BASE + contextid * ENABLE_PER_HART;
+}
+
+static inline
+void __iomem *plic_priority(struct plic_data *data, int hwirq)
+{
+ return data->reg + PRIORITY_BASE + hwirq * PRIORITY_PER_ID;
+}
+
+static inline
+void __iomem *plic_hart_threshold(struct plic_data *data, int contextid)
+{
+ return data->reg + CONTEXT_BASE + CONTEXT_PER_HART * contextid + CONTEXT_THRESHOLD;
+}
+
+static inline
+void __iomem *plic_hart_claim(struct plic_data *data, int contextid)
+{
+ return data->reg + CONTEXT_BASE + CONTEXT_PER_HART * contextid + CONTEXT_CLAIM;
+}
+
+/*
+ * Handling an interrupt is a two-step process: first you claim the interrupt
+ * by reading the claim register, then you complete the interrupt by writing
+ * that source ID back to the same claim register. This automatically enables
+ * and disables the interrupt, so there's nothing else to do.
+ */
+static inline
+u32 plic_claim(struct plic_data *data, int contextid)
+{
+ return readl(plic_hart_claim(data, contextid));
+}
+
+static inline
+void plic_complete(struct plic_data *data, int contextid, u32 claim)
+{
+ writel(claim, plic_hart_claim(data, contextid));
+}
+
+/* Explicit interrupt masking. */
+static void plic_disable(struct plic_data *data, int contextid, int hwirq)
+{
+ void __iomem *reg = plic_enable_vector(data, contextid) + (hwirq / 32);
+ u32 mask = ~(1 << (hwirq % 32));
+
+ spin_lock(&data->lock);
+ writel(readl(reg) & mask, reg);
+ spin_unlock(&data->lock);
+}
+
+static void plic_enable(struct plic_data *data, int contextid, int hwirq)
+{
+ void __iomem *reg = plic_enable_vector(data, contextid) + (hwirq / 32);
+ u32 bit = 1 << (hwirq % 32);
+
+ spin_lock(&data->lock);
+ writel(readl(reg) | bit, reg);
+ spin_unlock(&data->lock);
+}
+
+/*
+ * There is no need to mask/unmask PLIC interrupts
+ * They are "masked" by reading claim and "unmasked" when writing it back.
+ */
+static void plic_irq_mask(struct irq_data *d) { }
+static void plic_irq_unmask(struct irq_data *d) { }
+
+static void plic_irq_enable(struct irq_data *d)
+{
+ struct plic_data *data = irq_data_get_irq_chip_data(d);
+ void __iomem *priority = plic_priority(data, d->hwirq);
+ int i;
+
+ writel(1, priority);
+ for (i = 0; i < data->handlers; ++i)
+ if (data->handler[i].present)
+ plic_enable(data, i, d->hwirq);
+}
+
+static void plic_irq_disable(struct irq_data *d)
+{
+ struct plic_data *data = irq_data_get_irq_chip_data(d);
+ void __iomem *priority = plic_priority(data, d->hwirq);
+ int i;
+
+ writel(0, priority);
+ for (i = 0; i < data->handlers; ++i)
+ if (data->handler[i].present)
+ plic_disable(data, i, d->hwirq);
+}
+
+static void plic_irq_eoi(struct irq_data *d)
+{
+ struct plic_handler *handler = d->common->handler_data;
+ plic_complete(handler->data, handler->contextid, d->hwirq);
+}
+
+static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct plic_data *data = d->host_data;
+
+ irq_set_chip_and_handler(irq, &data->chip, handle_fasteoi_irq);
+ irq_set_chip_data(irq, data);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops plic_irqdomain_ops = {
+ .map = plic_irqdomain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static void plic_chained_handle_irq(struct irq_desc *desc)
+{
+ struct plic_handler *handler = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_domain *domain = handler->data->domain;
+ u32 what;
+
+ chained_irq_enter(chip, desc);
+
+ while ((what = plic_claim(handler->data, handler->contextid))) {
+ int irq = irq_find_mapping(domain, what);
+
+ if (irq > 0)
+ generic_handle_irq(irq);
+ else
+ handle_bad_irq(desc);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static int plic_init(struct device_node *node, struct device_node *parent)
+{
+ struct plic_data *data;
+ struct resource resource;
+ int i, ok = 0;
+ int out = -1;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (WARN_ON(!data))
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ data->reg = of_iomap(node, 0);
+ if (WARN_ON(!data->reg)) {
+ out = -EIO;
+ goto free_data;
+ }
+
+ of_property_read_u32(node, "riscv,ndev", &data->ndev);
+ if (WARN_ON(!data->ndev)) {
+ out = -EINVAL;
+ goto free_reg;
+ }
+
+ data->handlers = of_irq_count(node);
+ if (WARN_ON(!data->handlers)) {
+ out = -EINVAL;
+ goto free_reg;
+ }
+
+ data->handler =
+ kcalloc(data->handlers, sizeof(*data->handler), GFP_KERNEL);
+ if (WARN_ON(!data->handler)) {
+ out = -ENOMEM;
+ goto free_reg;
+ }
+
+ data->domain = irq_domain_add_linear(node, data->ndev+1, &plic_irqdomain_ops, data);
+ if (WARN_ON(!data->domain)) {
+ out = -ENOMEM;
+ goto free_handler;
+ }
+
+ of_address_to_resource(node, 0, &resource);
+ snprintf(data->name, sizeof(data->name),
+ "riscv,plic0,%llx", resource.start);
+ data->chip.name = data->name;
+ data->chip.irq_mask = plic_irq_mask;
+ data->chip.irq_unmask = plic_irq_unmask;
+ data->chip.irq_enable = plic_irq_enable;
+ data->chip.irq_disable = plic_irq_disable;
+ data->chip.irq_eoi = plic_irq_eoi;
+
+ for (i = 0; i < data->handlers; ++i) {
+ struct plic_handler *handler = &data->handler[i];
+ struct of_phandle_args parent;
+ int parent_irq, hwirq;
+
+ handler->present = false;
+
+ if (of_irq_parse_one(node, i, &parent))
+ continue;
+ /* skip context holes */
+ if (parent.args[0] == -1)
+ continue;
+
+ /* skip any contexts that lead to inactive harts */
+ if (of_device_is_compatible(parent.np, "riscv,cpu-intc") &&
+ parent.np->parent &&
+ riscv_of_processor_hart(parent.np->parent) < 0)
+ continue;
+
+ parent_irq = irq_create_of_mapping(&parent);
+ if (!parent_irq)
+ continue;
+
+ handler->present = true;
+ handler->contextid = i;
+ handler->data = data;
+ /* hwirq prio must be > this to trigger an interrupt */
+ writel(0, plic_hart_threshold(data, i));
+
+ for (hwirq = 1; hwirq <= data->ndev; ++hwirq)
+ plic_disable(data, i, hwirq);
+ irq_set_chained_handler_and_data(parent_irq, plic_chained_handle_irq, handler);
+ ++ok;
+ }
+
+ pr_info("%s: mapped %d interrupts to %d/%d handlers\n",
+ data->name, data->ndev, ok, data->handlers);
+ WARN_ON(!ok);
+ return 0;
+
+free_handler:
+ kfree(data->handler);
+free_reg:
+ iounmap(data->reg);
+free_data:
+ kfree(data);
+ return out;
+}
+
+IRQCHIP_DECLARE(plic0, "riscv,plic0", plic_init);
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 02/17] pci: Add a generic, weakly-linked pcibios_align_resource |
| Message-ID | <u1SD1-4hH-17@gated-at.bofh.it> |
| In reply to | #1684722 |
Multiple architectures define this as trivial function, and I'm adding
another one as part of the RISC-V port. This adds a __weak version of
pcibios_align_resource and deletes the now obselete ones in a handful of
ports.
The only functional change should be that a handful of ports used to
export pcibios_fixup_bus. Only some architectures export this, so I
just dropped it.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
arch/arc/kernel/pcibios.c | 13 -------------
arch/arm64/kernel/pci.c | 17 -----------------
arch/ia64/pci/pci.c | 7 -------
arch/microblaze/pci/pci-common.c | 7 -------
arch/sparc/kernel/leon_pci.c | 6 ------
arch/sparc/kernel/pci.c | 10 ----------
arch/sparc/kernel/pcic.c | 6 ------
arch/tile/kernel/pci.c | 10 ----------
arch/tile/kernel/pci_gx.c | 9 ---------
drivers/pci/setup-res.c | 12 ++++++++++++
10 files changed, 12 insertions(+), 85 deletions(-)
diff --git a/arch/arc/kernel/pcibios.c b/arch/arc/kernel/pcibios.c
index 72e1d73d0bd6..05aba5a7b5d2 100644
--- a/arch/arc/kernel/pcibios.c
+++ b/arch/arc/kernel/pcibios.c
@@ -7,16 +7,3 @@
*/
#include <linux/pci.h>
-
-/*
- * We don't have to worry about legacy ISA devices, so nothing to do here
- */
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-
-void pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index e2b7e4f9cc31..0e2ea1c78542 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -22,23 +22,6 @@
#include <linux/pci-ecam.h>
#include <linux/slab.h>
-/*
- * Called after each bus is probed, but before its children are examined
- */
-void pcibios_fixup_bus(struct pci_bus *bus)
-{
- /* nothing to do, expected to be removed in the future */
-}
-
-/*
- * We don't have to worry about legacy ISA devices, so nothing to do here
- */
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-
#ifdef CONFIG_ACPI
/*
* Try to assign the IRQ number when probing a new device
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 4068bde623dc..f5ec736100ee 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -411,13 +411,6 @@ pcibios_disable_device (struct pci_dev *dev)
acpi_pci_irq_disable(dev);
}
-resource_size_t
-pcibios_align_resource (void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-
/**
* ia64_pci_get_legacy_mem - generic legacy mem routine
* @bus: bus to get legacy memory base address for
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 404fb38d06b7..7a332e9f1de0 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -829,13 +829,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
* but we want to try to avoid allocating at 0x2900-0x2bff
* which might have be mirrored at 0x0100-0x03ff..
*/
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-EXPORT_SYMBOL(pcibios_align_resource);
-
int pcibios_add_device(struct pci_dev *dev)
{
dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 4371f72ff025..0eafdf3d036d 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -94,9 +94,3 @@ void pcibios_fixup_bus(struct pci_bus *pbus)
}
}
}
-
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 7eceaa10836f..3f8670c92951 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -690,16 +690,6 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
return bus;
}
-void pcibios_fixup_bus(struct pci_bus *pbus)
-{
-}
-
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
u16 cmd, oldcmd;
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index a38787b84322..e038e343f2c1 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -746,12 +746,6 @@ static void watchdog_reset() {
}
#endif
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-
int pcibios_enable_device(struct pci_dev *pdev, int mask)
{
return 0;
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index bc6656b5708b..284ed23b3914 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -67,16 +67,6 @@ static struct pci_ops tile_cfg_ops;
/*
- * We don't need to worry about the alignment of resources.
- */
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- return res->start;
-}
-EXPORT_SYMBOL(pcibios_align_resource);
-
-/*
* Open a FD to the hypervisor PCI device.
*
* controller_id is the controller number, config type is 0 or 1 for
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index b554a68eea1b..bdc623b91f7a 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -108,15 +108,6 @@ static struct pci_ops tile_cfg_ops;
/* Mask of CPUs that should receive PCIe interrupts. */
static struct cpumask intr_cpus_map;
-/* We don't need to worry about the alignment of resources. */
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size,
- resource_size_t align)
-{
- return res->start;
-}
-EXPORT_SYMBOL(pcibios_align_resource);
-
/*
* Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #.
* For now, we simply send interrupts to non-dataplane CPUs.
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 85774b7a316a..597ed1f8b15c 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -234,6 +234,18 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
return 0;
}
+/*
+ * We don't have to worry about legacy ISA devices, so nothing to do here.
+ * This is marked as __weak because multiple architectures define it, it should
+ * eventually go away.
+ */
+__attribute__ ((weak))
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ resource_size_t size, resource_size_t align)
+{
+ return res->start;
+}
+
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
int resno, resource_size_t size, resource_size_t align)
{
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u1SD1-4hH-25@gated-at.bofh.it> |
| In reply to | #1684722 |
The RISC-V ISA defines a simple console that is availiable via SBI calls
on all systems. This patch adds a driver for this console interface
that can act as both a target for early printk and as the system
console.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
drivers/tty/hvc/Kconfig | 11 +++++
drivers/tty/hvc/Makefile | 1 +
drivers/tty/hvc/hvc_sbi.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+)
create mode 100644 drivers/tty/hvc/hvc_sbi.c
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index b8d5ea0ae26b..24cbaaf47d8d 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -97,6 +97,17 @@ config HVC_BFIN_JTAG
the HVC driver. If you don't have JTAG, then you probably don't
want this option.
+config HVC_SBI
+ bool "SBI console support"
+ depends on RISCV
+ select HVC_DRIVER
+ default y
+ help
+ This enables support for console output via RISC-V SBI calls, which
+ is normally used only during boot to output printk.
+
+ If you don't know what do to here, say Y.
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES && HVC_CONSOLE
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
index 6a2702be76d1..2d63bfe4a96b 100644
--- a/drivers/tty/hvc/Makefile
+++ b/drivers/tty/hvc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o
obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
obj-$(CONFIG_HVC_BFIN_JTAG) += hvc_bfin_jtag.o
obj-$(CONFIG_HVCS) += hvcs.o
+obj-$(CONFIG_HVC_SBI) += hvc_sbi.o
diff --git a/drivers/tty/hvc/hvc_sbi.c b/drivers/tty/hvc/hvc_sbi.c
new file mode 100644
index 000000000000..98114cbd85f1
--- /dev/null
+++ b/drivers/tty/hvc/hvc_sbi.c
@@ -0,0 +1,103 @@
+/*
+ * RISC-V SBI interface to hvc_console.c
+ * based on drivers-tty/hvc/hvc_udbg.c
+ *
+ * Copyright (C) 2008 David Gibson, IBM Corporation
+ * 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+
+#include <asm/sbi.h>
+
+#include "hvc_console.h"
+
+static int hvc_sbi_tty_put(uint32_t vtermno, const char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ sbi_console_putchar(buf[i]);
+
+ return i;
+}
+
+static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count)
+{
+ int i, c;
+
+ for (i = 0; i < count; i++) {
+ if ((c = sbi_console_getchar()) < 0)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static const struct hv_ops hvc_sbi_ops = {
+ .get_chars = hvc_sbi_tty_get,
+ .put_chars = hvc_sbi_tty_put,
+};
+
+static int __init hvc_sbi_init(void)
+{
+ return PTR_ERR_OR_ZERO(hvc_alloc(0, 0, &hvc_sbi_ops, 16));
+}
+device_initcall(hvc_sbi_init);
+
+static int __init hvc_sbi_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_sbi_ops);
+ add_preferred_console("hvc", 0, NULL);
+
+ return 0;
+}
+console_initcall(hvc_sbi_console_init);
+
+#ifdef CONFIG_EARLY_PRINTK
+static void sbi_console_write(struct console *co, const char *buf,
+ unsigned int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ if (buf[i] == '\n')
+ sbi_console_putchar('\r');
+ sbi_console_putchar(buf[i]);
+ }
+}
+
+static struct console early_console_dev __initdata = {
+ .name = "early",
+ .write = sbi_console_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1
+};
+
+static int __init setup_early_printk(char *str)
+{
+ if (early_console == NULL) {
+ early_console = &early_console_dev;
+ register_console(early_console);
+ }
+ return 0;
+}
+early_param("earlyprintk", setup_early_printk);
+#endif
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2017-07-11 08:30 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u1WQh-7b3-3@gated-at.bofh.it> |
| In reply to | #1684728 |
Palmer Dabbelt <palmer@dabbelt.com> writes:
>
...
> +#ifdef CONFIG_EARLY_PRINTK
> +static void sbi_console_write(struct console *co, const char *buf,
> + unsigned int n)
> +{
> + int i;
> +
> + for (i = 0; i < n; ++i) {
> + if (buf[i] == '\n')
> + sbi_console_putchar('\r');
> + sbi_console_putchar(buf[i]);
> + }
> +}
> +
> +static struct console early_console_dev __initdata = {
> + .name = "early",
> + .write = sbi_console_write,
> + .flags = CON_PRINTBUFFER | CON_BOOT,
AFAICS you could add CON_ANYTIME here, which would mean this console
would print output before the CPU is online.
I think it doesn't currently matter because you call parse_early_param()
from setup_arch(), at which point the boot CPU has been marked online.
But if this console can actually work earlier then you might be better
off just registering it unconditionally very early.
cheers
> +static int __init setup_early_printk(char *str)
> +{
> + if (early_console == NULL) {
> + early_console = &early_console_dev;
> + register_console(early_console);
> + }
> + return 0;
> +}
> +early_param("earlyprintk", setup_early_printk);
> +#endif
> --
> 2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 18:30 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u26cV-4Ed-13@gated-at.bofh.it> |
| In reply to | #1684799 |
On Mon, 10 Jul 2017 23:21:07 PDT (-0700), mpe@ellerman.id.au wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>>
> ...
>> +#ifdef CONFIG_EARLY_PRINTK
>> +static void sbi_console_write(struct console *co, const char *buf,
>> + unsigned int n)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < n; ++i) {
>> + if (buf[i] == '\n')
>> + sbi_console_putchar('\r');
>> + sbi_console_putchar(buf[i]);
>> + }
>> +}
>> +
>> +static struct console early_console_dev __initdata = {
>> + .name = "early",
>> + .write = sbi_console_write,
>> + .flags = CON_PRINTBUFFER | CON_BOOT,
>
> AFAICS you could add CON_ANYTIME here, which would mean this console
> would print output before the CPU is online.
>
> I think it doesn't currently matter because you call parse_early_param()
> from setup_arch(), at which point the boot CPU has been marked online.
>
> But if this console can actually work earlier then you might be better
> off just registering it unconditionally very early.
That seems like a good idea. I'm not familiar with how all this works, but
from my understanding of this early_initcall() should be sufficient to make
this work? The only other driver that sets CON_ANYTIME and supports
EARLY_PRINTK is hvc_xen, but that installs a header to let init code register
the console directly. The early_initcall mechanism seems cleaner if it does
the right thing.
How does this look?
diff --git a/drivers/tty/hvc/hvc_sbi.c b/drivers/tty/hvc/hvc_sbi.c
index 98114cbd85f1..534d6b75a2c6 100644
--- a/drivers/tty/hvc/hvc_sbi.c
+++ b/drivers/tty/hvc/hvc_sbi.c
@@ -87,11 +87,11 @@ static void sbi_console_write(struct console *co, const char *buf,
static struct console early_console_dev __initdata = {
.name = "early",
.write = sbi_console_write,
- .flags = CON_PRINTBUFFER | CON_BOOT,
+ .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
.index = -1
};
-static int __init setup_early_printk(char *str)
+static int __init setup_early_printk(void)
{
if (early_console == NULL) {
early_console = &early_console_dev;
@@ -99,5 +99,5 @@ static int __init setup_early_printk(char *str)
}
return 0;
}
-early_param("earlyprintk", setup_early_printk);
+early_initcall(setup_early_printk);
#endif
[toc] | [prev] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2017-07-12 13:10 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u2nGO-7sP-23@gated-at.bofh.it> |
| In reply to | #1685194 |
Palmer Dabbelt <palmer@dabbelt.com> writes:
> On Mon, 10 Jul 2017 23:21:07 PDT (-0700), mpe@ellerman.id.au wrote:
>> Palmer Dabbelt <palmer@dabbelt.com> writes:
>>>
>> ...
>>> +#ifdef CONFIG_EARLY_PRINTK
>>> +static void sbi_console_write(struct console *co, const char *buf,
>>> + unsigned int n)
>>> +{
>>> + int i;
>>> +
>>> + for (i = 0; i < n; ++i) {
>>> + if (buf[i] == '\n')
>>> + sbi_console_putchar('\r');
>>> + sbi_console_putchar(buf[i]);
>>> + }
>>> +}
>>> +
>>> +static struct console early_console_dev __initdata = {
>>> + .name = "early",
>>> + .write = sbi_console_write,
>>> + .flags = CON_PRINTBUFFER | CON_BOOT,
>>
>> AFAICS you could add CON_ANYTIME here, which would mean this console
>> would print output before the CPU is online.
>>
>> I think it doesn't currently matter because you call parse_early_param()
>> from setup_arch(), at which point the boot CPU has been marked online.
>>
>> But if this console can actually work earlier then you might be better
>> off just registering it unconditionally very early.
>
> That seems like a good idea. I'm not familiar with how all this works, but
> from my understanding of this early_initcall() should be sufficient to make
> this work? The only other driver that sets CON_ANYTIME and supports
> EARLY_PRINTK is hvc_xen, but that installs a header to let init code register
> the console directly. The early_initcall mechanism seems cleaner if it does
> the right thing.
Unfortunately early_initcall is not very "early" :) It's earlier than
all the other initcalls, but it's late compared to most of the arch boot
code.
The early_param() will work better, ie. register the console earlier
and increase the chance of you getting output from an early crash, than
early_initcall. But it requires you to put earlyprintk on the command line.
The best option is to just register the console as early as you can, ie.
as soon as it can give you output. So somewhere in your setup_arch(), or
even earlier (I haven't read your boot code).
cheers
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-12 18:30 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u2sGt-25N-5@gated-at.bofh.it> |
| In reply to | #1685701 |
On Wed, 12 Jul 2017 04:04:00 PDT (-0700), mpe@ellerman.id.au wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
>> On Mon, 10 Jul 2017 23:21:07 PDT (-0700), mpe@ellerman.id.au wrote:
>>> Palmer Dabbelt <palmer@dabbelt.com> writes:
>>>>
>>> ...
>>>> +#ifdef CONFIG_EARLY_PRINTK
>>>> +static void sbi_console_write(struct console *co, const char *buf,
>>>> + unsigned int n)
>>>> +{
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < n; ++i) {
>>>> + if (buf[i] == '\n')
>>>> + sbi_console_putchar('\r');
>>>> + sbi_console_putchar(buf[i]);
>>>> + }
>>>> +}
>>>> +
>>>> +static struct console early_console_dev __initdata = {
>>>> + .name = "early",
>>>> + .write = sbi_console_write,
>>>> + .flags = CON_PRINTBUFFER | CON_BOOT,
>>>
>>> AFAICS you could add CON_ANYTIME here, which would mean this console
>>> would print output before the CPU is online.
>>>
>>> I think it doesn't currently matter because you call parse_early_param()
>>> from setup_arch(), at which point the boot CPU has been marked online.
>>>
>>> But if this console can actually work earlier then you might be better
>>> off just registering it unconditionally very early.
>>
>> That seems like a good idea. I'm not familiar with how all this works, but
>> from my understanding of this early_initcall() should be sufficient to make
>> this work? The only other driver that sets CON_ANYTIME and supports
>> EARLY_PRINTK is hvc_xen, but that installs a header to let init code register
>> the console directly. The early_initcall mechanism seems cleaner if it does
>> the right thing.
>
> Unfortunately early_initcall is not very "early" :) It's earlier than
> all the other initcalls, but it's late compared to most of the arch boot
> code.
>
> The early_param() will work better, ie. register the console earlier
> and increase the chance of you getting output from an early crash, than
> early_initcall. But it requires you to put earlyprintk on the command line.
>
> The best option is to just register the console as early as you can, ie.
> as soon as it can give you output. So somewhere in your setup_arch(), or
> even earlier (I haven't read your boot code).
Doing it that way would require either moving the TTY driver into arch code (it
was specifically suggested we move it out) or adding a header file to allow
setup_arch() to call into the driver (XEN does this, and we're doing it for our
timer, but it seems hacky).
[toc] | [prev] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2017-07-13 14:10 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u2L6q-5tf-25@gated-at.bofh.it> |
| In reply to | #1685892 |
Palmer Dabbelt <palmer@dabbelt.com> writes:
> On Wed, 12 Jul 2017 04:04:00 PDT (-0700), mpe@ellerman.id.au wrote:
>> Palmer Dabbelt <palmer@dabbelt.com> writes:
>>
>>> On Mon, 10 Jul 2017 23:21:07 PDT (-0700), mpe@ellerman.id.au wrote:
>>>> Palmer Dabbelt <palmer@dabbelt.com> writes:
>>>>>
>>>> ...
>>>>> +#ifdef CONFIG_EARLY_PRINTK
>>>>> +static void sbi_console_write(struct console *co, const char *buf,
>>>>> + unsigned int n)
>>>>> +{
>>>>> + int i;
>>>>> +
>>>>> + for (i = 0; i < n; ++i) {
>>>>> + if (buf[i] == '\n')
>>>>> + sbi_console_putchar('\r');
>>>>> + sbi_console_putchar(buf[i]);
>>>>> + }
>>>>> +}
>>>>> +
>>>>> +static struct console early_console_dev __initdata = {
>>>>> + .name = "early",
>>>>> + .write = sbi_console_write,
>>>>> + .flags = CON_PRINTBUFFER | CON_BOOT,
>>>>
>>>> AFAICS you could add CON_ANYTIME here, which would mean this console
>>>> would print output before the CPU is online.
>>>>
>>>> I think it doesn't currently matter because you call parse_early_param()
>>>> from setup_arch(), at which point the boot CPU has been marked online.
>>>>
>>>> But if this console can actually work earlier then you might be better
>>>> off just registering it unconditionally very early.
>>>
>>> That seems like a good idea. I'm not familiar with how all this works, but
>>> from my understanding of this early_initcall() should be sufficient to make
>>> this work? The only other driver that sets CON_ANYTIME and supports
>>> EARLY_PRINTK is hvc_xen, but that installs a header to let init code register
>>> the console directly. The early_initcall mechanism seems cleaner if it does
>>> the right thing.
>>
>> Unfortunately early_initcall is not very "early" :) It's earlier than
>> all the other initcalls, but it's late compared to most of the arch boot
>> code.
>>
>> The early_param() will work better, ie. register the console earlier
>> and increase the chance of you getting output from an early crash, than
>> early_initcall. But it requires you to put earlyprintk on the command line.
>>
>> The best option is to just register the console as early as you can, ie.
>> as soon as it can give you output. So somewhere in your setup_arch(), or
>> even earlier (I haven't read your boot code).
>
> Doing it that way would require either moving the TTY driver into arch code (it
> was specifically suggested we move it out) or adding a header file to allow
> setup_arch() to call into the driver (XEN does this, and we're doing it for our
> timer, but it seems hacky).
I think it's fairly uncontroversial to have the early console in arch
code, especially in a case like this where there's no code shared
between the console and the TTY driver. But maybe someone will prove me
wrong.
Doing it the other way is not really hacky IMO, you can just have an
extern for the early console in one of your asm headers.
But anyway none of that is really that important so I'll shuddup :)
cheers
[toc] | [prev] | [next] | [standalone]
| From | James Hogan <james.hogan@imgtec.com> |
|---|---|
| Date | 2017-07-13 14:40 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u2Lzr-5DQ-9@gated-at.bofh.it> |
| In reply to | #1686483 |
[Multipart message — attachments visible in raw view] — view raw
On Thu, Jul 13, 2017 at 09:59:53PM +1000, Michael Ellerman wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
> > On Wed, 12 Jul 2017 04:04:00 PDT (-0700), mpe@ellerman.id.au wrote:
> >> Palmer Dabbelt <palmer@dabbelt.com> writes:
> >>
> >>> On Mon, 10 Jul 2017 23:21:07 PDT (-0700), mpe@ellerman.id.au wrote:
> >>>> Palmer Dabbelt <palmer@dabbelt.com> writes:
> >>>>>
> >>>> ...
> >>>>> +#ifdef CONFIG_EARLY_PRINTK
> >>>>> +static void sbi_console_write(struct console *co, const char *buf,
> >>>>> + unsigned int n)
> >>>>> +{
> >>>>> + int i;
> >>>>> +
> >>>>> + for (i = 0; i < n; ++i) {
> >>>>> + if (buf[i] == '\n')
> >>>>> + sbi_console_putchar('\r');
> >>>>> + sbi_console_putchar(buf[i]);
> >>>>> + }
> >>>>> +}
> >>>>> +
> >>>>> +static struct console early_console_dev __initdata = {
> >>>>> + .name = "early",
> >>>>> + .write = sbi_console_write,
> >>>>> + .flags = CON_PRINTBUFFER | CON_BOOT,
> >>>>
> >>>> AFAICS you could add CON_ANYTIME here, which would mean this console
> >>>> would print output before the CPU is online.
> >>>>
> >>>> I think it doesn't currently matter because you call parse_early_param()
> >>>> from setup_arch(), at which point the boot CPU has been marked online.
> >>>>
> >>>> But if this console can actually work earlier then you might be better
> >>>> off just registering it unconditionally very early.
> >>>
> >>> That seems like a good idea. I'm not familiar with how all this works, but
> >>> from my understanding of this early_initcall() should be sufficient to make
> >>> this work? The only other driver that sets CON_ANYTIME and supports
> >>> EARLY_PRINTK is hvc_xen, but that installs a header to let init code register
> >>> the console directly. The early_initcall mechanism seems cleaner if it does
> >>> the right thing.
> >>
> >> Unfortunately early_initcall is not very "early" :) It's earlier than
> >> all the other initcalls, but it's late compared to most of the arch boot
> >> code.
> >>
> >> The early_param() will work better, ie. register the console earlier
> >> and increase the chance of you getting output from an early crash, than
> >> early_initcall. But it requires you to put earlyprintk on the command line.
> >>
> >> The best option is to just register the console as early as you can, ie.
> >> as soon as it can give you output. So somewhere in your setup_arch(), or
> >> even earlier (I haven't read your boot code).
> >
> > Doing it that way would require either moving the TTY driver into arch code (it
> > was specifically suggested we move it out) or adding a header file to allow
> > setup_arch() to call into the driver (XEN does this, and we're doing it for our
> > timer, but it seems hacky).
>
> I think it's fairly uncontroversial to have the early console in arch
> code, especially in a case like this where there's no code shared
> between the console and the TTY driver. But maybe someone will prove me
> wrong.
>
> Doing it the other way is not really hacky IMO, you can just have an
> extern for the early console in one of your asm headers.
For reference both metag and mips do something like this for JTAG based
consoles (with drivers both residing in drivers/tty/):
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/metag/kernel/setup.c#n107
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/metag/kernel/setup.c#n234
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/include/asm/cdmm.h#n98
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/kernel/setup.c#n958
Its not all that pretty but it gets you console output that much
earlier and is a fairly special case, so I think its worth it.
Cheers
James
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-14 00:00 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u2Ujo-2Cp-27@gated-at.bofh.it> |
| In reply to | #1686501 |
On Thu, 13 Jul 2017 05:32:26 PDT (-0700), james.hogan@imgtec.com wrote:
> On Thu, Jul 13, 2017 at 09:59:53PM +1000, Michael Ellerman wrote:
>> Palmer Dabbelt <palmer@dabbelt.com> writes:
>>
>> > On Wed, 12 Jul 2017 04:04:00 PDT (-0700), mpe@ellerman.id.au wrote:
>> >> Palmer Dabbelt <palmer@dabbelt.com> writes:
>> >>
>> >>> On Mon, 10 Jul 2017 23:21:07 PDT (-0700), mpe@ellerman.id.au wrote:
>> >>>> Palmer Dabbelt <palmer@dabbelt.com> writes:
>> >>>>>
>> >>>> ...
>> >>>>> +#ifdef CONFIG_EARLY_PRINTK
>> >>>>> +static void sbi_console_write(struct console *co, const char *buf,
>> >>>>> + unsigned int n)
>> >>>>> +{
>> >>>>> + int i;
>> >>>>> +
>> >>>>> + for (i = 0; i < n; ++i) {
>> >>>>> + if (buf[i] == '\n')
>> >>>>> + sbi_console_putchar('\r');
>> >>>>> + sbi_console_putchar(buf[i]);
>> >>>>> + }
>> >>>>> +}
>> >>>>> +
>> >>>>> +static struct console early_console_dev __initdata = {
>> >>>>> + .name = "early",
>> >>>>> + .write = sbi_console_write,
>> >>>>> + .flags = CON_PRINTBUFFER | CON_BOOT,
>> >>>>
>> >>>> AFAICS you could add CON_ANYTIME here, which would mean this console
>> >>>> would print output before the CPU is online.
>> >>>>
>> >>>> I think it doesn't currently matter because you call parse_early_param()
>> >>>> from setup_arch(), at which point the boot CPU has been marked online.
>> >>>>
>> >>>> But if this console can actually work earlier then you might be better
>> >>>> off just registering it unconditionally very early.
>> >>>
>> >>> That seems like a good idea. I'm not familiar with how all this works, but
>> >>> from my understanding of this early_initcall() should be sufficient to make
>> >>> this work? The only other driver that sets CON_ANYTIME and supports
>> >>> EARLY_PRINTK is hvc_xen, but that installs a header to let init code register
>> >>> the console directly. The early_initcall mechanism seems cleaner if it does
>> >>> the right thing.
>> >>
>> >> Unfortunately early_initcall is not very "early" :) It's earlier than
>> >> all the other initcalls, but it's late compared to most of the arch boot
>> >> code.
>> >>
>> >> The early_param() will work better, ie. register the console earlier
>> >> and increase the chance of you getting output from an early crash, than
>> >> early_initcall. But it requires you to put earlyprintk on the command line.
>> >>
>> >> The best option is to just register the console as early as you can, ie.
>> >> as soon as it can give you output. So somewhere in your setup_arch(), or
>> >> even earlier (I haven't read your boot code).
>> >
>> > Doing it that way would require either moving the TTY driver into arch code (it
>> > was specifically suggested we move it out) or adding a header file to allow
>> > setup_arch() to call into the driver (XEN does this, and we're doing it for our
>> > timer, but it seems hacky).
>>
>> I think it's fairly uncontroversial to have the early console in arch
>> code, especially in a case like this where there's no code shared
>> between the console and the TTY driver. But maybe someone will prove me
>> wrong.
>>
>> Doing it the other way is not really hacky IMO, you can just have an
>> extern for the early console in one of your asm headers.
>
> For reference both metag and mips do something like this for JTAG based
> consoles (with drivers both residing in drivers/tty/):
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/metag/kernel/setup.c#n107
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/metag/kernel/setup.c#n234
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/include/asm/cdmm.h#n98
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/kernel/setup.c#n958
>
> Its not all that pretty but it gets you console output that much
> earlier and is a fairly special case, so I think its worth it.
If someone else is doing it, then it's good enough for me :). How does this
look?
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 319fad96f537..148fd0dc414b 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -59,6 +59,14 @@ unsigned long pfn_base;
/* The lucky hart to first increment this variable will boot the other cores */
atomic_t hart_lottery;
+#if defined(CONFIG_HVC_RISCV_SBI) && defined(CONFIG_EARLY_PRINTK)
+/*
+ * The SBI's early console lives in hvc_riscv_sbi.c, but we want very early
+ * access
+ */
+extern struct console riscv_sbi_early_console_dev;
+#endif
+
#ifdef CONFIG_BLK_DEV_INITRD
static void __init setup_initrd(void)
{
@@ -203,6 +211,13 @@ static void __init setup_bootmem(void)
void __init setup_arch(char **cmdline_p)
{
+#if defined(CONFIG_TTY_RISCV_SBI) && defined(CONFIG_EARLY_PRINTK)
+ if (likely(early_console == NULL)) {
+ early_console = &riscv_sbi_early_console;
+ register_console(early_console);
+ }
+#endif
+
#ifdef CONFIG_CMDLINE_BOOL
#ifdef CONFIG_CMDLINE_OVERRIDE
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
diff --git a/drivers/tty/hvc/hvc_riscv_sbi.c b/drivers/tty/hvc/hvc_riscv_sbi.c
index 534d6b75a2c6..20a6bfda4e32 100644
--- a/drivers/tty/hvc/hvc_riscv_sbi.c
+++ b/drivers/tty/hvc/hvc_riscv_sbi.c
@@ -84,20 +84,11 @@ static void sbi_console_write(struct console *co, const char *buf,
}
}
-static struct console early_console_dev __initdata = {
+/* This is used by arch/riscv/kernel/setup.c */
+struct console riscv_sbi_early_console_dev __initdata = {
.name = "early",
.write = sbi_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
.index = -1
};
-
-static int __init setup_early_printk(void)
-{
- if (early_console == NULL) {
- early_console = &early_console_dev;
- register_console(early_console);
- }
- return 0;
-}
-early_initcall(setup_early_printk);
#endif
[toc] | [prev] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2017-07-14 07:10 +0200 |
| Subject | Re: [PATCH 08/17] tty: New RISC-V SBI console driver |
| Message-ID | <u311v-7cz-5@gated-at.bofh.it> |
| In reply to | #1686950 |
Palmer Dabbelt <palmer@dabbelt.com> writes:
> On Thu, 13 Jul 2017 05:32:26 PDT (-0700), james.hogan@imgtec.com wrote:
>> On Thu, Jul 13, 2017 at 09:59:53PM +1000, Michael Ellerman wrote:
>>>
>>> I think it's fairly uncontroversial to have the early console in arch
>>> code, especially in a case like this where there's no code shared
>>> between the console and the TTY driver. But maybe someone will prove me
>>> wrong.
>>>
>>> Doing it the other way is not really hacky IMO, you can just have an
>>> extern for the early console in one of your asm headers.
>>
>> For reference both metag and mips do something like this for JTAG based
>> consoles (with drivers both residing in drivers/tty/):
...
>>
>> Its not all that pretty but it gets you console output that much
>> earlier and is a fairly special case, so I think its worth it.
>
> If someone else is doing it, then it's good enough for me :). How does this
> look?
>
> diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
> index 319fad96f537..148fd0dc414b 100644
> --- a/arch/riscv/kernel/setup.c
> +++ b/arch/riscv/kernel/setup.c
> @@ -59,6 +59,14 @@ unsigned long pfn_base;
> /* The lucky hart to first increment this variable will boot the other cores */
> atomic_t hart_lottery;
>
> +#if defined(CONFIG_HVC_RISCV_SBI) && defined(CONFIG_EARLY_PRINTK)
^
This is always true because you
said so in your Kconfig.
> +/*
> + * The SBI's early console lives in hvc_riscv_sbi.c, but we want very early
> + * access
> + */
> +extern struct console riscv_sbi_early_console_dev;
> +#endif
I would have put it in one of your arch headers, so that the hvc driver
can include it too.
Personally I tend not to bother #ifdef'ing every extern declaration, but
there are arguments both ways.
> #ifdef CONFIG_BLK_DEV_INITRD
> static void __init setup_initrd(void)
> {
> @@ -203,6 +211,13 @@ static void __init setup_bootmem(void)
>
> void __init setup_arch(char **cmdline_p)
> {
> +#if defined(CONFIG_TTY_RISCV_SBI) && defined(CONFIG_EARLY_PRINTK)
^
HVC
> + if (likely(early_console == NULL)) {
I don't think you need to check. You're the boss of early_console at
this point in boot.
> + early_console = &riscv_sbi_early_console;
> + register_console(early_console);
> + }
> +#endif
> +
> #ifdef CONFIG_CMDLINE_BOOL
> #ifdef CONFIG_CMDLINE_OVERRIDE
> strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
cheers
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 12/17] RISC-V: ELF and module implementation |
| Message-ID | <u1SD2-4hH-29@gated-at.bofh.it> |
| In reply to | #1684722 |
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.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
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
diff --git a/arch/riscv/include/asm/compat.h b/arch/riscv/include/asm/compat.h
new file mode 100644
index 000000000000..044aecff8854
--- /dev/null
+++ b/arch/riscv/include/asm/compat.h
@@ -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*/
diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h
new file mode 100644
index 000000000000..a1ef503d616e
--- /dev/null
+++ b/arch/riscv/include/asm/elf.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
+ * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ASM_RISCV_ELF_H
+#define _ASM_RISCV_ELF_H
+
+#include <uapi/asm/elf.h>
+#include <asm/auxvec.h>
+#include <asm/byteorder.h>
+
+/* TODO: Move definition into include/uapi/linux/elf-em.h */
+#define EM_RISCV 0xF3
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_ARCH EM_RISCV
+
+#ifdef CONFIG_64BIT
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+#if defined(__LITTLE_ENDIAN)
+#define ELF_DATA ELFDATA2LSB
+#elif defined(__BIG_ENDIAN)
+#define ELF_DATA ELFDATA2MSB
+#else
+#error "Unknown endianness"
+#endif
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_RISCV)
+
+#define CORE_DUMP_USE_REGSET
+#define ELF_EXEC_PAGESIZE (PAGE_SIZE)
+
+/*
+ * This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader. We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+#define ELF_ET_DYN_BASE ((TASK_SIZE / 3) * 2)
+
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this CPU supports. This could be done in user space,
+ * but it's not easy, and we've already done it here.
+ */
+#define ELF_HWCAP (elf_hwcap)
+extern unsigned long elf_hwcap;
+
+/*
+ * This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization. This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+ */
+#define ELF_PLATFORM (NULL)
+
+#define ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (elf_addr_t)current->mm->context.vdso); \
+} while (0)
+
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int uses_interp);
+
+#endif /* _ASM_RISCV_ELF_H */
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
new file mode 100644
index 000000000000..8a4ed7bbcbea
--- /dev/null
+++ b/arch/riscv/include/asm/hwcap.h
@@ -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
diff --git a/arch/riscv/mm/extable.c b/arch/riscv/mm/extable.c
new file mode 100644
index 000000000000..11bb9417123b
--- /dev/null
+++ b/arch/riscv/mm/extable.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
+ * Lennox Wu <lennox.wu@sunplusct.com>
+ * Chen Liqin <liqin.chen@sunplusct.com>
+ * 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;
+}
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 15/17] RISC-V: Paging and MMU |
| Message-ID | <u1SD1-4hH-19@gated-at.bofh.it> |
| In reply to | #1684722 |
This patch contains code to manage the RISC-V MMU, including definitions
of the page tables and the page walking code.
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
---
arch/riscv/include/asm/mmu_context.h | 69 ++++++
arch/riscv/include/asm/page.h | 134 +++++++++++
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, 1196 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
diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h
new file mode 100644
index 000000000000..de1fc1631fc4
--- /dev/null
+++ b/arch/riscv/include/asm/mmu_context.h
@@ -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 */
diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
new file mode 100644
index 000000000000..5bbbff2d5a60
--- /dev/null
+++ b/arch/riscv/include/asm/page.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 Chen Liqin <liqin.chen@sunplusct.com>
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ * Copyright (C) 2017 XiaojingZhu <zhuxiaoj@ict.ac.cn>
+ *
+ * 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_PAGE_H
+#define _ASM_RISCV_PAGE_H
+
+#include <linux/pfn.h>
+#include <linux/const.h>
+
+#define PAGE_SHIFT (12)
+#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+/*
+ * PAGE_OFFSET -- the first address of the first page of memory.
+ * When not using MMU this corresponds to the first free page in
+ * physical memory (aligned on a page boundary).
+ */
+#ifdef CONFIG_64BIT
+#define PAGE_OFFSET _AC(0xffffffff80000000, UL)
+#else
+#define PAGE_OFFSET _AC(0xc0000000, UL)
+#endif
+
+#define KERN_VIRT_SIZE (-PAGE_OFFSET)
+
+#ifndef __ASSEMBLY__
+
+#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1)))
+#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1)))
+
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr, size) (((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
+
+#define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE)
+#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
+
+#define clear_user_page(pgaddr, vaddr, page) memset((pgaddr), 0, PAGE_SIZE)
+#define copy_user_page(vto, vfrom, vaddr, topg) \
+ memcpy((vto), (vfrom), PAGE_SIZE)
+
+/*
+ * Use struct definitions to apply C type checking
+ */
+
+/* Page Global Directory entry */
+typedef struct {
+ unsigned long pgd;
+} pgd_t;
+
+/* Page Table entry */
+typedef struct {
+ unsigned long pte;
+} pte_t;
+
+typedef struct {
+ unsigned long pgprot;
+} pgprot_t;
+
+typedef struct page *pgtable_t;
+
+#define pte_val(x) ((x).pte)
+#define pgd_val(x) ((x).pgd)
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) })
+#define __pgd(x) ((pgd_t) { (x) })
+#define __pgprot(x) ((pgprot_t) { (x) })
+
+#ifdef CONFIG_64BITS
+#define PTE_FMT "%016lx"
+#else
+#define PTE_FMT "%08lx"
+#endif
+
+extern unsigned long va_pa_offset;
+extern unsigned long pfn_base;
+
+extern unsigned long max_low_pfn;
+extern unsigned long min_low_pfn;
+
+#define __pa(x) ((unsigned long)(x) - va_pa_offset)
+#define __va(x) ((void *)((unsigned long) (x) + va_pa_offset))
+
+#define phys_to_pfn(phys) (PFN_DOWN(phys))
+#define pfn_to_phys(pfn) (PFN_PHYS(pfn))
+
+#define virt_to_pfn(vaddr) (phys_to_pfn(__pa(vaddr)))
+#define pfn_to_virt(pfn) (__va(pfn_to_phys(pfn)))
+
+#define virt_to_page(vaddr) (pfn_to_page(virt_to_pfn(vaddr)))
+#define page_to_virt(page) (pfn_to_virt(page_to_pfn(page)))
+
+#define page_to_phys(page) (pfn_to_phys(page_to_pfn(page)))
+#define page_to_bus(page) (page_to_phys(page))
+#define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr)))
+
+#define pfn_valid(pfn) \
+ (((pfn) >= pfn_base) && (((pfn)-pfn_base) < max_mapnr))
+
+#define ARCH_PFN_OFFSET (pfn_base)
+
+#endif /* __ASSEMBLY__ */
+
+#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
+
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#include <asm-generic/memory_model.h>
+#include <asm-generic/getorder.h>
+
+/* vDSO support */
+/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
+#define __HAVE_ARCH_GATE_AREA
+
+#endif /* _ASM_RISCV_PAGE_H */
diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
new file mode 100644
index 000000000000..b40074bcb164
--- /dev/null
+++ b/arch/riscv/include/asm/pgalloc.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 Chen Liqin <liqin.chen@sunplusct.com>
+ * 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_PGALLOC_H
+#define _ASM_RISCV_PGALLOC_H
+
+#include <linux/mm.h>
+#include <asm/tlb.h>
+
+static inline void pmd_populate_kernel(struct mm_struct *mm,
+ pmd_t *pmd, pte_t *pte)
+{
+ unsigned long pfn = virt_to_pfn(pte);
+
+ set_pmd(pmd, __pmd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
+}
+
+static inline void pmd_populate(struct mm_struct *mm,
+ pmd_t *pmd, pgtable_t pte)
+{
+ unsigned long pfn = virt_to_pfn(page_address(pte));
+
+ set_pmd(pmd, __pmd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
+}
+
+#ifndef __PAGETABLE_PMD_FOLDED
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+ unsigned long pfn = virt_to_pfn(pmd);
+
+ set_pud(pud, __pud((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
+}
+#endif /* __PAGETABLE_PMD_FOLDED */
+
+#define pmd_pgtable(pmd) pmd_page(pmd)
+
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+ if (likely(pgd != NULL)) {
+ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+ /* Copy kernel mappings */
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ init_mm.pgd + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ }
+ return pgd;
+}
+
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+ free_page((unsigned long)pgd);
+}
+
+#ifndef __PAGETABLE_PMD_FOLDED
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ return (pmd_t *)__get_free_page(
+ GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+}
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+ free_page((unsigned long)pmd);
+}
+
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+
+#endif /* __PAGETABLE_PMD_FOLDED */
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+ unsigned long address)
+{
+ return (pte_t *)__get_free_page(
+ GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+}
+
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+ unsigned long address)
+{
+ struct page *pte;
+
+ pte = alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+ if (likely(pte != NULL))
+ pgtable_page_ctor(pte);
+ return pte;
+}
+
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+ free_page((unsigned long)pte);
+}
+
+static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
+{
+ pgtable_page_dtor(pte);
+ __free_page(pte);
+}
+
+#define __pte_free_tlb(tlb, pte, buf) \
+do { \
+ pgtable_page_dtor(pte); \
+ tlb_remove_page((tlb), pte); \
+} while (0)
+
+static inline void check_pgt_cache(void)
+{
+}
+
+#endif /* _ASM_RISCV_PGALLOC_H */
diff --git a/arch/riscv/include/asm/pgtable-32.h b/arch/riscv/include/asm/pgtable-32.h
new file mode 100644
index 000000000000..d61974b74182
--- /dev/null
+++ b/arch/riscv/include/asm/pgtable-32.h
@@ -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 */
diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
new file mode 100644
index 000000000000..7aa0ea9bd8bb
--- /dev/null
+++ b/arch/riscv/include/asm/pgtable-64.h
@@ -0,0 +1,84 @@
+/*
+ * 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_64_H
+#define _ASM_RISCV_PGTABLE_64_H
+
+#include <linux/const.h>
+
+#define PGDIR_SHIFT 30
+/* Size of region mapped by a page global directory */
+#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE - 1))
+
+#define PMD_SHIFT 21
+/* Size of region mapped by a page middle directory */
+#define PMD_SIZE (_AC(1, UL) << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE - 1))
+
+/* Page Middle Directory entry */
+typedef struct {
+ unsigned long pmd;
+} pmd_t;
+
+#define pmd_val(x) ((x).pmd)
+#define __pmd(x) ((pmd_t) { (x) })
+
+#define PTRS_PER_PMD (PAGE_SIZE / sizeof(pmd_t))
+
+static inline int pud_present(pud_t pud)
+{
+ return (pud_val(pud) & _PAGE_PRESENT);
+}
+
+static inline int pud_none(pud_t pud)
+{
+ return (pud_val(pud) == 0);
+}
+
+static inline int pud_bad(pud_t pud)
+{
+ return !pud_present(pud);
+}
+
+static inline void set_pud(pud_t *pudp, pud_t pud)
+{
+ *pudp = pud;
+}
+
+static inline void pud_clear(pud_t *pudp)
+{
+ set_pud(pudp, __pud(0));
+}
+
+static inline unsigned long pud_page_vaddr(pud_t pud)
+{
+ return (unsigned long)pfn_to_virt(pud_val(pud) >> _PAGE_PFN_SHIFT);
+}
+
+#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+
+static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
+{
+ return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
+}
+
+static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
+{
+ return __pmd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
+}
+
+#define pmd_ERROR(e) \
+ pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e))
+
+#endif /* _ASM_RISCV_PGTABLE_64_H */
diff --git a/arch/riscv/include/asm/pgtable-bits.h b/arch/riscv/include/asm/pgtable-bits.h
new file mode 100644
index 000000000000..997ddbb1d370
--- /dev/null
+++ b/arch/riscv/include/asm/pgtable-bits.h
@@ -0,0 +1,48 @@
+/*
+ * 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_BITS_H
+#define _ASM_RISCV_PGTABLE_BITS_H
+
+/*
+ * PTE format:
+ * | XLEN-1 10 | 9 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+ * PFN reserved for SW D A G U X W R V
+ */
+
+#define _PAGE_ACCESSED_OFFSET 6
+
+#define _PAGE_PRESENT (1 << 0)
+#define _PAGE_READ (1 << 1) /* Readable */
+#define _PAGE_WRITE (1 << 2) /* Writable */
+#define _PAGE_EXEC (1 << 3) /* Executable */
+#define _PAGE_USER (1 << 4) /* User */
+#define _PAGE_GLOBAL (1 << 5) /* Global */
+#define _PAGE_ACCESSED (1 << 6) /* Set by hardware on any access */
+#define _PAGE_DIRTY (1 << 7) /* Set by hardware on any write */
+#define _PAGE_SOFT (1 << 8) /* Reserved for software */
+
+#define _PAGE_SPECIAL _PAGE_SOFT
+#define _PAGE_TABLE _PAGE_PRESENT
+
+#define _PAGE_PFN_SHIFT 10
+
+/* Set of bits to preserve across pte_modify() */
+#define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \
+ _PAGE_WRITE | _PAGE_EXEC | \
+ _PAGE_USER | _PAGE_GLOBAL))
+
+/* Advertise support for _PAGE_SPECIAL */
+#define __HAVE_ARCH_PTE_SPECIAL
+
+#endif /* _ASM_RISCV_PGTABLE_BITS_H */
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
new file mode 100644
index 000000000000..3399257780b2
--- /dev/null
+++ b/arch/riscv/include/asm/pgtable.h
@@ -0,0 +1,430 @@
+/*
+ * 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_H
+#define _ASM_RISCV_PGTABLE_H
+
+#include <linux/mmzone.h>
+
+#include <asm/pgtable-bits.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_MMU
+
+/* Page Upper Directory not used in RISC-V */
+#include <asm-generic/pgtable-nopud.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include <linux/mm_types.h>
+
+#ifdef CONFIG_64BIT
+#include <asm/pgtable-64.h>
+#else
+#include <asm/pgtable-32.h>
+#endif /* CONFIG_64BIT */
+
+/* Number of entries in the page global directory */
+#define PTRS_PER_PGD (PAGE_SIZE / sizeof(pgd_t))
+/* Number of entries in the page table */
+#define PTRS_PER_PTE (PAGE_SIZE / sizeof(pte_t))
+
+/* Number of PGD entries that a user-mode program can use */
+#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
+#define FIRST_USER_ADDRESS 0
+
+/* Page protection bits */
+#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER)
+
+#define PAGE_NONE __pgprot(0)
+#define PAGE_READ __pgprot(_PAGE_BASE | _PAGE_READ)
+#define PAGE_WRITE __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_WRITE)
+#define PAGE_EXEC __pgprot(_PAGE_BASE | _PAGE_EXEC)
+#define PAGE_READ_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC)
+#define PAGE_WRITE_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | \
+ _PAGE_EXEC | _PAGE_WRITE)
+
+#define PAGE_COPY PAGE_READ
+#define PAGE_COPY_EXEC PAGE_EXEC
+#define PAGE_COPY_READ_EXEC PAGE_READ_EXEC
+#define PAGE_SHARED PAGE_WRITE
+#define PAGE_SHARED_EXEC PAGE_WRITE_EXEC
+
+#define _PAGE_KERNEL (_PAGE_READ \
+ | _PAGE_WRITE \
+ | _PAGE_PRESENT \
+ | _PAGE_ACCESSED \
+ | _PAGE_DIRTY)
+
+#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
+
+extern pgd_t swapper_pg_dir[];
+
+/* MAP_PRIVATE permissions: xwr (copy-on-write) */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READ
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_EXEC
+#define __P101 PAGE_READ_EXEC
+#define __P110 PAGE_COPY_EXEC
+#define __P111 PAGE_COPY_READ_EXEC
+
+/* MAP_SHARED permissions: xwr */
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READ
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_EXEC
+#define __S101 PAGE_READ_EXEC
+#define __S110 PAGE_SHARED_EXEC
+#define __S111 PAGE_SHARED_EXEC
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero,
+ * used for zero-mapped memory areas, etc.
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+static inline int pmd_present(pmd_t pmd)
+{
+ return (pmd_val(pmd) & _PAGE_PRESENT);
+}
+
+static inline int pmd_none(pmd_t pmd)
+{
+ return (pmd_val(pmd) == 0);
+}
+
+static inline int pmd_bad(pmd_t pmd)
+{
+ return !pmd_present(pmd);
+}
+
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+ *pmdp = pmd;
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ set_pmd(pmdp, __pmd(0));
+}
+
+
+static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
+{
+ return __pgd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
+}
+
+#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+
+/* Locate an entry in the page global directory */
+static inline pgd_t *pgd_offset(const struct mm_struct *mm, unsigned long addr)
+{
+ return mm->pgd + pgd_index(addr);
+}
+/* Locate an entry in the kernel page global directory */
+#define pgd_offset_k(addr) pgd_offset(&init_mm, (addr))
+
+static inline struct page *pmd_page(pmd_t pmd)
+{
+ return pfn_to_page(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
+}
+
+static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+{
+ return (unsigned long)pfn_to_virt(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
+}
+
+/* Yields the page frame number (PFN) of a page table entry */
+static inline unsigned long pte_pfn(pte_t pte)
+{
+ return (pte_val(pte) >> _PAGE_PFN_SHIFT);
+}
+
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+/* Constructs a page table entry */
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
+{
+ return __pte((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
+}
+
+static inline pte_t mk_pte(struct page *page, pgprot_t prot)
+{
+ return pfn_pte(page_to_pfn(page), prot);
+}
+
+#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+
+static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long addr)
+{
+ return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(addr);
+}
+
+#define pte_offset_map(dir, addr) pte_offset_kernel((dir), (addr))
+#define pte_unmap(pte) ((void)(pte))
+
+/*
+ * Certain architectures need to do special things when PTEs within
+ * a page table are directly modified. Thus, the following hook is
+ * made available.
+ */
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+}
+
+static inline void set_pte_at(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep, pte_t pteval)
+{
+ set_pte(ptep, pteval);
+}
+
+static inline void pte_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ set_pte_at(mm, addr, ptep, __pte(0));
+}
+
+static inline int pte_present(pte_t pte)
+{
+ return (pte_val(pte) & _PAGE_PRESENT);
+}
+
+static inline int pte_none(pte_t pte)
+{
+ return (pte_val(pte) == 0);
+}
+
+/* static inline int pte_read(pte_t pte) */
+
+static inline int pte_write(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_WRITE;
+}
+
+static inline int pte_huge(pte_t pte)
+{
+ return pte_present(pte)
+ && (pte_val(pte) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));
+}
+
+/* static inline int pte_exec(pte_t pte) */
+
+static inline int pte_dirty(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_DIRTY;
+}
+
+static inline int pte_young(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_ACCESSED;
+}
+
+static inline int pte_special(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_SPECIAL;
+}
+
+/* static inline pte_t pte_rdprotect(pte_t pte) */
+
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~(_PAGE_WRITE));
+}
+
+/* static inline pte_t pte_mkread(pte_t pte) */
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_WRITE);
+}
+
+/* static inline pte_t pte_mkexec(pte_t pte) */
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_DIRTY);
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~(_PAGE_DIRTY));
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~(_PAGE_ACCESSED));
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_SPECIAL);
+}
+
+/* Modify page protection bits */
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
+}
+
+#define pgd_ERROR(e) \
+ pr_err("%s:%d: bad pgd " PTE_FMT ".\n", __FILE__, __LINE__, pgd_val(e))
+
+
+/* Commit new configuration to MMU hardware */
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)
+{
+ /*
+ * The kernel assumes that TLBs don't cache invalid entries, but
+ * in RISC-V, SFENCE.VMA specifies an ordering constraint, not a
+ * cache flush; it is necessary even after writing invalid entries.
+ * Relying on flush_tlb_fix_spurious_fault would suffice, but
+ * the extra traps reduce performance. So, eagerly SFENCE.VMA.
+ */
+ local_flush_tlb_page(address);
+}
+
+#define __HAVE_ARCH_PTE_SAME
+static inline int pte_same(pte_t pte_a, pte_t pte_b)
+{
+ return pte_val(pte_a) == pte_val(pte_b);
+}
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline int ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty)
+{
+ if (!pte_same(*ptep, entry))
+ set_pte_at(vma->vm_mm, address, ptep, entry);
+ /*
+ * update_mmu_cache will unconditionally execute, handling both
+ * the case that the PTE changed and the spurious fault case.
+ */
+ return true;
+}
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ return __pte(atomic_long_xchg((atomic_long_t *)ptep, 0));
+}
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long address,
+ pte_t *ptep)
+{
+ if (!pte_young(*ptep))
+ return 0;
+ return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep));
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ atomic_long_and(~(unsigned long)_PAGE_WRITE, (atomic_long_t *)ptep);
+}
+
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)
+{
+ /*
+ * This comment is borrowed from x86, but applies equally to RISC-V:
+ *
+ * Clearing the accessed bit without a TLB flush
+ * doesn't cause data corruption. [ It could cause incorrect
+ * page aging and the (mistaken) reclaim of hot pages, but the
+ * chance of that should be relatively low. ]
+ *
+ * So as a performance optimization don't flush the TLB when
+ * clearing the accessed bit, it will eventually be flushed by
+ * a context switch or a VM operation anyway. [ In the rare
+ * event of it not getting flushed for a long time the delay
+ * shouldn't really matter because there's no real memory
+ * pressure for swapout to react to. ]
+ */
+ return ptep_test_and_clear_young(vma, address, ptep);
+}
+
+/*
+ * Encode and decode a swap entry
+ *
+ * Format of swap PTE:
+ * bit 0: _PAGE_PRESENT (zero)
+ * bit 1: reserved for future use (zero)
+ * bits 2 to 6: swap type
+ * bits 7 to XLEN-1: swap offset
+ */
+#define __SWP_TYPE_SHIFT 2
+#define __SWP_TYPE_BITS 5
+#define __SWP_TYPE_MASK ((1UL << __SWP_TYPE_BITS) - 1)
+#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
+
+#define MAX_SWAPFILES_CHECK() \
+ BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
+
+#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
+#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT)
+#define __swp_entry(type, offset) ((swp_entry_t) \
+ { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
+
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
+
+#ifdef CONFIG_FLATMEM
+#define kern_addr_valid(addr) (1) /* FIXME */
+#endif
+
+extern void paging_init(void);
+
+static inline void pgtable_cache_init(void)
+{
+ /* No page table caches to initialize */
+}
+
+#endif /* CONFIG_MMU */
+
+#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
+#define VMALLOC_END (PAGE_OFFSET - 1)
+#define VMALLOC_START (PAGE_OFFSET - VMALLOC_SIZE)
+
+/*
+ * Task size is 0x40000000000 for RV64 or 0xb800000 for RV32.
+ * Note that PGDIR_SIZE must evenly divide TASK_SIZE.
+ */
+#ifdef CONFIG_64BIT
+#define TASK_SIZE (PGDIR_SIZE * PTRS_PER_PGD / 2)
+#else
+#define TASK_SIZE VMALLOC_START
+#endif
+
+#include <asm-generic/pgtable.h>
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_RISCV_PGTABLE_H */
diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c
new file mode 100644
index 000000000000..df2ca3c65048
--- /dev/null
+++ b/arch/riscv/mm/fault.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
+ * Lennox Wu <lennox.wu@sunplusct.com>
+ * Chen Liqin <liqin.chen@sunplusct.com>
+ * 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; 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/mm.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/perf_event.h>
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+
+#include <asm/pgalloc.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+/*
+ * This routine handles page faults. It determines the address and the
+ * problem, and then passes it off to one of the appropriate routines.
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs)
+{
+ struct task_struct *tsk;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm;
+ unsigned long addr, cause;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+ int fault, code = SEGV_MAPERR;
+
+ cause = regs->scause;
+ addr = regs->sbadaddr;
+
+ tsk = current;
+ mm = tsk->mm;
+
+ /*
+ * Fault-in kernel-space virtual memory on-demand.
+ * The 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ */
+ if (unlikely((addr >= VMALLOC_START) && (addr <= VMALLOC_END)))
+ goto vmalloc_fault;
+
+ /* Enable interrupts if they were enabled in the parent context. */
+ if (likely(regs->sstatus & SR_PIE))
+ local_irq_enable();
+
+ /*
+ * If we're in an interrupt, have no user context, or are running
+ * in an atomic region, then we must not take the fault.
+ */
+ if (unlikely(faulthandler_disabled() || !mm))
+ goto no_context;
+
+ if (user_mode(regs))
+ flags |= FAULT_FLAG_USER;
+
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
+
+retry:
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, addr);
+ if (unlikely(!vma))
+ goto bad_area;
+ if (likely(vma->vm_start <= addr))
+ goto good_area;
+ if (unlikely(!(vma->vm_flags & VM_GROWSDOWN)))
+ goto bad_area;
+ if (unlikely(expand_stack(vma, addr)))
+ goto bad_area;
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it.
+ */
+good_area:
+ code = SEGV_ACCERR;
+
+ switch (cause) {
+ case EXC_INST_PAGE_FAULT:
+ if (!(vma->vm_flags & VM_EXEC))
+ goto bad_area;
+ break;
+ case EXC_LOAD_PAGE_FAULT:
+ if (!(vma->vm_flags & VM_READ))
+ goto bad_area;
+ break;
+ case EXC_STORE_PAGE_FAULT:
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ flags |= FAULT_FLAG_WRITE;
+ break;
+ default:
+ panic("%s: unhandled cause %lu", __func__, cause);
+ }
+
+ /*
+ * If for any reason at all we could not handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ fault = handle_mm_fault(vma, addr, flags);
+
+ /*
+ * If we need to retry but a fatal signal is pending, handle the
+ * signal first. We do not need to release the mmap_sem because it
+ * would already be released in __lock_page_or_retry in mm/filemap.c.
+ */
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(tsk))
+ return;
+
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
+ }
+
+ /*
+ * Major/minor page fault accounting is only done on the
+ * initial attempt. If we go through a retry, it is extremely
+ * likely that the page will be found in page cache at that point.
+ */
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR) {
+ tsk->maj_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ,
+ 1, regs, addr);
+ } else {
+ tsk->min_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN,
+ 1, regs, addr);
+ }
+ if (fault & VM_FAULT_RETRY) {
+ /*
+ * Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+ * of starvation.
+ */
+ flags &= ~(FAULT_FLAG_ALLOW_RETRY);
+ flags |= FAULT_FLAG_TRIED;
+
+ /*
+ * No need to up_read(&mm->mmap_sem) as we would
+ * have already released it in __lock_page_or_retry
+ * in mm/filemap.c.
+ */
+ goto retry;
+ }
+ }
+
+ up_read(&mm->mmap_sem);
+ return;
+
+ /*
+ * Something tried to access memory that isn't in our memory map.
+ * Fix it, but check if it's kernel or user first.
+ */
+bad_area:
+ up_read(&mm->mmap_sem);
+ /* User mode accesses just cause a SIGSEGV */
+ if (user_mode(regs)) {
+ do_trap(regs, SIGSEGV, code, addr, tsk);
+ return;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if (fixup_exception(regs))
+ return;
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ bust_spinlocks(1);
+ pr_alert("Unable to handle kernel %s at virtual address " REG_FMT "\n",
+ (addr < PAGE_SIZE) ? "NULL pointer dereference" :
+ "paging request", addr);
+ die(regs, "Oops");
+ do_exit(SIGKILL);
+
+ /*
+ * We ran out of memory, call the OOM killer, and return the userspace
+ * (which will retry the fault, or kill us if we got oom-killed).
+ */
+out_of_memory:
+ up_read(&mm->mmap_sem);
+ if (!user_mode(regs))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
+
+do_sigbus:
+ up_read(&mm->mmap_sem);
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+ do_trap(regs, SIGBUS, BUS_ADRERR, addr, tsk);
+ return;
+
+vmalloc_fault:
+ {
+ pgd_t *pgd, *pgd_k;
+ pud_t *pud, *pud_k;
+ p4d_t *p4d, *p4d_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+ int index;
+
+ if (user_mode(regs))
+ goto bad_area;
+
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Do _not_ use "tsk->active_mm->pgd" here.
+ * We might be inside an interrupt in the middle
+ * of a task switch.
+ */
+ index = pgd_index(addr);
+ pgd = (pgd_t *)pfn_to_virt(csr_read(sptbr)) + index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ goto no_context;
+ set_pgd(pgd, *pgd_k);
+
+ p4d = p4d_offset(pgd, addr);
+ p4d_k = p4d_offset(pgd_k, addr);
+ if (!p4d_present(*p4d_k))
+ goto no_context;
+
+ pud = pud_offset(p4d, addr);
+ pud_k = pud_offset(p4d_k, addr);
+ if (!pud_present(*pud_k))
+ goto no_context;
+
+ /*
+ * Since the vmalloc area is global, it is unnecessary
+ * to copy individual PTEs
+ */
+ pmd = pmd_offset(pud, addr);
+ pmd_k = pmd_offset(pud_k, addr);
+ if (!pmd_present(*pmd_k))
+ goto no_context;
+ set_pmd(pmd, *pmd_k);
+
+ /*
+ * Make sure the actual PTE exists as well to
+ * catch kernel vmalloc-area accesses to non-mapped
+ * addresses. If we don't do this, this will just
+ * silently loop forever.
+ */
+ pte_k = pte_offset_kernel(pmd_k, addr);
+ if (!pte_present(*pte_k))
+ goto no_context;
+ return;
+ }
+}
--
2.13.0
[toc] | [prev] | [next] | [standalone]
| From | Palmer Dabbelt <palmer@dabbelt.com> |
|---|---|
| Date | 2017-07-11 04:00 +0200 |
| Subject | [PATCH 04/17] MAINTAINERS: Add RISC-V |
| Message-ID | <u1SD2-4hH-33@gated-at.bofh.it> |
| In reply to | #1684722 |
From: Jonathan Neuschäfer <j.neuschaefer@gmx.net> RISC-V needs a MAINTAINERS entry. Let's add one. Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net> Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com> --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d8eab9322ba2..3ead16565003 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11180,6 +11180,14 @@ M: Maxim Levitsky <maximlevitsky@gmail.com> S: Maintained F: drivers/memstick/host/r592.* +RISC-V ARCHITECTURE +M: Palmer Dabbelt <palmer@sifive.com> +M: Albert Ou <albert@sifive.com> +L: patches@groups.riscv.org +T: git https://github.com/riscv/riscv-linux +S: Supported +F: arch/riscv/ + ROCCAT DRIVERS M: Stefan Achatz <erazor_de@users.sourceforge.net> W: http://sourceforge.net/projects/roccat/ -- 2.13.0
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web