forked from Minki/linux
RISC-V Patches for the 6.1 Merge Window, Part 2
* A handful of DT updates for the PolarFire SOC. * A fix to correct the handling of write-only mappings. * m{vetndor,arcd,imp}id is now in /proc/cpuinfo * The SiFive L2 cache controller support has been refactored to also support L3 caches. There's also a handful of fixes, cleanups and improvements throughout the tree. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmNJiegTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYiaW+D/9nN7JMKD4KbED8MUgRVcs+TS4MQk5J QkjmAXme7w2H1+T5mxNWHk0QvEC6qMu2JQWHeott0ROYPkbXoNtuOOkzcsZhVaeb rjWH/WC5QhEeMPDc1qc0AmxVkOa937f2NkGtoEvhW6SMWvStHpefdOHo/ij106Re 7wxkcj0fjgn/zPmDltRbWSMyFZWJec5DvZ3AB4NYHnc2ycr8Z7HAG08rjZkdkIjQ zYGsCkUtrk4qShikKK3cSelW6hH1/FdM+bAo0rzt1frmTw1FLaFOsZZjOaVYekzi l0jxsb8FRBWyKBFqcagukjZwFy6D+7Q+masb0cXY03eZpEVrroA4bHiPkuZ22Ms/ 7ol/I5FvTyrj2R4zd70ziYVF3usO78t5HC4AIQmFl25TNcQdYQd8X28yh12iG6QN Pa0lh/EOr5idaT2+TErhzRepICnK1Nj9y0H5TZxYljLAhH9j0d/8+Iw88vzJnPga vek7unZ3BzkooLVIpfpkT8vC94MA0hoP849MVFQDtZgZhPMbjIkN91HrDiw9ktV2 SK9cuPndfrs5nW1WKu8F0cDziusbMHv4F51TPVRu/dFcIkspv+aLojAThgvcm42K 55LgvDgLjo7P3PUghiDXUoPZXvL19t5Bnq2/E47rlSTvvGssIu/onZO6BkxybAm6 BkHuchr8TGBWMg== =iCOr -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-6.1-mw2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux Pull more RISC-V updates from Palmer Dabbelt: - DT updates for the PolarFire SOC - a fix to correct the handling of write-only mappings - m{vetndor,arcd,imp}id is now in /proc/cpuinfo - the SiFive L2 cache controller support has been refactored to also support L3 caches - misc fixes, cleanups and improvements throughout the tree * tag 'riscv-for-linus-6.1-mw2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: (42 commits) MAINTAINERS: add RISC-V's patchwork RISC-V: Make port I/O string accessors actually work riscv: enable software resend of irqs RISC-V: Re-enable counter access from userspace riscv: vdso: fix NULL deference in vdso_join_timens() when vfork riscv: Add cache information in AUX vector soc: sifive: ccache: define the macro for the register shifts soc: sifive: ccache: use pr_fmt() to remove CCACHE: prefixes soc: sifive: ccache: reduce printing on init soc: sifive: ccache: determine the cache level from dts soc: sifive: ccache: Rename SiFive L2 cache to Composable cache. dt-bindings: sifive-ccache: change Sifive L2 cache to Composable cache riscv: check for kernel config option in t-head memory types errata riscv: use BIT() marco for cpufeature probing riscv: use BIT() macros in t-head errata init riscv: drop some idefs from CMO initialization riscv: cleanup svpbmt cpufeature probing riscv: Pass -mno-relax only on lld < 15.0.0 RISC-V: Avoid dereferening NULL regs in die() dt-bindings: riscv: add new riscv,isa strings for emulators ...
This commit is contained in:
commit
498574970f
@ -66,6 +66,11 @@ properties:
|
||||
- enum:
|
||||
- allwinner,sun20i-d1-plic
|
||||
- const: thead,c900-plic
|
||||
- items:
|
||||
- const: sifive,plic-1.0.0
|
||||
- const: riscv,plic0
|
||||
deprecated: true
|
||||
description: For the QEMU virt machine only
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -9,6 +9,7 @@ title: RISC-V bindings for 'cpus' DT nodes
|
||||
maintainers:
|
||||
- Paul Walmsley <paul.walmsley@sifive.com>
|
||||
- Palmer Dabbelt <palmer@sifive.com>
|
||||
- Conor Dooley <conor@kernel.org>
|
||||
|
||||
description: |
|
||||
This document uses some terminology common to the RISC-V community
|
||||
@ -79,9 +80,7 @@ properties:
|
||||
insensitive, letters in the riscv,isa string must be all
|
||||
lowercase to simplify parsing.
|
||||
$ref: "/schemas/types.yaml#/definitions/string"
|
||||
enum:
|
||||
- rv64imac
|
||||
- rv64imafdc
|
||||
pattern: ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$
|
||||
|
||||
# RISC-V requires 'timebase-frequency' in /cpus, so disallow it here
|
||||
timebase-frequency: false
|
||||
|
@ -7,8 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Microchip PolarFire SoC-based boards
|
||||
|
||||
maintainers:
|
||||
- Cyril Jean <Cyril.Jean@microchip.com>
|
||||
- Lewis Hanly <lewis.hanly@microchip.com>
|
||||
- Conor Dooley <conor.dooley@microchip.com>
|
||||
- Daire McNamara <daire.mcnamara@microchip.com>
|
||||
|
||||
description:
|
||||
Microchip PolarFire SoC-based boards
|
||||
@ -17,12 +17,20 @@ properties:
|
||||
$nodename:
|
||||
const: '/'
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- microchip,mpfs-icicle-kit
|
||||
- microchip,mpfs-icicle-reference-rtlv2203
|
||||
- sundance,polarberry
|
||||
- const: microchip,mpfs
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- microchip,mpfs-icicle-reference-rtlv2203
|
||||
- microchip,mpfs-icicle-reference-rtlv2210
|
||||
- const: microchip,mpfs-icicle-kit
|
||||
- const: microchip,mpfs
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- aries,m100pfsevp
|
||||
- microchip,mpfs-sev-kit
|
||||
- sundance,polarberry
|
||||
- const: microchip,mpfs
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
|
@ -2,18 +2,18 @@
|
||||
# Copyright (C) 2020 SiFive, Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/riscv/sifive-l2-cache.yaml#
|
||||
$id: http://devicetree.org/schemas/riscv/sifive,ccache0.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SiFive L2 Cache Controller
|
||||
title: SiFive Composable Cache Controller
|
||||
|
||||
maintainers:
|
||||
- Sagar Kadam <sagar.kadam@sifive.com>
|
||||
- Paul Walmsley <paul.walmsley@sifive.com>
|
||||
|
||||
description:
|
||||
The SiFive Level 2 Cache Controller is used to provide access to fast copies
|
||||
of memory for masters in a Core Complex. The Level 2 Cache Controller also
|
||||
The SiFive Composable Cache Controller is used to provide access to fast copies
|
||||
of memory for masters in a Core Complex. The Composable Cache Controller also
|
||||
acts as directory-based coherency manager.
|
||||
All the properties in ePAPR/DeviceTree specification applies for this platform.
|
||||
|
||||
@ -22,6 +22,7 @@ select:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- sifive,ccache0
|
||||
- sifive,fu540-c000-ccache
|
||||
- sifive,fu740-c000-ccache
|
||||
|
||||
@ -33,6 +34,7 @@ properties:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- sifive,ccache0
|
||||
- sifive,fu540-c000-ccache
|
||||
- sifive,fu740-c000-ccache
|
||||
- const: cache
|
||||
@ -45,7 +47,7 @@ properties:
|
||||
const: 64
|
||||
|
||||
cache-level:
|
||||
const: 2
|
||||
enum: [2, 3]
|
||||
|
||||
cache-sets:
|
||||
enum: [1024, 2048]
|
||||
@ -115,6 +117,22 @@ allOf:
|
||||
cache-sets:
|
||||
const: 1024
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: sifive,ccache0
|
||||
|
||||
then:
|
||||
properties:
|
||||
cache-level:
|
||||
enum: [2, 3]
|
||||
|
||||
else:
|
||||
properties:
|
||||
cache-level:
|
||||
const: 2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
@ -22,12 +22,18 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- sifive,fu540-c000-clint
|
||||
- starfive,jh7100-clint
|
||||
- canaan,k210-clint
|
||||
- const: sifive,clint0
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- sifive,fu540-c000-clint
|
||||
- starfive,jh7100-clint
|
||||
- canaan,k210-clint
|
||||
- const: sifive,clint0
|
||||
- items:
|
||||
- const: sifive,clint0
|
||||
- const: riscv,clint0
|
||||
deprecated: true
|
||||
description: For the QEMU virt machine only
|
||||
|
||||
description:
|
||||
Should be "<vendor>,<chip>-clint" and "sifive,clint<version>".
|
||||
|
@ -8,6 +8,7 @@ RISC-V architecture
|
||||
boot-image-header
|
||||
vm-layout
|
||||
patch-acceptance
|
||||
uabi
|
||||
|
||||
features
|
||||
|
||||
|
6
Documentation/riscv/uabi.rst
Normal file
6
Documentation/riscv/uabi.rst
Normal file
@ -0,0 +1,6 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
RISC-V Linux User ABI
|
||||
=====================
|
||||
|
||||
Misaligned accesses are supported in userspace, but they may perform poorly.
|
@ -17702,6 +17702,7 @@ M: Palmer Dabbelt <palmer@dabbelt.com>
|
||||
M: Albert Ou <aou@eecs.berkeley.edu>
|
||||
L: linux-riscv@lists.infradead.org
|
||||
S: Supported
|
||||
Q: https://patchwork.kernel.org/project/linux-riscv/list/
|
||||
P: Documentation/riscv/patch-acceptance.rst
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git
|
||||
F: arch/riscv/
|
||||
@ -17713,12 +17714,13 @@ M: Conor Dooley <conor.dooley@microchip.com>
|
||||
M: Daire McNamara <daire.mcnamara@microchip.com>
|
||||
L: linux-riscv@lists.infradead.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/clock/microchip,mpfs.yaml
|
||||
F: Documentation/devicetree/bindings/clock/microchip,mpfs*.yaml
|
||||
F: Documentation/devicetree/bindings/gpio/microchip,mpfs-gpio.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/microchip,corei2c.yaml
|
||||
F: Documentation/devicetree/bindings/mailbox/microchip,mpfs-mailbox.yaml
|
||||
F: Documentation/devicetree/bindings/net/can/microchip,mpfs-can.yaml
|
||||
F: Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml
|
||||
F: Documentation/devicetree/bindings/riscv/microchip.yaml
|
||||
F: Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml
|
||||
F: Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml
|
||||
F: Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
|
||||
|
@ -70,6 +70,7 @@ config RISCV
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_TIME_VSYSCALL if MMU && 64BIT
|
||||
select GENERIC_VDSO_TIME_NS if HAVE_GENERIC_VDSO
|
||||
select HARDIRQS_SW_RESEND
|
||||
select HAVE_ARCH_AUDITSYSCALL
|
||||
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
|
||||
select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
|
||||
|
@ -37,6 +37,7 @@ else
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LD_IS_LLD),y)
|
||||
ifeq ($(shell test $(CONFIG_LLD_VERSION) -lt 150000; echo $$?),0)
|
||||
KBUILD_CFLAGS += -mno-relax
|
||||
KBUILD_AFLAGS += -mno-relax
|
||||
ifndef CONFIG_AS_IS_LLVM
|
||||
@ -44,6 +45,7 @@ ifndef CONFIG_AS_IS_LLVM
|
||||
KBUILD_AFLAGS += -Wa,-mno-relax
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# ISA string setting
|
||||
riscv-march-$(CONFIG_ARCH_RV32I) := rv32ima
|
||||
|
@ -1,4 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-icicle-kit.dtb
|
||||
dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-m100pfsevp.dtb
|
||||
dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-polarberry.dtb
|
||||
dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-sev-kit.dtb
|
||||
obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y))
|
||||
|
@ -2,20 +2,21 @@
|
||||
/* Copyright (c) 2020-2021 Microchip Technology Inc */
|
||||
|
||||
/ {
|
||||
compatible = "microchip,mpfs-icicle-reference-rtlv2203", "microchip,mpfs";
|
||||
compatible = "microchip,mpfs-icicle-reference-rtlv2210", "microchip,mpfs-icicle-kit",
|
||||
"microchip,mpfs";
|
||||
|
||||
core_pwm0: pwm@41000000 {
|
||||
core_pwm0: pwm@40000000 {
|
||||
compatible = "microchip,corepwm-rtl-v4";
|
||||
reg = <0x0 0x41000000 0x0 0xF0>;
|
||||
reg = <0x0 0x40000000 0x0 0xF0>;
|
||||
microchip,sync-update-mask = /bits/ 32 <0>;
|
||||
#pwm-cells = <2>;
|
||||
clocks = <&fabric_clk3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2c2: i2c@44000000 {
|
||||
i2c2: i2c@40000200 {
|
||||
compatible = "microchip,corei2c-rtl-v7";
|
||||
reg = <0x0 0x44000000 0x0 0x1000>;
|
||||
reg = <0x0 0x40000200 0x0 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&fabric_clk3>;
|
||||
@ -28,7 +29,7 @@
|
||||
fabric_clk3: fabric-clk3 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <62500000>;
|
||||
clock-frequency = <50000000>;
|
||||
};
|
||||
|
||||
fabric_clk1: fabric-clk1 {
|
||||
@ -36,4 +37,34 @@
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <125000000>;
|
||||
};
|
||||
|
||||
pcie: pcie@3000000000 {
|
||||
compatible = "microchip,pcie-host-1.0";
|
||||
#address-cells = <0x3>;
|
||||
#interrupt-cells = <0x1>;
|
||||
#size-cells = <0x2>;
|
||||
device_type = "pci";
|
||||
reg = <0x30 0x0 0x0 0x8000000>, <0x0 0x43000000 0x0 0x10000>;
|
||||
reg-names = "cfg", "apb";
|
||||
bus-range = <0x0 0x7f>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <119>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc 0>,
|
||||
<0 0 0 2 &pcie_intc 1>,
|
||||
<0 0 0 3 &pcie_intc 2>,
|
||||
<0 0 0 4 &pcie_intc 3>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
clocks = <&fabric_clk1>, <&fabric_clk3>;
|
||||
clock-names = "fic1", "fic3";
|
||||
ranges = <0x3000000 0x0 0x8000000 0x30 0x8000000 0x0 0x80000000>;
|
||||
dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 0x1 0x00000000>;
|
||||
msi-parent = <&pcie>;
|
||||
msi-controller;
|
||||
status = "disabled";
|
||||
pcie_intc: interrupt-controller {
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -11,7 +11,8 @@
|
||||
|
||||
/ {
|
||||
model = "Microchip PolarFire-SoC Icicle Kit";
|
||||
compatible = "microchip,mpfs-icicle-kit", "microchip,mpfs";
|
||||
compatible = "microchip,mpfs-icicle-reference-rtlv2210", "microchip,mpfs-icicle-kit",
|
||||
"microchip,mpfs";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &mac1;
|
||||
@ -32,15 +33,26 @@
|
||||
|
||||
ddrc_cache_lo: memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x80000000 0x0 0x2e000000>;
|
||||
reg = <0x0 0x80000000 0x0 0x40000000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ddrc_cache_hi: memory@1000000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x10 0x0 0x0 0x40000000>;
|
||||
reg = <0x10 0x40000000 0x0 0x40000000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
hss_payload: region@BFC00000 {
|
||||
reg = <0x0 0xBFC00000 0x0 0x400000>;
|
||||
no-map;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&core_pwm0 {
|
||||
|
45
arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi
Normal file
45
arch/riscv/boot/dts/microchip/mpfs-m100pfs-fabric.dtsi
Normal file
@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Copyright (c) 2022 Microchip Technology Inc */
|
||||
|
||||
/ {
|
||||
fabric_clk3: fabric-clk3 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <62500000>;
|
||||
};
|
||||
|
||||
fabric_clk1: fabric-clk1 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <125000000>;
|
||||
};
|
||||
|
||||
pcie: pcie@2000000000 {
|
||||
compatible = "microchip,pcie-host-1.0";
|
||||
#address-cells = <0x3>;
|
||||
#interrupt-cells = <0x1>;
|
||||
#size-cells = <0x2>;
|
||||
device_type = "pci";
|
||||
reg = <0x20 0x0 0x0 0x8000000>, <0x0 0x43000000 0x0 0x10000>;
|
||||
reg-names = "cfg", "apb";
|
||||
bus-range = <0x0 0x7f>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <119>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc 0>,
|
||||
<0 0 0 2 &pcie_intc 1>,
|
||||
<0 0 0 3 &pcie_intc 2>,
|
||||
<0 0 0 4 &pcie_intc 3>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
|
||||
clock-names = "fic0", "fic1", "fic3";
|
||||
ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
|
||||
msi-parent = <&pcie>;
|
||||
msi-controller;
|
||||
status = "disabled";
|
||||
pcie_intc: interrupt-controller {
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
179
arch/riscv/boot/dts/microchip/mpfs-m100pfsevp.dts
Normal file
179
arch/riscv/boot/dts/microchip/mpfs-m100pfsevp.dts
Normal file
@ -0,0 +1,179 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Original all-in-one devicetree:
|
||||
* Copyright (C) 2021-2022 - Wolfgang Grandegger <wg@aries-embedded.de>
|
||||
* Rewritten to use includes:
|
||||
* Copyright (C) 2022 - Conor Dooley <conor.dooley@microchip.com>
|
||||
*/
|
||||
/dts-v1/;
|
||||
|
||||
#include "mpfs.dtsi"
|
||||
#include "mpfs-m100pfs-fabric.dtsi"
|
||||
|
||||
/* Clock frequency (in Hz) of the rtcclk */
|
||||
#define MTIMER_FREQ 1000000
|
||||
|
||||
/ {
|
||||
model = "Aries Embedded M100PFEVPS";
|
||||
compatible = "aries,m100pfsevp", "microchip,mpfs";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &mac0;
|
||||
ethernet1 = &mac1;
|
||||
serial0 = &mmuart0;
|
||||
serial1 = &mmuart1;
|
||||
serial2 = &mmuart2;
|
||||
serial3 = &mmuart3;
|
||||
serial4 = &mmuart4;
|
||||
gpio0 = &gpio0;
|
||||
gpio1 = &gpio2;
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial1:115200n8";
|
||||
};
|
||||
|
||||
cpus {
|
||||
timebase-frequency = <MTIMER_FREQ>;
|
||||
};
|
||||
|
||||
ddrc_cache_lo: memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x80000000 0x0 0x40000000>;
|
||||
};
|
||||
ddrc_cache_hi: memory@1040000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x10 0x40000000 0x0 0x40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&can0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
interrupts = <13>, <14>, <15>, <16>,
|
||||
<17>, <18>, <19>, <20>,
|
||||
<21>, <22>, <23>, <24>,
|
||||
<25>, <26>;
|
||||
ngpios = <14>;
|
||||
status = "okay";
|
||||
|
||||
pmic-irq-hog {
|
||||
gpio-hog;
|
||||
gpios = <13 0>;
|
||||
input;
|
||||
};
|
||||
|
||||
/* Set to low for eMMC, high for SD-card */
|
||||
mmc-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <12 0>;
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
|
||||
&gpio2 {
|
||||
interrupts = <13>, <14>, <15>, <16>,
|
||||
<17>, <18>, <19>, <20>,
|
||||
<21>, <22>, <23>, <24>,
|
||||
<25>, <26>, <27>, <28>,
|
||||
<29>, <30>, <31>, <32>,
|
||||
<33>, <34>, <35>, <36>,
|
||||
<37>, <38>, <39>, <40>,
|
||||
<41>, <42>, <43>, <44>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mac0 {
|
||||
status = "okay";
|
||||
phy-mode = "gmii";
|
||||
phy-handle = <&phy0>;
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
&mac1 {
|
||||
status = "okay";
|
||||
phy-mode = "gmii";
|
||||
phy-handle = <&phy1>;
|
||||
phy1: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
&mbox {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmc {
|
||||
max-frequency = <50000000>;
|
||||
bus-width = <4>;
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
no-1-8-v;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
sd-uhs-sdr104;
|
||||
disable-wp;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart4 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&qspi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&refclk {
|
||||
clock-frequency = <125000000>;
|
||||
};
|
||||
|
||||
&rtc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&syscontroller {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb {
|
||||
status = "okay";
|
||||
dr_mode = "host";
|
||||
};
|
@ -13,4 +13,33 @@
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <125000000>;
|
||||
};
|
||||
|
||||
pcie: pcie@2000000000 {
|
||||
compatible = "microchip,pcie-host-1.0";
|
||||
#address-cells = <0x3>;
|
||||
#interrupt-cells = <0x1>;
|
||||
#size-cells = <0x2>;
|
||||
device_type = "pci";
|
||||
reg = <0x20 0x0 0x0 0x8000000>, <0x0 0x43000000 0x0 0x10000>;
|
||||
reg-names = "cfg", "apb";
|
||||
bus-range = <0x0 0x7f>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <119>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc 0>,
|
||||
<0 0 0 2 &pcie_intc 1>,
|
||||
<0 0 0 3 &pcie_intc 2>,
|
||||
<0 0 0 4 &pcie_intc 3>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
|
||||
clock-names = "fic0", "fic1", "fic3";
|
||||
ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
|
||||
msi-parent = <&pcie>;
|
||||
msi-controller;
|
||||
status = "disabled";
|
||||
pcie_intc: interrupt-controller {
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
45
arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi
Normal file
45
arch/riscv/boot/dts/microchip/mpfs-sev-kit-fabric.dtsi
Normal file
@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Copyright (c) 2022 Microchip Technology Inc */
|
||||
|
||||
/ {
|
||||
fabric_clk3: fabric-clk3 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <0>;
|
||||
};
|
||||
|
||||
fabric_clk1: fabric-clk1 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <125000000>;
|
||||
};
|
||||
|
||||
pcie: pcie@2000000000 {
|
||||
compatible = "microchip,pcie-host-1.0";
|
||||
#address-cells = <0x3>;
|
||||
#interrupt-cells = <0x1>;
|
||||
#size-cells = <0x2>;
|
||||
device_type = "pci";
|
||||
reg = <0x20 0x0 0x0 0x8000000>, <0x0 0x43000000 0x0 0x10000>;
|
||||
reg-names = "cfg", "apb";
|
||||
bus-range = <0x0 0x7f>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <119>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc 0>,
|
||||
<0 0 0 2 &pcie_intc 1>,
|
||||
<0 0 0 3 &pcie_intc 2>,
|
||||
<0 0 0 4 &pcie_intc 3>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
|
||||
clock-names = "fic0", "fic1", "fic3";
|
||||
ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
|
||||
msi-parent = <&pcie>;
|
||||
msi-controller;
|
||||
status = "disabled";
|
||||
pcie_intc: interrupt-controller {
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
145
arch/riscv/boot/dts/microchip/mpfs-sev-kit.dts
Normal file
145
arch/riscv/boot/dts/microchip/mpfs-sev-kit.dts
Normal file
@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Copyright (c) 2022 Microchip Technology Inc */
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "mpfs.dtsi"
|
||||
#include "mpfs-sev-kit-fabric.dtsi"
|
||||
|
||||
/* Clock frequency (in Hz) of the rtcclk */
|
||||
#define MTIMER_FREQ 1000000
|
||||
|
||||
/ {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
model = "Microchip PolarFire-SoC SEV Kit";
|
||||
compatible = "microchip,mpfs-sev-kit", "microchip,mpfs";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &mac1;
|
||||
serial0 = &mmuart0;
|
||||
serial1 = &mmuart1;
|
||||
serial2 = &mmuart2;
|
||||
serial3 = &mmuart3;
|
||||
serial4 = &mmuart4;
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial1:115200n8";
|
||||
};
|
||||
|
||||
cpus {
|
||||
timebase-frequency = <MTIMER_FREQ>;
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
fabricbuf0ddrc: buffer@80000000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0x0 0x80000000 0x0 0x2000000>;
|
||||
};
|
||||
|
||||
fabricbuf1ddrnc: buffer@c4000000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0x0 0xc4000000 0x0 0x4000000>;
|
||||
};
|
||||
|
||||
fabricbuf2ddrncwcb: buffer@d4000000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0x0 0xd4000000 0x0 0x4000000>;
|
||||
};
|
||||
};
|
||||
|
||||
ddrc_cache: memory@1000000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x10 0x0 0x0 0x76000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio2 {
|
||||
interrupts = <53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mac0 {
|
||||
status = "okay";
|
||||
phy-mode = "sgmii";
|
||||
phy-handle = <&phy0>;
|
||||
phy1: ethernet-phy@9 {
|
||||
reg = <9>;
|
||||
};
|
||||
phy0: ethernet-phy@8 {
|
||||
reg = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
&mac1 {
|
||||
status = "okay";
|
||||
phy-mode = "sgmii";
|
||||
phy-handle = <&phy1>;
|
||||
};
|
||||
|
||||
&mbox {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmc {
|
||||
status = "okay";
|
||||
bus-width = <4>;
|
||||
disable-wp;
|
||||
cap-sd-highspeed;
|
||||
cap-mmc-highspeed;
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs200-1_8v;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
sd-uhs-sdr104;
|
||||
};
|
||||
|
||||
&mmuart1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mmuart4 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&refclk {
|
||||
clock-frequency = <125000000>;
|
||||
};
|
||||
|
||||
&rtc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&syscontroller {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb {
|
||||
status = "okay";
|
||||
dr_mode = "otg";
|
||||
};
|
@ -330,7 +330,7 @@
|
||||
};
|
||||
|
||||
qspi: spi@21000000 {
|
||||
compatible = "microchip,mpfs-qspi";
|
||||
compatible = "microchip,mpfs-qspi", "microchip,coreqspi-rtl-v2";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x0 0x21000000 0x0 0x1000>;
|
||||
@ -464,35 +464,6 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie: pcie@2000000000 {
|
||||
compatible = "microchip,pcie-host-1.0";
|
||||
#address-cells = <0x3>;
|
||||
#interrupt-cells = <0x1>;
|
||||
#size-cells = <0x2>;
|
||||
device_type = "pci";
|
||||
reg = <0x20 0x0 0x0 0x8000000>, <0x0 0x43000000 0x0 0x10000>;
|
||||
reg-names = "cfg", "apb";
|
||||
bus-range = <0x0 0x7f>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <119>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc 0>,
|
||||
<0 0 0 2 &pcie_intc 1>,
|
||||
<0 0 0 3 &pcie_intc 2>,
|
||||
<0 0 0 4 &pcie_intc 3>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
clocks = <&fabric_clk1>, <&fabric_clk1>, <&fabric_clk3>;
|
||||
clock-names = "fic0", "fic1", "fic3";
|
||||
ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
|
||||
msi-parent = <&pcie>;
|
||||
msi-controller;
|
||||
status = "disabled";
|
||||
pcie_intc: interrupt-controller {
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
|
||||
mbox: mailbox@37020000 {
|
||||
compatible = "microchip,mpfs-mailbox";
|
||||
reg = <0x0 0x37020000 0x0 0x1000>, <0x0 0x2000318C 0x0 0x40>;
|
||||
|
@ -17,6 +17,9 @@
|
||||
static bool errata_probe_pbmt(unsigned int stage,
|
||||
unsigned long arch_id, unsigned long impid)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ERRATA_THEAD_PBMT))
|
||||
return false;
|
||||
|
||||
if (arch_id != 0 || impid != 0)
|
||||
return false;
|
||||
|
||||
@ -30,7 +33,9 @@ static bool errata_probe_pbmt(unsigned int stage,
|
||||
static bool errata_probe_cmo(unsigned int stage,
|
||||
unsigned long arch_id, unsigned long impid)
|
||||
{
|
||||
#ifdef CONFIG_ERRATA_THEAD_CMO
|
||||
if (!IS_ENABLED(CONFIG_ERRATA_THEAD_CMO))
|
||||
return false;
|
||||
|
||||
if (arch_id != 0 || impid != 0)
|
||||
return false;
|
||||
|
||||
@ -40,9 +45,6 @@ static bool errata_probe_cmo(unsigned int stage,
|
||||
riscv_cbom_block_size = L1_CACHE_BYTES;
|
||||
riscv_noncoherent_supported();
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 thead_errata_probe(unsigned int stage,
|
||||
@ -51,10 +53,10 @@ static u32 thead_errata_probe(unsigned int stage,
|
||||
u32 cpu_req_errata = 0;
|
||||
|
||||
if (errata_probe_pbmt(stage, archid, impid))
|
||||
cpu_req_errata |= (1U << ERRATA_THEAD_PBMT);
|
||||
cpu_req_errata |= BIT(ERRATA_THEAD_PBMT);
|
||||
|
||||
if (errata_probe_cmo(stage, archid, impid))
|
||||
cpu_req_errata |= (1U << ERRATA_THEAD_CMO);
|
||||
cpu_req_errata |= BIT(ERRATA_THEAD_CMO);
|
||||
|
||||
return cpu_req_errata;
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ static inline void riscv_init_cbom_blocksize(void) { }
|
||||
|
||||
#ifdef CONFIG_RISCV_DMA_NONCOHERENT
|
||||
void riscv_noncoherent_supported(void);
|
||||
#else
|
||||
static inline void riscv_noncoherent_supported(void) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -99,6 +99,10 @@ do { \
|
||||
get_cache_size(2, CACHE_TYPE_UNIFIED)); \
|
||||
NEW_AUX_ENT(AT_L2_CACHEGEOMETRY, \
|
||||
get_cache_geometry(2, CACHE_TYPE_UNIFIED)); \
|
||||
NEW_AUX_ENT(AT_L3_CACHESIZE, \
|
||||
get_cache_size(3, CACHE_TYPE_UNIFIED)); \
|
||||
NEW_AUX_ENT(AT_L3_CACHEGEOMETRY, \
|
||||
get_cache_geometry(3, CACHE_TYPE_UNIFIED)); \
|
||||
} while (0)
|
||||
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
|
||||
struct linux_binprm;
|
||||
|
@ -101,9 +101,9 @@ __io_reads_ins(reads, u32, l, __io_br(), __io_ar(addr))
|
||||
__io_reads_ins(ins, u8, b, __io_pbr(), __io_par(addr))
|
||||
__io_reads_ins(ins, u16, w, __io_pbr(), __io_par(addr))
|
||||
__io_reads_ins(ins, u32, l, __io_pbr(), __io_par(addr))
|
||||
#define insb(addr, buffer, count) __insb((void __iomem *)(long)addr, buffer, count)
|
||||
#define insw(addr, buffer, count) __insw((void __iomem *)(long)addr, buffer, count)
|
||||
#define insl(addr, buffer, count) __insl((void __iomem *)(long)addr, buffer, count)
|
||||
#define insb(addr, buffer, count) __insb(PCI_IOBASE + (addr), buffer, count)
|
||||
#define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count)
|
||||
#define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count)
|
||||
|
||||
__io_writes_outs(writes, u8, b, __io_bw(), __io_aw())
|
||||
__io_writes_outs(writes, u16, w, __io_bw(), __io_aw())
|
||||
@ -115,22 +115,22 @@ __io_writes_outs(writes, u32, l, __io_bw(), __io_aw())
|
||||
__io_writes_outs(outs, u8, b, __io_pbw(), __io_paw())
|
||||
__io_writes_outs(outs, u16, w, __io_pbw(), __io_paw())
|
||||
__io_writes_outs(outs, u32, l, __io_pbw(), __io_paw())
|
||||
#define outsb(addr, buffer, count) __outsb((void __iomem *)(long)addr, buffer, count)
|
||||
#define outsw(addr, buffer, count) __outsw((void __iomem *)(long)addr, buffer, count)
|
||||
#define outsl(addr, buffer, count) __outsl((void __iomem *)(long)addr, buffer, count)
|
||||
#define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count)
|
||||
#define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count)
|
||||
#define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count)
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
__io_reads_ins(reads, u64, q, __io_br(), __io_ar(addr))
|
||||
#define readsq(addr, buffer, count) __readsq(addr, buffer, count)
|
||||
|
||||
__io_reads_ins(ins, u64, q, __io_pbr(), __io_par(addr))
|
||||
#define insq(addr, buffer, count) __insq((void __iomem *)addr, buffer, count)
|
||||
#define insq(addr, buffer, count) __insq(PCI_IOBASE + (addr), buffer, count)
|
||||
|
||||
__io_writes_outs(writes, u64, q, __io_bw(), __io_aw())
|
||||
#define writesq(addr, buffer, count) __writesq(addr, buffer, count)
|
||||
|
||||
__io_writes_outs(outs, u64, q, __io_pbr(), __io_paw())
|
||||
#define outsq(addr, buffer, count) __outsq((void __iomem *)addr, buffer, count)
|
||||
#define outsq(addr, buffer, count) __outsq(PCI_IOBASE + (addr), buffer, count)
|
||||
#endif
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
|
@ -16,7 +16,6 @@ typedef struct {
|
||||
atomic_long_t id;
|
||||
#endif
|
||||
void *vdso;
|
||||
void *vdso_info;
|
||||
#ifdef CONFIG_SMP
|
||||
/* A local icache flush is needed before user execution can resume. */
|
||||
cpumask_t icache_stale_mask;
|
||||
|
@ -30,8 +30,10 @@
|
||||
#define AT_L1D_CACHEGEOMETRY 43
|
||||
#define AT_L2_CACHESIZE 44
|
||||
#define AT_L2_CACHEGEOMETRY 45
|
||||
#define AT_L3_CACHESIZE 46
|
||||
#define AT_L3_CACHEGEOMETRY 47
|
||||
|
||||
/* entries in ARCH_DLINFO */
|
||||
#define AT_VECTOR_SIZE_ARCH 7
|
||||
#define AT_VECTOR_SIZE_ARCH 9
|
||||
|
||||
#endif /* _UAPI_ASM_RISCV_AUXVEC_H */
|
||||
|
@ -3,10 +3,13 @@
|
||||
* Copyright (C) 2012 Regents of the University of California
|
||||
*/
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/csr.h>
|
||||
#include <asm/hwcap.h>
|
||||
#include <asm/sbi.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
@ -68,6 +71,50 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
struct riscv_cpuinfo {
|
||||
unsigned long mvendorid;
|
||||
unsigned long marchid;
|
||||
unsigned long mimpid;
|
||||
};
|
||||
static DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
|
||||
|
||||
static int riscv_cpuinfo_starting(unsigned int cpu)
|
||||
{
|
||||
struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
|
||||
|
||||
#if IS_ENABLED(CONFIG_RISCV_SBI)
|
||||
ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid();
|
||||
ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid();
|
||||
ci->mimpid = sbi_spec_is_0_1() ? 0 : sbi_get_mimpid();
|
||||
#elif IS_ENABLED(CONFIG_RISCV_M_MODE)
|
||||
ci->mvendorid = csr_read(CSR_MVENDORID);
|
||||
ci->marchid = csr_read(CSR_MARCHID);
|
||||
ci->mimpid = csr_read(CSR_MIMPID);
|
||||
#else
|
||||
ci->mvendorid = 0;
|
||||
ci->marchid = 0;
|
||||
ci->mimpid = 0;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init riscv_cpuinfo_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/cpuinfo:starting",
|
||||
riscv_cpuinfo_starting, NULL);
|
||||
if (ret < 0) {
|
||||
pr_err("cpuinfo: failed to register hotplug callbacks.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
device_initcall(riscv_cpuinfo_init);
|
||||
|
||||
#define __RISCV_ISA_EXT_DATA(UPROP, EXTID) \
|
||||
{ \
|
||||
.uprop = #UPROP, \
|
||||
@ -186,6 +233,7 @@ static int c_show(struct seq_file *m, void *v)
|
||||
{
|
||||
unsigned long cpu_id = (unsigned long)v - 1;
|
||||
struct device_node *node = of_get_cpu_node(cpu_id, NULL);
|
||||
struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
|
||||
const char *compat, *isa;
|
||||
|
||||
seq_printf(m, "processor\t: %lu\n", cpu_id);
|
||||
@ -196,6 +244,9 @@ static int c_show(struct seq_file *m, void *v)
|
||||
if (!of_property_read_string(node, "compatible", &compat)
|
||||
&& strcmp(compat, "riscv"))
|
||||
seq_printf(m, "uarch\t\t: %s\n", compat);
|
||||
seq_printf(m, "mvendorid\t: 0x%lx\n", ci->mvendorid);
|
||||
seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid);
|
||||
seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid);
|
||||
seq_puts(m, "\n");
|
||||
of_node_put(node);
|
||||
|
||||
|
@ -254,35 +254,28 @@ void __init riscv_fill_hwcap(void)
|
||||
#ifdef CONFIG_RISCV_ALTERNATIVE
|
||||
static bool __init_or_module cpufeature_probe_svpbmt(unsigned int stage)
|
||||
{
|
||||
#ifdef CONFIG_RISCV_ISA_SVPBMT
|
||||
switch (stage) {
|
||||
case RISCV_ALTERNATIVES_EARLY_BOOT:
|
||||
if (!IS_ENABLED(CONFIG_RISCV_ISA_SVPBMT))
|
||||
return false;
|
||||
default:
|
||||
return riscv_isa_extension_available(NULL, SVPBMT);
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
|
||||
return false;
|
||||
|
||||
return riscv_isa_extension_available(NULL, SVPBMT);
|
||||
}
|
||||
|
||||
static bool __init_or_module cpufeature_probe_zicbom(unsigned int stage)
|
||||
{
|
||||
#ifdef CONFIG_RISCV_ISA_ZICBOM
|
||||
switch (stage) {
|
||||
case RISCV_ALTERNATIVES_EARLY_BOOT:
|
||||
if (!IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM))
|
||||
return false;
|
||||
default:
|
||||
if (riscv_isa_extension_available(NULL, ZICBOM)) {
|
||||
riscv_noncoherent_supported();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
|
||||
return false;
|
||||
|
||||
if (!riscv_isa_extension_available(NULL, ZICBOM))
|
||||
return false;
|
||||
|
||||
riscv_noncoherent_supported();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -297,10 +290,10 @@ static u32 __init_or_module cpufeature_probe(unsigned int stage)
|
||||
u32 cpu_req_feature = 0;
|
||||
|
||||
if (cpufeature_probe_svpbmt(stage))
|
||||
cpu_req_feature |= (1U << CPUFEATURE_SVPBMT);
|
||||
cpu_req_feature |= BIT(CPUFEATURE_SVPBMT);
|
||||
|
||||
if (cpufeature_probe_zicbom(stage))
|
||||
cpu_req_feature |= (1U << CPUFEATURE_ZICBOM);
|
||||
cpu_req_feature |= BIT(CPUFEATURE_ZICBOM);
|
||||
|
||||
return cpu_req_feature;
|
||||
}
|
||||
|
@ -252,10 +252,10 @@ static void __init parse_dtb(void)
|
||||
pr_info("Machine model: %s\n", name);
|
||||
dump_stack_set_arch_desc("%s (DT)", name);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
pr_err("No DTB passed to the kernel\n");
|
||||
}
|
||||
|
||||
pr_err("No DTB passed to the kernel\n");
|
||||
#ifdef CONFIG_CMDLINE_FORCE
|
||||
strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
|
||||
pr_info("Forcing kernel command line to: %s\n", boot_command_line);
|
||||
|
@ -18,9 +18,6 @@ static long riscv_sys_mmap(unsigned long addr, unsigned long len,
|
||||
if (unlikely(offset & (~PAGE_MASK >> page_shift_offset)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely((prot & PROT_WRITE) && !(prot & PROT_READ)))
|
||||
return -EINVAL;
|
||||
|
||||
return ksys_mmap_pgoff(addr, len, prot, flags, fd,
|
||||
offset >> (PAGE_SHIFT - page_shift_offset));
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ void die(struct pt_regs *regs, const char *str)
|
||||
{
|
||||
static int die_counter;
|
||||
int ret;
|
||||
long cause;
|
||||
|
||||
oops_enter();
|
||||
|
||||
@ -42,11 +43,13 @@ void die(struct pt_regs *regs, const char *str)
|
||||
|
||||
pr_emerg("%s [#%d]\n", str, ++die_counter);
|
||||
print_modules();
|
||||
show_regs(regs);
|
||||
if (regs)
|
||||
show_regs(regs);
|
||||
|
||||
ret = notify_die(DIE_OOPS, str, regs, 0, regs->cause, SIGSEGV);
|
||||
cause = regs ? regs->cause : -1;
|
||||
ret = notify_die(DIE_OOPS, str, regs, 0, cause, SIGSEGV);
|
||||
|
||||
if (regs && kexec_should_crash(current))
|
||||
if (kexec_should_crash(current))
|
||||
crash_kexec(regs);
|
||||
|
||||
bust_spinlocks(0);
|
||||
|
@ -60,6 +60,11 @@ struct __vdso_info {
|
||||
struct vm_special_mapping *cm;
|
||||
};
|
||||
|
||||
static struct __vdso_info vdso_info;
|
||||
#ifdef CONFIG_COMPAT
|
||||
static struct __vdso_info compat_vdso_info;
|
||||
#endif
|
||||
|
||||
static int vdso_mremap(const struct vm_special_mapping *sm,
|
||||
struct vm_area_struct *new_vma)
|
||||
{
|
||||
@ -115,15 +120,18 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
|
||||
struct mm_struct *mm = task->mm;
|
||||
struct vm_area_struct *vma;
|
||||
VMA_ITERATOR(vmi, mm, 0);
|
||||
struct __vdso_info *vdso_info = mm->context.vdso_info;
|
||||
|
||||
mmap_read_lock(mm);
|
||||
|
||||
for_each_vma(vmi, vma) {
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
|
||||
if (vma_is_special_mapping(vma, vdso_info->dm))
|
||||
if (vma_is_special_mapping(vma, vdso_info.dm))
|
||||
zap_page_range(vma, vma->vm_start, size);
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (vma_is_special_mapping(vma, compat_vdso_info.dm))
|
||||
zap_page_range(vma, vma->vm_start, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
mmap_read_unlock(mm);
|
||||
@ -265,7 +273,6 @@ static int __setup_additional_pages(struct mm_struct *mm,
|
||||
|
||||
vdso_base += VVAR_SIZE;
|
||||
mm->context.vdso = (void *)vdso_base;
|
||||
mm->context.vdso_info = (void *)vdso_info;
|
||||
|
||||
ret =
|
||||
_install_special_mapping(mm, vdso_base, vdso_text_len,
|
||||
|
@ -184,7 +184,8 @@ static inline bool access_error(unsigned long cause, struct vm_area_struct *vma)
|
||||
}
|
||||
break;
|
||||
case EXC_LOAD_PAGE_FAULT:
|
||||
if (!(vma->vm_flags & VM_READ)) {
|
||||
/* Write implies read */
|
||||
if (!(vma->vm_flags & (VM_READ | VM_WRITE))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -473,7 +473,7 @@ config EDAC_ALTERA_SDMMC
|
||||
|
||||
config EDAC_SIFIVE
|
||||
bool "Sifive platform EDAC driver"
|
||||
depends on EDAC=y && SIFIVE_L2
|
||||
depends on EDAC=y && SIFIVE_CCACHE
|
||||
help
|
||||
Support for error detection and correction on the SiFive SoCs.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
/*
|
||||
* SiFive Platform EDAC Driver
|
||||
*
|
||||
* Copyright (C) 2018-2019 SiFive, Inc.
|
||||
* Copyright (C) 2018-2022 SiFive, Inc.
|
||||
*
|
||||
* This driver is partially based on octeon_edac-pc.c
|
||||
*
|
||||
@ -10,7 +10,7 @@
|
||||
#include <linux/edac.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "edac_module.h"
|
||||
#include <soc/sifive/sifive_l2_cache.h>
|
||||
#include <soc/sifive/sifive_ccache.h>
|
||||
|
||||
#define DRVNAME "sifive_edac"
|
||||
|
||||
@ -32,9 +32,9 @@ int ecc_err_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
|
||||
p = container_of(this, struct sifive_edac_priv, notifier);
|
||||
|
||||
if (event == SIFIVE_L2_ERR_TYPE_UE)
|
||||
if (event == SIFIVE_CCACHE_ERR_TYPE_UE)
|
||||
edac_device_handle_ue(p->dci, 0, 0, msg);
|
||||
else if (event == SIFIVE_L2_ERR_TYPE_CE)
|
||||
else if (event == SIFIVE_CCACHE_ERR_TYPE_CE)
|
||||
edac_device_handle_ce(p->dci, 0, 0, msg);
|
||||
|
||||
return NOTIFY_OK;
|
||||
@ -67,7 +67,7 @@ static int ecc_register(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
register_sifive_l2_error_notifier(&p->notifier);
|
||||
register_sifive_ccache_error_notifier(&p->notifier);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -81,7 +81,7 @@ static int ecc_unregister(struct platform_device *pdev)
|
||||
{
|
||||
struct sifive_edac_priv *p = platform_get_drvdata(pdev);
|
||||
|
||||
unregister_sifive_l2_error_notifier(&p->notifier);
|
||||
unregister_sifive_ccache_error_notifier(&p->notifier);
|
||||
edac_device_del_device(&pdev->dev);
|
||||
edac_device_free_ctl_info(p->dci);
|
||||
|
||||
|
@ -652,8 +652,11 @@ static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
|
||||
struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
|
||||
|
||||
/* Enable the access for TIME csr only from the user mode now */
|
||||
csr_write(CSR_SCOUNTEREN, 0x2);
|
||||
/*
|
||||
* Enable the access for CYCLE, TIME, and INSTRET CSRs from userspace,
|
||||
* as is necessary to maintain uABI compatibility.
|
||||
*/
|
||||
csr_write(CSR_SCOUNTEREN, 0x7);
|
||||
|
||||
/* Stop all the counters so that they can be enabled from perf */
|
||||
pmu_sbi_stop_all(pmu);
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
if SOC_SIFIVE
|
||||
|
||||
config SIFIVE_L2
|
||||
bool "Sifive L2 Cache controller"
|
||||
config SIFIVE_CCACHE
|
||||
bool "Sifive Composable Cache controller"
|
||||
help
|
||||
Support for the L2 cache controller on SiFive platforms.
|
||||
Support for the composable cache controller on SiFive platforms.
|
||||
|
||||
endif
|
||||
|
@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_SIFIVE_L2) += sifive_l2_cache.o
|
||||
obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
|
||||
|
255
drivers/soc/sifive/sifive_ccache.c
Normal file
255
drivers/soc/sifive/sifive_ccache.c
Normal file
@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* SiFive composable cache controller Driver
|
||||
*
|
||||
* Copyright (C) 2018-2022 SiFive, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "CCACHE: " fmt
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <asm/cacheinfo.h>
|
||||
#include <soc/sifive/sifive_ccache.h>
|
||||
|
||||
#define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100
|
||||
#define SIFIVE_CCACHE_DIRECCFIX_HIGH 0x104
|
||||
#define SIFIVE_CCACHE_DIRECCFIX_COUNT 0x108
|
||||
|
||||
#define SIFIVE_CCACHE_DIRECCFAIL_LOW 0x120
|
||||
#define SIFIVE_CCACHE_DIRECCFAIL_HIGH 0x124
|
||||
#define SIFIVE_CCACHE_DIRECCFAIL_COUNT 0x128
|
||||
|
||||
#define SIFIVE_CCACHE_DATECCFIX_LOW 0x140
|
||||
#define SIFIVE_CCACHE_DATECCFIX_HIGH 0x144
|
||||
#define SIFIVE_CCACHE_DATECCFIX_COUNT 0x148
|
||||
|
||||
#define SIFIVE_CCACHE_DATECCFAIL_LOW 0x160
|
||||
#define SIFIVE_CCACHE_DATECCFAIL_HIGH 0x164
|
||||
#define SIFIVE_CCACHE_DATECCFAIL_COUNT 0x168
|
||||
|
||||
#define SIFIVE_CCACHE_CONFIG 0x00
|
||||
#define SIFIVE_CCACHE_CONFIG_BANK_MASK GENMASK_ULL(7, 0)
|
||||
#define SIFIVE_CCACHE_CONFIG_WAYS_MASK GENMASK_ULL(15, 8)
|
||||
#define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16)
|
||||
#define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24)
|
||||
|
||||
#define SIFIVE_CCACHE_WAYENABLE 0x08
|
||||
#define SIFIVE_CCACHE_ECCINJECTERR 0x40
|
||||
|
||||
#define SIFIVE_CCACHE_MAX_ECCINTR 4
|
||||
|
||||
static void __iomem *ccache_base;
|
||||
static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR];
|
||||
static struct riscv_cacheinfo_ops ccache_cache_ops;
|
||||
static int level;
|
||||
|
||||
enum {
|
||||
DIR_CORR = 0,
|
||||
DATA_CORR,
|
||||
DATA_UNCORR,
|
||||
DIR_UNCORR,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static struct dentry *sifive_test;
|
||||
|
||||
static ssize_t ccache_write(struct file *file, const char __user *data,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (kstrtouint_from_user(data, count, 0, &val))
|
||||
return -EINVAL;
|
||||
if ((val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
|
||||
writel(val, ccache_base + SIFIVE_CCACHE_ECCINJECTERR);
|
||||
else
|
||||
return -EINVAL;
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ccache_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.write = ccache_write
|
||||
};
|
||||
|
||||
static void setup_sifive_debug(void)
|
||||
{
|
||||
sifive_test = debugfs_create_dir("sifive_ccache_cache", NULL);
|
||||
|
||||
debugfs_create_file("sifive_debug_inject_error", 0200,
|
||||
sifive_test, NULL, &ccache_fops);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ccache_config_read(void)
|
||||
{
|
||||
u32 cfg;
|
||||
|
||||
cfg = readl(ccache_base + SIFIVE_CCACHE_CONFIG);
|
||||
pr_info("%llu banks, %llu ways, sets/bank=%llu, bytes/block=%llu\n",
|
||||
FIELD_GET(SIFIVE_CCACHE_CONFIG_BANK_MASK, cfg),
|
||||
FIELD_GET(SIFIVE_CCACHE_CONFIG_WAYS_MASK, cfg),
|
||||
BIT_ULL(FIELD_GET(SIFIVE_CCACHE_CONFIG_SETS_MASK, cfg)),
|
||||
BIT_ULL(FIELD_GET(SIFIVE_CCACHE_CONFIG_BLKS_MASK, cfg)));
|
||||
|
||||
cfg = readl(ccache_base + SIFIVE_CCACHE_WAYENABLE);
|
||||
pr_info("Index of the largest way enabled: %u\n", cfg);
|
||||
}
|
||||
|
||||
static const struct of_device_id sifive_ccache_ids[] = {
|
||||
{ .compatible = "sifive,fu540-c000-ccache" },
|
||||
{ .compatible = "sifive,fu740-c000-ccache" },
|
||||
{ .compatible = "sifive,ccache0" },
|
||||
{ /* end of table */ }
|
||||
};
|
||||
|
||||
static ATOMIC_NOTIFIER_HEAD(ccache_err_chain);
|
||||
|
||||
int register_sifive_ccache_error_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(&ccache_err_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_sifive_ccache_error_notifier);
|
||||
|
||||
int unregister_sifive_ccache_error_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(&ccache_err_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier);
|
||||
|
||||
static int ccache_largest_wayenabled(void)
|
||||
{
|
||||
return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF;
|
||||
}
|
||||
|
||||
static ssize_t number_of_ways_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", ccache_largest_wayenabled());
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(number_of_ways_enabled);
|
||||
|
||||
static struct attribute *priv_attrs[] = {
|
||||
&dev_attr_number_of_ways_enabled.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group priv_attr_group = {
|
||||
.attrs = priv_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *ccache_get_priv_group(struct cacheinfo
|
||||
*this_leaf)
|
||||
{
|
||||
/* We want to use private group for composable cache only */
|
||||
if (this_leaf->level == level)
|
||||
return &priv_attr_group;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static irqreturn_t ccache_int_handler(int irq, void *device)
|
||||
{
|
||||
unsigned int add_h, add_l;
|
||||
|
||||
if (irq == g_irq[DIR_CORR]) {
|
||||
add_h = readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_HIGH);
|
||||
add_l = readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_LOW);
|
||||
pr_err("DirError @ 0x%08X.%08X\n", add_h, add_l);
|
||||
/* Reading this register clears the DirError interrupt sig */
|
||||
readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_COUNT);
|
||||
atomic_notifier_call_chain(&ccache_err_chain,
|
||||
SIFIVE_CCACHE_ERR_TYPE_CE,
|
||||
"DirECCFix");
|
||||
}
|
||||
if (irq == g_irq[DIR_UNCORR]) {
|
||||
add_h = readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_HIGH);
|
||||
add_l = readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_LOW);
|
||||
/* Reading this register clears the DirFail interrupt sig */
|
||||
readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_COUNT);
|
||||
atomic_notifier_call_chain(&ccache_err_chain,
|
||||
SIFIVE_CCACHE_ERR_TYPE_UE,
|
||||
"DirECCFail");
|
||||
panic("CCACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l);
|
||||
}
|
||||
if (irq == g_irq[DATA_CORR]) {
|
||||
add_h = readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_HIGH);
|
||||
add_l = readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_LOW);
|
||||
pr_err("DataError @ 0x%08X.%08X\n", add_h, add_l);
|
||||
/* Reading this register clears the DataError interrupt sig */
|
||||
readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_COUNT);
|
||||
atomic_notifier_call_chain(&ccache_err_chain,
|
||||
SIFIVE_CCACHE_ERR_TYPE_CE,
|
||||
"DatECCFix");
|
||||
}
|
||||
if (irq == g_irq[DATA_UNCORR]) {
|
||||
add_h = readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_HIGH);
|
||||
add_l = readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_LOW);
|
||||
pr_err("DataFail @ 0x%08X.%08X\n", add_h, add_l);
|
||||
/* Reading this register clears the DataFail interrupt sig */
|
||||
readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_COUNT);
|
||||
atomic_notifier_call_chain(&ccache_err_chain,
|
||||
SIFIVE_CCACHE_ERR_TYPE_UE,
|
||||
"DatECCFail");
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init sifive_ccache_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
int i, rc, intr_num;
|
||||
|
||||
np = of_find_matching_node(NULL, sifive_ccache_ids);
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
if (of_address_to_resource(np, 0, &res))
|
||||
return -ENODEV;
|
||||
|
||||
ccache_base = ioremap(res.start, resource_size(&res));
|
||||
if (!ccache_base)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(np, "cache-level", &level))
|
||||
return -ENOENT;
|
||||
|
||||
intr_num = of_property_count_u32_elems(np, "interrupts");
|
||||
if (!intr_num) {
|
||||
pr_err("No interrupts property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < intr_num; i++) {
|
||||
g_irq[i] = irq_of_parse_and_map(np, i);
|
||||
rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc",
|
||||
NULL);
|
||||
if (rc) {
|
||||
pr_err("Could not request IRQ %d\n", g_irq[i]);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
ccache_config_read();
|
||||
|
||||
ccache_cache_ops.get_priv_group = ccache_get_priv_group;
|
||||
riscv_set_cacheinfo_ops(&ccache_cache_ops);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
setup_sifive_debug();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_initcall(sifive_ccache_init);
|
@ -1,237 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* SiFive L2 cache controller Driver
|
||||
*
|
||||
* Copyright (C) 2018-2019 SiFive, Inc.
|
||||
*
|
||||
*/
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/cacheinfo.h>
|
||||
#include <soc/sifive/sifive_l2_cache.h>
|
||||
|
||||
#define SIFIVE_L2_DIRECCFIX_LOW 0x100
|
||||
#define SIFIVE_L2_DIRECCFIX_HIGH 0x104
|
||||
#define SIFIVE_L2_DIRECCFIX_COUNT 0x108
|
||||
|
||||
#define SIFIVE_L2_DIRECCFAIL_LOW 0x120
|
||||
#define SIFIVE_L2_DIRECCFAIL_HIGH 0x124
|
||||
#define SIFIVE_L2_DIRECCFAIL_COUNT 0x128
|
||||
|
||||
#define SIFIVE_L2_DATECCFIX_LOW 0x140
|
||||
#define SIFIVE_L2_DATECCFIX_HIGH 0x144
|
||||
#define SIFIVE_L2_DATECCFIX_COUNT 0x148
|
||||
|
||||
#define SIFIVE_L2_DATECCFAIL_LOW 0x160
|
||||
#define SIFIVE_L2_DATECCFAIL_HIGH 0x164
|
||||
#define SIFIVE_L2_DATECCFAIL_COUNT 0x168
|
||||
|
||||
#define SIFIVE_L2_CONFIG 0x00
|
||||
#define SIFIVE_L2_WAYENABLE 0x08
|
||||
#define SIFIVE_L2_ECCINJECTERR 0x40
|
||||
|
||||
#define SIFIVE_L2_MAX_ECCINTR 4
|
||||
|
||||
static void __iomem *l2_base;
|
||||
static int g_irq[SIFIVE_L2_MAX_ECCINTR];
|
||||
static struct riscv_cacheinfo_ops l2_cache_ops;
|
||||
|
||||
enum {
|
||||
DIR_CORR = 0,
|
||||
DATA_CORR,
|
||||
DATA_UNCORR,
|
||||
DIR_UNCORR,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static struct dentry *sifive_test;
|
||||
|
||||
static ssize_t l2_write(struct file *file, const char __user *data,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (kstrtouint_from_user(data, count, 0, &val))
|
||||
return -EINVAL;
|
||||
if ((val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
|
||||
writel(val, l2_base + SIFIVE_L2_ECCINJECTERR);
|
||||
else
|
||||
return -EINVAL;
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations l2_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.write = l2_write
|
||||
};
|
||||
|
||||
static void setup_sifive_debug(void)
|
||||
{
|
||||
sifive_test = debugfs_create_dir("sifive_l2_cache", NULL);
|
||||
|
||||
debugfs_create_file("sifive_debug_inject_error", 0200,
|
||||
sifive_test, NULL, &l2_fops);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void l2_config_read(void)
|
||||
{
|
||||
u32 regval, val;
|
||||
|
||||
regval = readl(l2_base + SIFIVE_L2_CONFIG);
|
||||
val = regval & 0xFF;
|
||||
pr_info("L2CACHE: No. of Banks in the cache: %d\n", val);
|
||||
val = (regval & 0xFF00) >> 8;
|
||||
pr_info("L2CACHE: No. of ways per bank: %d\n", val);
|
||||
val = (regval & 0xFF0000) >> 16;
|
||||
pr_info("L2CACHE: Sets per bank: %llu\n", (uint64_t)1 << val);
|
||||
val = (regval & 0xFF000000) >> 24;
|
||||
pr_info("L2CACHE: Bytes per cache block: %llu\n", (uint64_t)1 << val);
|
||||
|
||||
regval = readl(l2_base + SIFIVE_L2_WAYENABLE);
|
||||
pr_info("L2CACHE: Index of the largest way enabled: %d\n", regval);
|
||||
}
|
||||
|
||||
static const struct of_device_id sifive_l2_ids[] = {
|
||||
{ .compatible = "sifive,fu540-c000-ccache" },
|
||||
{ .compatible = "sifive,fu740-c000-ccache" },
|
||||
{ /* end of table */ },
|
||||
};
|
||||
|
||||
static ATOMIC_NOTIFIER_HEAD(l2_err_chain);
|
||||
|
||||
int register_sifive_l2_error_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(&l2_err_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_sifive_l2_error_notifier);
|
||||
|
||||
int unregister_sifive_l2_error_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(&l2_err_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier);
|
||||
|
||||
static int l2_largest_wayenabled(void)
|
||||
{
|
||||
return readl(l2_base + SIFIVE_L2_WAYENABLE) & 0xFF;
|
||||
}
|
||||
|
||||
static ssize_t number_of_ways_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", l2_largest_wayenabled());
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(number_of_ways_enabled);
|
||||
|
||||
static struct attribute *priv_attrs[] = {
|
||||
&dev_attr_number_of_ways_enabled.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group priv_attr_group = {
|
||||
.attrs = priv_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *l2_get_priv_group(struct cacheinfo *this_leaf)
|
||||
{
|
||||
/* We want to use private group for L2 cache only */
|
||||
if (this_leaf->level == 2)
|
||||
return &priv_attr_group;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static irqreturn_t l2_int_handler(int irq, void *device)
|
||||
{
|
||||
unsigned int add_h, add_l;
|
||||
|
||||
if (irq == g_irq[DIR_CORR]) {
|
||||
add_h = readl(l2_base + SIFIVE_L2_DIRECCFIX_HIGH);
|
||||
add_l = readl(l2_base + SIFIVE_L2_DIRECCFIX_LOW);
|
||||
pr_err("L2CACHE: DirError @ 0x%08X.%08X\n", add_h, add_l);
|
||||
/* Reading this register clears the DirError interrupt sig */
|
||||
readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT);
|
||||
atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
|
||||
"DirECCFix");
|
||||
}
|
||||
if (irq == g_irq[DIR_UNCORR]) {
|
||||
add_h = readl(l2_base + SIFIVE_L2_DIRECCFAIL_HIGH);
|
||||
add_l = readl(l2_base + SIFIVE_L2_DIRECCFAIL_LOW);
|
||||
/* Reading this register clears the DirFail interrupt sig */
|
||||
readl(l2_base + SIFIVE_L2_DIRECCFAIL_COUNT);
|
||||
atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
|
||||
"DirECCFail");
|
||||
panic("L2CACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l);
|
||||
}
|
||||
if (irq == g_irq[DATA_CORR]) {
|
||||
add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
|
||||
add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
|
||||
pr_err("L2CACHE: DataError @ 0x%08X.%08X\n", add_h, add_l);
|
||||
/* Reading this register clears the DataError interrupt sig */
|
||||
readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT);
|
||||
atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
|
||||
"DatECCFix");
|
||||
}
|
||||
if (irq == g_irq[DATA_UNCORR]) {
|
||||
add_h = readl(l2_base + SIFIVE_L2_DATECCFAIL_HIGH);
|
||||
add_l = readl(l2_base + SIFIVE_L2_DATECCFAIL_LOW);
|
||||
pr_err("L2CACHE: DataFail @ 0x%08X.%08X\n", add_h, add_l);
|
||||
/* Reading this register clears the DataFail interrupt sig */
|
||||
readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT);
|
||||
atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
|
||||
"DatECCFail");
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init sifive_l2_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
int i, rc, intr_num;
|
||||
|
||||
np = of_find_matching_node(NULL, sifive_l2_ids);
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
if (of_address_to_resource(np, 0, &res))
|
||||
return -ENODEV;
|
||||
|
||||
l2_base = ioremap(res.start, resource_size(&res));
|
||||
if (!l2_base)
|
||||
return -ENOMEM;
|
||||
|
||||
intr_num = of_property_count_u32_elems(np, "interrupts");
|
||||
if (!intr_num) {
|
||||
pr_err("L2CACHE: no interrupts property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < intr_num; i++) {
|
||||
g_irq[i] = irq_of_parse_and_map(np, i);
|
||||
rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL);
|
||||
if (rc) {
|
||||
pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[i]);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
l2_config_read();
|
||||
|
||||
l2_cache_ops.get_priv_group = l2_get_priv_group;
|
||||
riscv_set_cacheinfo_ops(&l2_cache_ops);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
setup_sifive_debug();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
device_initcall(sifive_l2_init);
|
16
include/soc/sifive/sifive_ccache.h
Normal file
16
include/soc/sifive/sifive_ccache.h
Normal file
@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* SiFive Composable Cache Controller header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOC_SIFIVE_CCACHE_H
|
||||
#define __SOC_SIFIVE_CCACHE_H
|
||||
|
||||
extern int register_sifive_ccache_error_notifier(struct notifier_block *nb);
|
||||
extern int unregister_sifive_ccache_error_notifier(struct notifier_block *nb);
|
||||
|
||||
#define SIFIVE_CCACHE_ERR_TYPE_CE 0
|
||||
#define SIFIVE_CCACHE_ERR_TYPE_UE 1
|
||||
|
||||
#endif /* __SOC_SIFIVE_CCACHE_H */
|
@ -1,16 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* SiFive L2 Cache Controller header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOC_SIFIVE_L2_CACHE_H
|
||||
#define __SOC_SIFIVE_L2_CACHE_H
|
||||
|
||||
extern int register_sifive_l2_error_notifier(struct notifier_block *nb);
|
||||
extern int unregister_sifive_l2_error_notifier(struct notifier_block *nb);
|
||||
|
||||
#define SIFIVE_L2_ERR_TYPE_CE 0
|
||||
#define SIFIVE_L2_ERR_TYPE_UE 1
|
||||
|
||||
#endif /* __SOC_SIFIVE_L2_CACHE_H */
|
Loading…
Reference in New Issue
Block a user