提交 69dac8e4 编写于 作者: L Linus Torvalds

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

Pull more RISC-V updates from Palmer Dabbelt:
 "There's still a handful of new features in here, but there are a lot
  of fixes/cleanups as well:

   - Support for the Zicbom extension for explicit cache-block
     management, along with the necessary bits to make the non-standard
     cache management ops on the Allwinner D1 function

   - Support for the Zihintpause extension, which codifies a go-slow
     instruction used for cpu_relax()

   - Support for the Sstc extension for supervisor-mode timer/counter
     management

   - Many device tree fixes and cleanups, including a large set for the
     Canaan device trees

   - A handful of fixes and cleanups for the PMU driver"

* tag 'riscv-for-linus-5.20-mw2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: (43 commits)
  dt-bindings: gpio: sifive: add gpio-line-names
  wireguard: selftests: set CONFIG_NONPORTABLE on riscv32
  RISC-V: KVM: Support sstc extension
  RISC-V: Improve SBI definitions
  RISC-V: Move counter info definition to sbi header file
  RISC-V: Fix SBI PMU calls for RV32
  RISC-V: Update user page mapping only once during start
  RISC-V: Fix counter restart during overflow for RV32
  RISC-V: Prefer sstc extension if available
  RISC-V: Enable sstc extension parsing from DT
  RISC-V: Add SSTC extension CSR details
  riscv:uprobe fix SR_SPIE set/clear handling
  dt-bindings: riscv: fix SiFive l2-cache's cache-sets
  riscv: ensure cpu_ops_sbi is declared
  RISC-V: cpu_ops_spinwait.c should include head.h
  RISC-V: Declare cpu_ops_spinwait in <asm/cpu_ops.h>
  riscv: dts: starfive: correct number of external interrupts
  riscv: dts: sifive unmatched: Add PWM controlled LEDs
  riscv/purgatory: Omit use of bin2c
  riscv/purgatory: hard-code obj-y in Makefile
  ...
Ilitek ILI9341 display panels
This binding is for display panels using an Ilitek ILI9341 controller in SPI
mode.
Required properties:
- compatible: "adafruit,yx240qv29", "ilitek,ili9341"
- dc-gpios: D/C pin
- reset-gpios: Reset pin
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in ../spi/spi-bus.txt must be specified.
Optional properties:
- rotation: panel rotation in degrees counter clockwise (0,90,180,270)
- backlight: phandle of the backlight device attached to the panel
Example:
display@0{
compatible = "adafruit,yx240qv29", "ilitek,ili9341";
reg = <0>;
spi-max-frequency = <32000000>;
dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
rotation = <270>;
backlight = <&backlight>;
};
......@@ -21,8 +21,10 @@ properties:
compatible:
items:
- enum:
- adafruit,yx240qv29
# ili9341 240*320 Color on stm32f429-disco board
- st,sf-tc240t-9370-t
- canaan,kd233-tft
- const: ilitek,ili9341
reg: true
......@@ -47,31 +49,50 @@ properties:
vddi-led-supply:
description: Voltage supply for the LED driver (1.65 .. 3.3 V)
additionalProperties: false
unevaluatedProperties: false
required:
- compatible
- reg
- dc-gpios
- port
if:
properties:
compatible:
contains:
enum:
- st,sf-tc240t-9370-t
then:
required:
- port
examples:
- |+
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
panel: display@0 {
compatible = "st,sf-tc240t-9370-t",
"ilitek,ili9341";
reg = <0>;
spi-3wire;
spi-max-frequency = <10000000>;
dc-gpios = <&gpiod 13 0>;
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
compatible = "st,sf-tc240t-9370-t",
"ilitek,ili9341";
reg = <0>;
spi-3wire;
spi-max-frequency = <10000000>;
dc-gpios = <&gpiod 13 0>;
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
display@1{
compatible = "adafruit,yx240qv29", "ilitek,ili9341";
reg = <1>;
spi-max-frequency = <10000000>;
dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
rotation = <270>;
backlight = <&backlight>;
};
};
...
......@@ -46,6 +46,10 @@ properties:
maximum: 32
default: 16
gpio-line-names:
minItems: 1
maxItems: 32
gpio-controller: true
required:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/canaan,k210-sram.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Canaan K210 SRAM memory controller
description:
The Canaan K210 SRAM memory controller is responsible for the system's 8 MiB
of SRAM. The controller is initialised by the bootloader, which configures
its clocks, before OS bringup.
maintainers:
- Conor Dooley <conor@kernel.org>
properties:
compatible:
enum:
- canaan,k210-sram
clocks:
minItems: 1
items:
- description: sram0 clock
- description: sram1 clock
- description: aisram clock
clock-names:
minItems: 1
items:
- const: sram0
- const: sram1
- const: aisram
required:
- compatible
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/k210-clk.h>
memory-controller {
compatible = "canaan,k210-sram";
clocks = <&sysclk K210_CLK_SRAM0>,
<&sysclk K210_CLK_SRAM1>,
<&sysclk K210_CLK_AI>;
clock-names = "sram0", "sram1", "aisram";
};
......@@ -63,6 +63,11 @@ properties:
- riscv,sv48
- riscv,none
riscv,cbom-block-size:
$ref: /schemas/types.yaml#/definitions/uint32
description:
The blocksize in bytes for the Zicbom cache operations.
riscv,isa:
description:
Identifies the specific RISC-V instruction set architecture
......
......@@ -46,7 +46,7 @@ properties:
const: 2
cache-sets:
const: 1024
enum: [1024, 2048]
cache-size:
const: 2097152
......@@ -84,6 +84,8 @@ then:
description: |
Must contain entries for DirError, DataError and DataFail signals.
maxItems: 3
cache-sets:
const: 1024
else:
properties:
......@@ -91,6 +93,8 @@ else:
description: |
Must contain entries for DirError, DataError, DataFail, DirFail signals.
minItems: 4
cache-sets:
const: 2048
additionalProperties: false
......
......@@ -113,6 +113,7 @@ config RISCV
select MODULES_USE_ELF_RELA if MODULES
select MODULE_SECTIONS if MODULES
select OF
select OF_DMA_DEFAULT_COHERENT
select OF_EARLY_FLATTREE
select OF_IRQ
select PCI_DOMAINS_GENERIC if PCI
......@@ -218,6 +219,14 @@ config PGTABLE_LEVELS
config LOCKDEP_SUPPORT
def_bool y
config RISCV_DMA_NONCOHERENT
bool
select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SETUP_DMA_OPS
select DMA_DIRECT_REMAP
source "arch/riscv/Kconfig.socs"
source "arch/riscv/Kconfig.erratas"
......@@ -392,6 +401,28 @@ config RISCV_ISA_SVPBMT
If you don't know what to do here, say Y.
config CC_HAS_ZICBOM
bool
default y if 64BIT && $(cc-option,-mabi=lp64 -march=rv64ima_zicbom)
default y if 32BIT && $(cc-option,-mabi=ilp32 -march=rv32ima_zicbom)
config RISCV_ISA_ZICBOM
bool "Zicbom extension support for non-coherent DMA operation"
depends on CC_HAS_ZICBOM
depends on !XIP_KERNEL && MMU
select RISCV_DMA_NONCOHERENT
select RISCV_ALTERNATIVE
default y
help
Adds support to dynamically detect the presence of the ZICBOM
extension (Cache Block Management Operations) and enable its
usage.
The Zicbom extension can be used to handle for example
non-coherent DMA support on devices that need it.
If you don't know what to do here, say Y.
config FPU
bool "FPU support"
default y
......@@ -463,7 +494,6 @@ config KEXEC_FILE
config ARCH_HAS_KEXEC_PURGATORY
def_bool KEXEC_FILE
select BUILD_BIN2C
depends on CRYPTO=y
depends on CRYPTO_SHA256=y
......
......@@ -55,4 +55,15 @@ config ERRATA_THEAD_PBMT
If you don't know what to do here, say "Y".
config ERRATA_THEAD_CMO
bool "Apply T-Head cache management errata"
depends on ERRATA_THEAD
select RISCV_DMA_NONCOHERENT
default y
help
This will apply the cache management errata to handle the
non-standard handling on non-coherent operations on T-Head SoCs.
If you don't know what to do here, say "Y".
endmenu # "CPU errata selection"
......@@ -56,6 +56,14 @@ riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c
toolchain-need-zicsr-zifencei := $(call cc-option-yn, -march=$(riscv-march-y)_zicsr_zifencei)
riscv-march-$(toolchain-need-zicsr-zifencei) := $(riscv-march-y)_zicsr_zifencei
# Check if the toolchain supports Zicbom extension
toolchain-supports-zicbom := $(call cc-option-yn, -march=$(riscv-march-y)_zicbom)
riscv-march-$(toolchain-supports-zicbom) := $(riscv-march-y)_zicbom
# Check if the toolchain supports Zihintpause extension
toolchain-supports-zihintpause := $(call cc-option-yn, -march=$(riscv-march-y)_zihintpause)
riscv-march-$(toolchain-supports-zihintpause) := $(riscv-march-y)_zihintpause
KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
KBUILD_AFLAGS += -march=$(riscv-march-y)
......
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .dtb, $(CONFIG_SOC_CANAAN_K210_DTB_SOURCE))
obj-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
dtb-$(CONFIG_SOC_CANAAN) += canaan_kd233.dtb
dtb-$(CONFIG_SOC_CANAAN) += k210_generic.dtb
dtb-$(CONFIG_SOC_CANAAN) += sipeed_maix_bit.dtb
dtb-$(CONFIG_SOC_CANAAN) += sipeed_maix_dock.dtb
dtb-$(CONFIG_SOC_CANAAN) += sipeed_maix_go.dtb
dtb-$(CONFIG_SOC_CANAAN) += sipeed_maixduino.dtb
obj-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .dtb.o, $(CONFIG_SOC_CANAAN_K210_DTB_SOURCE))
......@@ -127,10 +127,10 @@
cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
panel@0 {
compatible = "ilitek,ili9341";
compatible = "canaan,kd233-tft", "ilitek,ili9341";
reg = <0>;
dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
spi-max-frequency = <15000000>;
spi-max-frequency = <10000000>;
status = "disabled";
};
};
......@@ -142,7 +142,7 @@
cs-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
status = "okay";
slot@0 {
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
voltage-ranges = <3300 3300>;
......
......@@ -81,11 +81,13 @@
sram: memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x400000>, /* sram0 4 MiB */
<0x80400000 0x200000>, /* sram1 2 MiB */
<0x80600000 0x200000>; /* aisram 2 MiB */
};
sram_controller: memory-controller {
compatible = "canaan,k210-sram";
reg = <0x80000000 0x400000>,
<0x80400000 0x200000>,
<0x80600000 0x200000>;
reg-names = "sram0", "sram1", "aisram";
clocks = <&sysclk K210_CLK_SRAM0>,
<&sysclk K210_CLK_SRAM1>,
<&sysclk K210_CLK_AI>;
......@@ -173,7 +175,7 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-pm-bus";
ranges;
ranges = <0x50200000 0x50200000 0x200000>;
clocks = <&sysclk K210_CLK_APB0>;
gpio1: gpio@50200000 {
......@@ -261,7 +263,7 @@
};
i2s0: i2s@50250000 {
compatible = "snps,designware-i2s";
compatible = "canaan,k210-i2s", "snps,designware-i2s";
reg = <0x50250000 0x200>;
interrupts = <5>;
clocks = <&sysclk K210_CLK_I2S0>;
......@@ -270,7 +272,7 @@
};
i2s1: i2s@50260000 {
compatible = "snps,designware-i2s";
compatible = "canaan,k210-i2s", "snps,designware-i2s";
reg = <0x50260000 0x200>;
interrupts = <6>;
clocks = <&sysclk K210_CLK_I2S1>;
......@@ -279,7 +281,7 @@
};
i2s2: i2s@50270000 {
compatible = "snps,designware-i2s";
compatible = "canaan,k210-i2s", "snps,designware-i2s";
reg = <0x50270000 0x200>;
interrupts = <7>;
clocks = <&sysclk K210_CLK_I2S2>;
......@@ -329,28 +331,58 @@
timer0: timer@502d0000 {
compatible = "snps,dw-apb-timer";
reg = <0x502D0000 0x100>;
interrupts = <14>, <15>;
reg = <0x502D0000 0x14>;
interrupts = <14>;
clocks = <&sysclk K210_CLK_TIMER0>,
<&sysclk K210_CLK_APB0>;
clock-names = "timer", "pclk";
resets = <&sysrst K210_RST_TIMER0>;
};
timer1: timer@502e0000 {
timer1: timer@502d0014 {
compatible = "snps,dw-apb-timer";
reg = <0x502D0014 0x14>;
interrupts = <15>;
clocks = <&sysclk K210_CLK_TIMER0>,
<&sysclk K210_CLK_APB0>;
clock-names = "timer", "pclk";
resets = <&sysrst K210_RST_TIMER0>;
};
timer2: timer@502e0000 {
compatible = "snps,dw-apb-timer";
reg = <0x502E0000 0x14>;
interrupts = <16>;
clocks = <&sysclk K210_CLK_TIMER1>,
<&sysclk K210_CLK_APB0>;
clock-names = "timer", "pclk";
resets = <&sysrst K210_RST_TIMER1>;
};
timer3: timer@502e0014 {
compatible = "snps,dw-apb-timer";
reg = <0x502E0000 0x100>;
interrupts = <16>, <17>;
reg = <0x502E0014 0x114>;
interrupts = <17>;
clocks = <&sysclk K210_CLK_TIMER1>,
<&sysclk K210_CLK_APB0>;
clock-names = "timer", "pclk";
resets = <&sysrst K210_RST_TIMER1>;
};
timer2: timer@502f0000 {
timer4: timer@502f0000 {
compatible = "snps,dw-apb-timer";
reg = <0x502F0000 0x100>;
interrupts = <18>, <19>;
reg = <0x502F0000 0x14>;
interrupts = <18>;
clocks = <&sysclk K210_CLK_TIMER2>,
<&sysclk K210_CLK_APB0>;
clock-names = "timer", "pclk";
resets = <&sysrst K210_RST_TIMER2>;
};
timer5: timer@502f0014 {
compatible = "snps,dw-apb-timer";
reg = <0x502F0014 0x14>;
interrupts = <19>;
clocks = <&sysclk K210_CLK_TIMER2>,
<&sysclk K210_CLK_APB0>;
clock-names = "timer", "pclk";
......@@ -362,7 +394,7 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-pm-bus";
ranges;
ranges = <0x50400000 0x50400000 0x40100>;
clocks = <&sysclk K210_CLK_APB1>;
wdt0: watchdog@50400000 {
......@@ -417,7 +449,7 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-pm-bus";
ranges;
ranges = <0x52000000 0x52000000 0x2000200>;
clocks = <&sysclk K210_CLK_APB2>;
spi0: spi@52000000 {
......@@ -431,7 +463,6 @@
clock-names = "ssi_clk", "pclk";
resets = <&sysrst K210_RST_SPI0>;
reset-names = "spi";
spi-max-frequency = <25000000>;
num-cs = <4>;
reg-io-width = <4>;
};
......@@ -447,7 +478,6 @@
clock-names = "ssi_clk", "pclk";
resets = <&sysrst K210_RST_SPI1>;
reset-names = "spi";
spi-max-frequency = <25000000>;
num-cs = <4>;
reg-io-width = <4>;
};
......@@ -463,8 +493,7 @@
clock-names = "ssi_clk", "pclk";
resets = <&sysrst K210_RST_SPI3>;
reset-names = "spi";
/* Could possibly go up to 200 MHz */
spi-max-frequency = <100000000>;
num-cs = <4>;
reg-io-width = <4>;
};
......
......@@ -189,7 +189,7 @@
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
status = "okay";
slot@0 {
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
voltage-ranges = <3300 3300>;
......
......@@ -191,7 +191,7 @@
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
status = "okay";
slot@0 {
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
voltage-ranges = <3300 3300>;
......
......@@ -199,7 +199,7 @@
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
status = "okay";
slot@0 {
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
voltage-ranges = <3300 3300>;
......
......@@ -164,7 +164,7 @@
cs-gpios = <&gpio1_0 2 GPIO_ACTIVE_LOW>;
status = "okay";
slot@0 {
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
voltage-ranges = <3300 3300>;
......
......@@ -4,6 +4,8 @@
#include "fu740-c000.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/pwm/pwm.h>
/* Clock frequency (in Hz) of the PCB crystal for rtcclk */
#define RTCCLK_FREQ 1000000
......@@ -44,6 +46,46 @@
compatible = "gpio-poweroff";
gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
};
led-controller-1 {
compatible = "pwm-leds";
led-d12 {
pwms = <&pwm0 0 7812500 PWM_POLARITY_INVERTED>;
active-low;
color = <LED_COLOR_ID_GREEN>;
max-brightness = <255>;
label = "d12";
};
};
led-controller-2 {
compatible = "pwm-leds-multicolor";
multi-led {
color = <LED_COLOR_ID_RGB>;
max-brightness = <255>;
label = "d2";
led-red {
pwms = <&pwm0 2 7812500 PWM_POLARITY_INVERTED>;
active-low;
color = <LED_COLOR_ID_RED>;
};
led-green {
pwms = <&pwm0 1 7812500 PWM_POLARITY_INVERTED>;
active-low;
color = <LED_COLOR_ID_GREEN>;
};
led-blue {
pwms = <&pwm0 3 7812500 PWM_POLARITY_INVERTED>;
active-low;
color = <LED_COLOR_ID_BLUE>;
};
};
};
};
&uart0 {
......
......@@ -130,7 +130,7 @@
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
riscv,ndev = <127>;
riscv,ndev = <133>;
};
clkgen: clock-controller@11800000 {
......
......@@ -27,6 +27,23 @@ static bool errata_probe_pbmt(unsigned int stage,
return false;
}
static bool errata_probe_cmo(unsigned int stage,
unsigned long arch_id, unsigned long impid)
{
#ifdef CONFIG_ERRATA_THEAD_CMO
if (arch_id != 0 || impid != 0)
return false;
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
return false;
riscv_noncoherent_supported();
return true;
#else
return false;
#endif
}
static u32 thead_errata_probe(unsigned int stage,
unsigned long archid, unsigned long impid)
{
......@@ -35,6 +52,9 @@ static u32 thead_errata_probe(unsigned int stage,
if (errata_probe_pbmt(stage, archid, impid))
cpu_req_errata |= (1U << ERRATA_THEAD_PBMT);
if (errata_probe_cmo(stage, archid, impid))
cpu_req_errata |= (1U << ERRATA_THEAD_CMO);
return cpu_req_errata;
}
......
......@@ -11,6 +11,10 @@
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
#ifdef CONFIG_RISCV_DMA_NONCOHERENT
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
#endif
/*
* RISC-V requires the stack pointer to be 16-byte aligned, so ensure that
* the flat loader aligns it accordingly.
......
......@@ -42,6 +42,16 @@ void flush_icache_mm(struct mm_struct *mm, bool local);
#endif /* CONFIG_SMP */
#ifdef CONFIG_RISCV_ISA_ZICBOM
void riscv_init_cbom_blocksize(void);
#else
static inline void riscv_init_cbom_blocksize(void) { }
#endif
#ifdef CONFIG_RISCV_DMA_NONCOHERENT
void riscv_noncoherent_supported(void);
#endif
/*
* Bits in sys_riscv_flush_icache()'s flags argument.
*/
......
......@@ -38,6 +38,7 @@ struct cpu_operations {
#endif
};
extern const struct cpu_operations cpu_ops_spinwait;
extern const struct cpu_operations *cpu_ops[NR_CPUS];
void __init cpu_set_ops(int cpu);
......
......@@ -10,6 +10,8 @@
#include <linux/sched.h>
#include <linux/threads.h>
extern const struct cpu_operations cpu_ops_sbi;
/**
* struct sbi_hart_boot_data - Hart specific boot used during booting and
* cpu hotplug.
......
......@@ -247,6 +247,9 @@
#define CSR_SIP 0x144
#define CSR_SATP 0x180
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
#define CSR_VSTVEC 0x205
......@@ -256,6 +259,8 @@
#define CSR_VSTVAL 0x243
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
#define CSR_VSTIMECMP 0x24D
#define CSR_VSTIMECMPH 0x25D
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
......
......@@ -16,11 +16,13 @@
#ifdef CONFIG_ERRATA_THEAD
#define ERRATA_THEAD_PBMT 0
#define ERRATA_THEAD_NUMBER 1
#define ERRATA_THEAD_CMO 1
#define ERRATA_THEAD_NUMBER 2
#endif
#define CPUFEATURE_SVPBMT 0
#define CPUFEATURE_NUMBER 1
#define CPUFEATURE_ZICBOM 1
#define CPUFEATURE_NUMBER 2
#ifdef __ASSEMBLY__
......@@ -87,6 +89,59 @@ asm volatile(ALTERNATIVE( \
#define ALT_THEAD_PMA(_val)
#endif
/*
* dcache.ipa rs1 (invalidate, physical address)
* | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
* 0000001 01010 rs1 000 00000 0001011
* dache.iva rs1 (invalida, virtual address)
* 0000001 00110 rs1 000 00000 0001011
*
* dcache.cpa rs1 (clean, physical address)
* | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
* 0000001 01001 rs1 000 00000 0001011
* dcache.cva rs1 (clean, virtual address)
* 0000001 00100 rs1 000 00000 0001011
*
* dcache.cipa rs1 (clean then invalidate, physical address)
* | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
* 0000001 01011 rs1 000 00000 0001011
* dcache.civa rs1 (... virtual address)
* 0000001 00111 rs1 000 00000 0001011
*
* sync.s (make sure all cache operations finished)
* | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
* 0000000 11001 00000 000 00000 0001011
*/
#define THEAD_inval_A0 ".long 0x0265000b"
#define THEAD_clean_A0 ".long 0x0245000b"
#define THEAD_flush_A0 ".long 0x0275000b"
#define THEAD_SYNC_S ".long 0x0190000b"
#define ALT_CMO_OP(_op, _start, _size, _cachesize) \
asm volatile(ALTERNATIVE_2( \
__nops(6), \
"mv a0, %1\n\t" \
"j 2f\n\t" \
"3:\n\t" \
"cbo." __stringify(_op) " (a0)\n\t" \
"add a0, a0, %0\n\t" \
"2:\n\t" \
"bltu a0, %2, 3b\n\t" \
"nop", 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \
"mv a0, %1\n\t" \
"j 2f\n\t" \
"3:\n\t" \
THEAD_##_op##_A0 "\n\t" \
"add a0, a0, %0\n\t" \
"2:\n\t" \
"bltu a0, %2, 3b\n\t" \
THEAD_SYNC_S, THEAD_VENDOR_ID, \
ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \
: : "r"(_cachesize), \
"r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \
"r"((unsigned long)(_start) + (_size)) \
: "a0")
#endif /* __ASSEMBLY__ */
#endif
......@@ -8,6 +8,7 @@
#ifndef _ASM_RISCV_HWCAP_H
#define _ASM_RISCV_HWCAP_H
#include <asm/errno.h>
#include <linux/bits.h>
#include <uapi/asm/hwcap.h>
......@@ -54,6 +55,9 @@ extern unsigned long elf_hwcap;
enum riscv_isa_ext_id {
RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE,
RISCV_ISA_EXT_SVPBMT,
RISCV_ISA_EXT_ZICBOM,
RISCV_ISA_EXT_ZIHINTPAUSE,
RISCV_ISA_EXT_SSTC,
RISCV_ISA_EXT_ID_MAX = RISCV_ISA_EXT_MAX,
};
......@@ -64,6 +68,7 @@ enum riscv_isa_ext_id {
*/
enum riscv_isa_ext_key {
RISCV_ISA_EXT_KEY_FPU, /* For 'F' and 'D' */
RISCV_ISA_EXT_KEY_ZIHINTPAUSE,
RISCV_ISA_EXT_KEY_MAX,
};
......@@ -83,6 +88,8 @@ static __always_inline int riscv_isa_ext2key(int num)
return RISCV_ISA_EXT_KEY_FPU;
case RISCV_ISA_EXT_d:
return RISCV_ISA_EXT_KEY_FPU;
case RISCV_ISA_EXT_ZIHINTPAUSE:
return RISCV_ISA_EXT_KEY_ZIHINTPAUSE;
default:
return -EINVAL;
}
......
......@@ -28,6 +28,11 @@ struct kvm_vcpu_timer {
u64 next_cycles;
/* Underlying hrtimer instance */
struct hrtimer hrt;
/* Flag to check if sstc is enabled or not */
bool sstc_enabled;
/* A function pointer to switch between stimecmp or hrtimer at runtime */
int (*timer_next_event)(struct kvm_vcpu *vcpu, u64 ncycles);
};
int kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles);
......@@ -40,5 +45,7 @@ int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu);
int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu);
void kvm_riscv_guest_timer_init(struct kvm *kvm);
void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu);
bool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu);
#endif
......@@ -122,7 +122,21 @@ enum sbi_ext_pmu_fid {
SBI_EXT_PMU_COUNTER_FW_READ,
};
#define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(55, 0)
union sbi_pmu_ctr_info {
unsigned long value;
struct {
unsigned long csr:12;
unsigned long width:6;
#if __riscv_xlen == 32
unsigned long reserved:13;
#else
unsigned long reserved:45;
#endif
unsigned long type:1;
};
};
#define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0)
#define RISCV_PMU_RAW_EVENT_IDX 0x20000
/** General pmu event codes specified in SBI PMU extension */
......@@ -189,12 +203,26 @@ enum sbi_pmu_ctr_type {
SBI_PMU_CTR_TYPE_FW,
};
/* Helper macros to decode event idx */
#define SBI_PMU_EVENT_IDX_OFFSET 20
#define SBI_PMU_EVENT_IDX_MASK 0xFFFFF
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
#define SBI_PMU_EVENT_IDX_TYPE_MASK 0xF0000
#define SBI_PMU_EVENT_RAW_IDX 0x20000
#define SBI_PMU_FIXED_CTR_MASK 0x07
#define SBI_PMU_EVENT_CACHE_ID_CODE_MASK 0xFFF8
#define SBI_PMU_EVENT_CACHE_OP_ID_CODE_MASK 0x06
#define SBI_PMU_EVENT_CACHE_RESULT_ID_CODE_MASK 0x01
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
/* Flags defined for config matching function */
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
#define SBI_PMU_CFG_FLAG_AUTO_START (1 << 2)
#define SBI_PMU_CFG_FLAG_SET_VUINH (1 << 3)
#define SBI_PMU_CFG_FLAG_SET_VSNH (1 << 4)
#define SBI_PMU_CFG_FLAG_SET_VSINH (1 << 4)
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
......
......@@ -4,15 +4,30 @@
#ifndef __ASSEMBLY__
#include <linux/jump_label.h>
#include <asm/barrier.h>
#include <asm/hwcap.h>
static inline void cpu_relax(void)
{
if (!static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_ZIHINTPAUSE])) {
#ifdef __riscv_muldiv
int dummy;
/* In lieu of a halt instruction, induce a long-latency stall. */
__asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy));
int dummy;
/* In lieu of a halt instruction, induce a long-latency stall. */
__asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy));
#endif
} else {
/*
* Reduce instruction retirement.
* This assumes the PC changes.
*/
#ifdef __riscv_zihintpause
__asm__ __volatile__ ("pause");
#else
/* Encoding of the pause instruction */
__asm__ __volatile__ (".4byte 0x100000F");
#endif
}
barrier();
}
......
......@@ -97,6 +97,7 @@ enum KVM_RISCV_ISA_EXT_ID {
KVM_RISCV_ISA_EXT_I,
KVM_RISCV_ISA_EXT_M,
KVM_RISCV_ISA_EXT_SVPBMT,
KVM_RISCV_ISA_EXT_SSTC,
KVM_RISCV_ISA_EXT_MAX,
};
......
......@@ -93,6 +93,9 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid)
static struct riscv_isa_ext_data isa_ext_arr[] = {
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
__RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX),
};
......
......@@ -9,15 +9,14 @@
#include <linux/string.h>
#include <linux/sched.h>
#include <asm/cpu_ops.h>
#include <asm/cpu_ops_sbi.h>
#include <asm/sbi.h>
#include <asm/smp.h>
const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
extern const struct cpu_operations cpu_ops_sbi;
#ifdef CONFIG_RISCV_BOOT_SPINWAIT
extern const struct cpu_operations cpu_ops_spinwait;
#else
#ifndef CONFIG_RISCV_BOOT_SPINWAIT
const struct cpu_operations cpu_ops_spinwait = {
.name = "",
.cpu_prepare = NULL,
......
......@@ -11,6 +11,8 @@
#include <asm/sbi.h>
#include <asm/smp.h>
#include "head.h"
const struct cpu_operations cpu_ops_spinwait;
void *__cpu_spinwait_stack_pointer[NR_CPUS] __section(".data");
void *__cpu_spinwait_task_pointer[NR_CPUS] __section(".data");
......
......@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <asm/alternative.h>
#include <asm/cacheflush.h>
#include <asm/errata_list.h>
#include <asm/hwcap.h>
#include <asm/patch.h>
......@@ -200,6 +201,9 @@ void __init riscv_fill_hwcap(void)
} else {
SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM);
SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE);
SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
}
#undef SET_ISA_EXT_MAP
}
......@@ -261,6 +265,25 @@ static bool __init_or_module cpufeature_probe_svpbmt(unsigned int stage)
return false;
}
static bool __init_or_module cpufeature_probe_zicbom(unsigned int stage)
{
#ifdef CONFIG_RISCV_ISA_ZICBOM
switch (stage) {
case RISCV_ALTERNATIVES_EARLY_BOOT:
return false;
default:
if (riscv_isa_extension_available(NULL, ZICBOM)) {
riscv_noncoherent_supported();
return true;
} else {
return false;
}
}
#endif
return false;
}
/*
* Probe presence of individual extensions.
*
......@@ -275,6 +298,9 @@ static u32 __init_or_module cpufeature_probe(unsigned int stage)
if (cpufeature_probe_svpbmt(stage))
cpu_req_feature |= (1U << CPUFEATURE_SVPBMT);
if (cpufeature_probe_zicbom(stage))
cpu_req_feature |= (1U << CPUFEATURE_ZICBOM);
return cpu_req_feature;
}
......
......@@ -44,7 +44,7 @@ SYM_CODE_START(riscv_crash_save_regs)
REG_S t6, PT_T6(a0) /* x31 */
csrr t1, CSR_STATUS
csrr t2, CSR_EPC
auipc t2, 0x0
csrr t3, CSR_TVAL
csrr t4, CSR_CAUSE
......
......@@ -138,19 +138,37 @@ void machine_shutdown(void)
#endif
}
/* Override the weak function in kernel/panic.c */
void crash_smp_send_stop(void)
{
static int cpus_stopped;
/*
* This function can be called twice in panic path, but obviously
* we execute this only once.
*/
if (cpus_stopped)
return;
smp_send_stop();
cpus_stopped = 1;
}
/*
* machine_crash_shutdown - Prepare to kexec after a kernel crash
*
* This function is called by crash_kexec just before machine_kexec
* below and its goal is similar to machine_shutdown, but in case of
* a kernel crash. Since we don't handle such cases yet, this function
* is empty.
* and its goal is to shutdown non-crashing cpus and save registers.
*/
void
machine_crash_shutdown(struct pt_regs *regs)
{
local_irq_disable();
/* shutdown non-crashing cpus */
crash_smp_send_stop();
crash_save_cpu(regs, smp_processor_id());
machine_shutdown();
pr_info("Starting crashdump kernel...\n");
}
......@@ -171,7 +189,7 @@ machine_kexec(struct kimage *image)
struct kimage_arch *internal = &image->arch;
unsigned long jump_addr = (unsigned long) image->start;
unsigned long first_ind_entry = (unsigned long) &image->head;
unsigned long this_cpu_id = smp_processor_id();
unsigned long this_cpu_id = __smp_processor_id();
unsigned long this_hart_id = cpuid_to_hartid_map(this_cpu_id);
unsigned long fdt_addr = internal->fdt_addr;
void *control_code_buffer = page_address(image->control_code_page);
......
......@@ -59,8 +59,6 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
instruction_pointer_set(regs, utask->xol_vaddr);
regs->status &= ~SR_SPIE;
return 0;
}
......@@ -72,8 +70,6 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
regs->status |= SR_SPIE;
return 0;
}
......@@ -111,8 +107,6 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
* address.
*/
instruction_pointer_set(regs, utask->vaddr);
regs->status &= ~SR_SPIE;
}
bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
......
......@@ -22,6 +22,7 @@
#include <linux/crash_dump.h>
#include <asm/alternative.h>
#include <asm/cacheflush.h>
#include <asm/cpu_ops.h>
#include <asm/early_ioremap.h>
#include <asm/pgtable.h>
......@@ -296,6 +297,7 @@ void __init setup_arch(char **cmdline_p)
#endif
riscv_fill_hwcap();
riscv_init_cbom_blocksize();
apply_boot_alternatives();
}
......
......@@ -7,6 +7,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/stringify.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
......@@ -150,9 +151,6 @@
#define PRECISION_S 0
#define PRECISION_D 1
#define STR(x) XSTR(x)
#define XSTR(x) #x
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
static inline type load_##type(const type *addr) \
{ \
......@@ -207,9 +205,9 @@ static inline ulong get_insn(ulong mepc)
asm ("and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
#if defined(CONFIG_64BIT)
STR(LWU) " %[insn], (%[addr])\n"
__stringify(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
__stringify(LW) " %[insn], (%[addr])\n"
#endif
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
......
......@@ -52,6 +52,7 @@ static const unsigned long kvm_isa_ext_arr[] = {
RISCV_ISA_EXT_i,
RISCV_ISA_EXT_m,
RISCV_ISA_EXT_SVPBMT,
RISCV_ISA_EXT_SSTC,
};
static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext)
......@@ -85,6 +86,7 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext)
case KVM_RISCV_ISA_EXT_C:
case KVM_RISCV_ISA_EXT_I:
case KVM_RISCV_ISA_EXT_M:
case KVM_RISCV_ISA_EXT_SSTC:
return false;
default:
break;
......@@ -203,7 +205,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
return kvm_riscv_vcpu_has_interrupts(vcpu, 1UL << IRQ_VS_TIMER);
return kvm_riscv_vcpu_timer_pending(vcpu);
}
void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
......@@ -785,6 +787,8 @@ static void kvm_riscv_vcpu_update_config(const unsigned long *isa)
if (__riscv_isa_extension_available(isa, RISCV_ISA_EXT_SVPBMT))
henvcfg |= ENVCFG_PBMTE;
if (__riscv_isa_extension_available(isa, RISCV_ISA_EXT_SSTC))
henvcfg |= ENVCFG_STCE;
csr_write(CSR_HENVCFG, henvcfg);
#ifdef CONFIG_32BIT
csr_write(CSR_HENVCFGH, henvcfg >> 32);
......@@ -828,6 +832,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
vcpu->arch.isa);
kvm_riscv_vcpu_host_fp_restore(&vcpu->arch.host_context);
kvm_riscv_vcpu_timer_save(vcpu);
csr->vsstatus = csr_read(CSR_VSSTATUS);
csr->vsie = csr_read(CSR_VSIE);
csr->vstvec = csr_read(CSR_VSTVEC);
......
......@@ -69,7 +69,18 @@ static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t)
return 0;
}
int kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles)
static int kvm_riscv_vcpu_update_vstimecmp(struct kvm_vcpu *vcpu, u64 ncycles)
{
#if defined(CONFIG_32BIT)
csr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF);
csr_write(CSR_VSTIMECMPH, ncycles >> 32);
#else
csr_write(CSR_VSTIMECMP, ncycles);
#endif
return 0;
}
static int kvm_riscv_vcpu_update_hrtimer(struct kvm_vcpu *vcpu, u64 ncycles)
{
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer;
......@@ -88,6 +99,65 @@ int kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles)
return 0;
}
int kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles)
{
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
return t->timer_next_event(vcpu, ncycles);
}
static enum hrtimer_restart kvm_riscv_vcpu_vstimer_expired(struct hrtimer *h)
{
u64 delta_ns;
struct kvm_vcpu_timer *t = container_of(h, struct kvm_vcpu_timer, hrt);
struct kvm_vcpu *vcpu = container_of(t, struct kvm_vcpu, arch.timer);
struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer;
if (kvm_riscv_current_cycles(gt) < t->next_cycles) {
delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t);
hrtimer_forward_now(&t->hrt, ktime_set(0, delta_ns));
return HRTIMER_RESTART;
}
t->next_set = false;
kvm_vcpu_kick(vcpu);
return HRTIMER_NORESTART;
}
bool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer;
if (!kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t) ||
kvm_riscv_vcpu_has_interrupts(vcpu, 1UL << IRQ_VS_TIMER))
return true;
else
return false;
}
static void kvm_riscv_vcpu_timer_blocking(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer;
u64 delta_ns;
if (!t->init_done)
return;
delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t);
if (delta_ns) {
hrtimer_start(&t->hrt, ktime_set(0, delta_ns), HRTIMER_MODE_REL);
t->next_set = true;
}
}
static void kvm_riscv_vcpu_timer_unblocking(struct kvm_vcpu *vcpu)
{
kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer);
}
int kvm_riscv_vcpu_get_reg_timer(struct kvm_vcpu *vcpu,
const struct kvm_one_reg *reg)
{
......@@ -180,10 +250,20 @@ int kvm_riscv_vcpu_timer_init(struct kvm_vcpu *vcpu)
return -EINVAL;
hrtimer_init(&t->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
t->hrt.function = kvm_riscv_vcpu_hrtimer_expired;
t->init_done = true;
t->next_set = false;
/* Enable sstc for every vcpu if available in hardware */
if (riscv_isa_extension_available(NULL, SSTC)) {
t->sstc_enabled = true;
t->hrt.function = kvm_riscv_vcpu_vstimer_expired;
t->timer_next_event = kvm_riscv_vcpu_update_vstimecmp;
} else {
t->sstc_enabled = false;
t->hrt.function = kvm_riscv_vcpu_hrtimer_expired;
t->timer_next_event = kvm_riscv_vcpu_update_hrtimer;
}
return 0;
}
......@@ -199,21 +279,73 @@ int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu)
int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
t->next_cycles = -1ULL;
return kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer);
}
void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
static void kvm_riscv_vcpu_update_timedelta(struct kvm_vcpu *vcpu)
{
struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer;
#ifdef CONFIG_64BIT
csr_write(CSR_HTIMEDELTA, gt->time_delta);
#else
#if defined(CONFIG_32BIT)
csr_write(CSR_HTIMEDELTA, (u32)(gt->time_delta));
csr_write(CSR_HTIMEDELTAH, (u32)(gt->time_delta >> 32));
#else
csr_write(CSR_HTIMEDELTA, gt->time_delta);
#endif
}
void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_csr *csr;
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
kvm_riscv_vcpu_update_timedelta(vcpu);
if (!t->sstc_enabled)
return;
csr = &vcpu->arch.guest_csr;
#if defined(CONFIG_32BIT)
csr_write(CSR_VSTIMECMP, (u32)t->next_cycles);
csr_write(CSR_VSTIMECMPH, (u32)(t->next_cycles >> 32));
#else
csr_write(CSR_VSTIMECMP, t->next_cycles);
#endif
/* timer should be enabled for the remaining operations */
if (unlikely(!t->init_done))
return;
kvm_riscv_vcpu_timer_unblocking(vcpu);
}
void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_csr *csr;
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
if (!t->sstc_enabled)
return;
csr = &vcpu->arch.guest_csr;
t = &vcpu->arch.timer;
#if defined(CONFIG_32BIT)
t->next_cycles = csr_read(CSR_VSTIMECMP);
t->next_cycles |= (u64)csr_read(CSR_VSTIMECMPH) << 32;
#else
t->next_cycles = csr_read(CSR_VSTIMECMP);
#endif
/* timer should be enabled for the remaining operations */
if (unlikely(!t->init_done))
return;
if (kvm_vcpu_is_blocking(vcpu))
kvm_riscv_vcpu_timer_blocking(vcpu);
}
void kvm_riscv_guest_timer_init(struct kvm *kvm)
{
struct kvm_guest_timer *gt = &kvm->arch.timer;
......
......@@ -175,7 +175,7 @@ ENTRY(__asm_copy_from_user)
/* Exception fixup code */
10:
/* Disable access to user memory */
csrs CSR_STATUS, t6
csrc CSR_STATUS, t6
mv a0, t5
ret
ENDPROC(__asm_copy_to_user)
......@@ -227,7 +227,7 @@ ENTRY(__clear_user)
/* Exception fixup code */
11:
/* Disable access to user memory */
csrs CSR_STATUS, t6
csrc CSR_STATUS, t6
mv a0, a1
ret
ENDPROC(__clear_user)
......
......@@ -30,3 +30,4 @@ endif
endif
obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
obj-$(CONFIG_RISCV_DMA_NONCOHERENT) += dma-noncoherent.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* RISC-V specific functions to support DMA for non-coherent devices
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*/
#include <linux/dma-direct.h>
#include <linux/dma-map-ops.h>
#include <linux/mm.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <asm/cacheflush.h>
static unsigned int riscv_cbom_block_size = L1_CACHE_BYTES;
static bool noncoherent_supported;
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
enum dma_data_direction dir)
{
void *vaddr = phys_to_virt(paddr);
switch (dir) {
case DMA_TO_DEVICE:
ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size);
break;
case DMA_FROM_DEVICE:
ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size);
break;
case DMA_BIDIRECTIONAL:
ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size);
break;
default:
break;
}
}
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
enum dma_data_direction dir)
{
void *vaddr = phys_to_virt(paddr);
switch (dir) {
case DMA_TO_DEVICE:
break;
case DMA_FROM_DEVICE:
case DMA_BIDIRECTIONAL:
ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size);
break;
default:
break;
}
}
void arch_dma_prep_coherent(struct page *page, size_t size)
{
void *flush_addr = page_address(page);
ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size);
}
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu, bool coherent)
{
WARN_TAINT(!coherent && riscv_cbom_block_size > ARCH_DMA_MINALIGN,
TAINT_CPU_OUT_OF_SPEC,
"%s %s: ARCH_DMA_MINALIGN smaller than riscv,cbom-block-size (%d < %d)",
dev_driver_string(dev), dev_name(dev),
ARCH_DMA_MINALIGN, riscv_cbom_block_size);
WARN_TAINT(!coherent && !noncoherent_supported, TAINT_CPU_OUT_OF_SPEC,
"%s %s: device non-coherent but no non-coherent operations supported",
dev_driver_string(dev), dev_name(dev));
dev->dma_coherent = coherent;
}
#ifdef CONFIG_RISCV_ISA_ZICBOM
void riscv_init_cbom_blocksize(void)
{
struct device_node *node;
int ret;
u32 val;
for_each_of_cpu_node(node) {
unsigned long hartid;
int cbom_hartid;
ret = riscv_of_processor_hartid(node, &hartid);
if (ret)
continue;
if (hartid < 0)
continue;
/* set block-size for cbom extension if available */
ret = of_property_read_u32(node, "riscv,cbom-block-size", &val);
if (ret)
continue;
if (!riscv_cbom_block_size) {
riscv_cbom_block_size = val;
cbom_hartid = hartid;
} else {
if (riscv_cbom_block_size != val)
pr_warn("cbom-block-size mismatched between harts %d and %lu\n",
cbom_hartid, hartid);
}
}
}
#endif
void riscv_noncoherent_supported(void)
{
noncoherent_supported = true;
}
......@@ -135,6 +135,10 @@ static void __init print_vm_layout(void)
(unsigned long)VMEMMAP_END);
print_ml("vmalloc", (unsigned long)VMALLOC_START,
(unsigned long)VMALLOC_END);
#ifdef CONFIG_64BIT
print_ml("modules", (unsigned long)MODULES_VADDR,
(unsigned long)MODULES_END);
#endif
print_ml("lowmem", (unsigned long)PAGE_OFFSET,
(unsigned long)high_memory);
if (IS_ENABLED(CONFIG_64BIT)) {
......
# SPDX-License-Identifier: GPL-2.0-only
purgatory.chk
purgatory.ro
kexec-purgatory.c
......@@ -84,12 +84,6 @@ $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
$(obj)/purgatory.chk: $(obj)/purgatory.ro FORCE
$(call if_changed,ld)
targets += kexec-purgatory.c
$(obj)/kexec-purgatory.o: $(obj)/purgatory.ro $(obj)/purgatory.chk
quiet_cmd_bin2c = BIN2C $@
cmd_bin2c = $(objtree)/scripts/bin2c kexec_purgatory < $< > $@
$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro $(obj)/purgatory.chk FORCE
$(call if_changed,bin2c)
obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) += kexec-purgatory.o
obj-y += kexec-purgatory.o
/* SPDX-License-Identifier: GPL-2.0 */
.section .rodata, "a"
.align 8
kexec_purgatory:
.globl kexec_purgatory
.incbin "arch/riscv/purgatory/purgatory.ro"
.Lkexec_purgatroy_end:
.align 8
kexec_purgatory_size:
.globl kexec_purgatory_size
.quad .Lkexec_purgatroy_end - kexec_purgatory
......@@ -7,6 +7,9 @@
* either be read from the "time" and "timeh" CSRs, and can use the SBI to
* setup events, or directly accessed using MMIO registers.
*/
#define pr_fmt(fmt) "riscv-timer: " fmt
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
......@@ -20,14 +23,28 @@
#include <linux/of_irq.h>
#include <clocksource/timer-riscv.h>
#include <asm/smp.h>
#include <asm/hwcap.h>
#include <asm/sbi.h>
#include <asm/timex.h>
static DEFINE_STATIC_KEY_FALSE(riscv_sstc_available);
static int riscv_clock_next_event(unsigned long delta,
struct clock_event_device *ce)
{
u64 next_tval = get_cycles64() + delta;
csr_set(CSR_IE, IE_TIE);
sbi_set_timer(get_cycles64() + delta);
if (static_branch_likely(&riscv_sstc_available)) {
#if defined(CONFIG_32BIT)
csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF);
csr_write(CSR_STIMECMPH, next_tval >> 32);
#else
csr_write(CSR_STIMECMP, next_tval);
#endif
} else
sbi_set_timer(next_tval);
return 0;
}
......@@ -166,6 +183,12 @@ static int __init riscv_timer_init_dt(struct device_node *n)
if (error)
pr_err("cpu hp setup state failed for RISCV timer [%d]\n",
error);
if (riscv_isa_extension_available(NULL, SSTC)) {
pr_info("Timer interrupt in S-mode is available via sstc extension\n");
static_branch_enable(&riscv_sstc_available);
}
return error;
}
......
......@@ -1045,26 +1045,29 @@ phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np)
*
* It returns true if "dma-coherent" property was found
* for this device in the DT, or if DMA is coherent by
* default for OF devices on the current platform.
* default for OF devices on the current platform and no
* "dma-noncoherent" property was found for this device.
*/
bool of_dma_is_coherent(struct device_node *np)
{
struct device_node *node;
if (IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT))
return true;
bool is_coherent = IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT);
node = of_node_get(np);
while (node) {
if (of_property_read_bool(node, "dma-coherent")) {
of_node_put(node);
return true;
is_coherent = true;
break;
}
if (of_property_read_bool(node, "dma-noncoherent")) {
is_coherent = false;
break;
}
node = of_get_next_dma_parent(node);
}
of_node_put(node);
return false;
return is_coherent;
}
EXPORT_SYMBOL_GPL(of_dma_is_coherent);
......
......@@ -170,7 +170,6 @@ int riscv_pmu_event_set_period(struct perf_event *event)
left = (max_period >> 1);
local64_set(&hwc->prev_count, (u64)-left);
perf_event_update_userpage(event);
return overflow;
}
......
......@@ -41,20 +41,6 @@ static const struct attribute_group *riscv_pmu_attr_groups[] = {
NULL,
};
union sbi_pmu_ctr_info {
unsigned long value;
struct {
unsigned long csr:12;
unsigned long width:6;
#if __riscv_xlen == 32
unsigned long reserved:13;
#else
unsigned long reserved:45;
#endif
unsigned long type:1;
};
};
/*
* RISC-V doesn't have hetergenous harts yet. This need to be part of
* per_cpu in case of harts with different pmu counters
......@@ -294,8 +280,13 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
cflags |= SBI_PMU_CFG_FLAG_SET_UINH;
/* retrieve the available counter index */
#if defined(CONFIG_32BIT)
ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, cmask,
cflags, hwc->event_base, hwc->config, hwc->config >> 32);
#else
ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, cmask,
cflags, hwc->event_base, hwc->config, 0);
#endif
if (ret.error) {
pr_debug("Not able to find a counter for event %lx config %llx\n",
hwc->event_base, hwc->config);
......@@ -437,8 +428,13 @@ static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival)
struct hw_perf_event *hwc = &event->hw;
unsigned long flag = SBI_PMU_START_FLAG_SET_INIT_VALUE;
#if defined(CONFIG_32BIT)
ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, hwc->idx,
1, flag, ival, ival >> 32, 0);
#else
ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, hwc->idx,
1, flag, ival, 0, 0);
#endif
if (ret.error && (ret.error != SBI_ERR_ALREADY_STARTED))
pr_err("Starting counter idx %d failed with error %d\n",
hwc->idx, sbi_err_map_linux_errno(ret.error));
......@@ -545,8 +541,14 @@ static inline void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
hwc = &event->hw;
max_period = riscv_pmu_ctr_get_width_mask(event);
init_val = local64_read(&hwc->prev_count) & max_period;
#if defined(CONFIG_32BIT)
sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1,
flag, init_val, init_val >> 32, 0);
#else
sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1,
flag, init_val, 0, 0);
#endif
perf_event_update_userpage(event);
}
ctr_ovf_mask = ctr_ovf_mask >> 1;
idx++;
......
......@@ -42,6 +42,8 @@ if [ -n "${building_out_of_srctree}" ]; then
done
fi
rm -f arch/riscv/purgatory/kexec-purgatory.c
rm -f scripts/extract-cert
rm -f arch/x86/purgatory/kexec-purgatory.c
CONFIG_NONPORTABLE=y
CONFIG_ARCH_RV32I=y
CONFIG_MMU=y
CONFIG_FPU=y
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册