diff --git a/0001-riscv-kernel.patch b/0001-riscv-kernel.patch index 31a860c..6b84da7 100644 --- a/0001-riscv-kernel.patch +++ b/0001-riscv-kernel.patch @@ -1,6 +1,6 @@ -From e71d7cb54ac724161d5753280d5d0c2ef6f5484d Mon Sep 17 00:00:00 2001 +From 7539e4b83d9faf805d537cebded712eb237e20d4 Mon Sep 17 00:00:00 2001 From: Mingzheng Xing -Date: Tue, 10 Dec 2024 20:35:26 +0800 +Date: Thu, 16 Jan 2025 21:14:16 +0800 Subject: [PATCH] riscv kernel Signed-off-by: Mingzheng Xing @@ -8,6 +8,8 @@ Signed-off-by: Mingzheng Xing .../hwlock/xuantie,th1520-hwspinlock.yaml | 34 + .../bindings/iio/adc/thead,th1520-adc.yaml | 52 + .../bindings/iio/adc/xuantie,th1520-adc.yaml | 52 + + .../interrupt-controller/riscv,aplic.yaml | 172 + + .../interrupt-controller/riscv,imsics.yaml | 172 + .../mailbox/xuantie-th1520-mailbox.txt | 57 + .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 1 + .../devicetree/bindings/net/snps,dwmac.yaml | 2 + @@ -16,6 +18,7 @@ Signed-off-by: Mingzheng Xing .../pinctrl/thead,th1520-pinctrl.yaml | 374 + .../bindings/pwm/xuantie,th1520-pwm.yaml | 44 + .../bindings/reset/xuantie,th1520-reset.yaml | 45 + + .../devicetree/bindings/riscv/extensions.yaml | 6 + .../devicetree/bindings/rtc/xgene-rtc.txt | 16 + .../soc/xuantie/xuantie,th1520-event.yaml | 37 + .../bindings/sound/everest,es7210.txt | 12 + @@ -30,8 +33,11 @@ Signed-off-by: Mingzheng Xing .../membarrier-sync-core/arch-support.txt | 18 +- Documentation/scheduler/index.rst | 1 + Documentation/scheduler/membarrier.rst | 39 + - MAINTAINERS | 4 + - arch/riscv/Kconfig | 37 +- + MAINTAINERS | 18 + + arch/arm64/include/asm/tlb.h | 5 +- + arch/loongarch/include/asm/pgalloc.h | 1 + + arch/mips/include/asm/pgalloc.h | 1 + + arch/riscv/Kconfig | 41 +- arch/riscv/Kconfig.socs | 12 + arch/riscv/Makefile | 19 +- arch/riscv/Makefile.isa | 18 + @@ -40,8 +46,8 @@ Signed-off-by: Mingzheng Xing .../riscv/boot/dts/sophgo/mango-2sockets.dtsi | 699 + .../boot/dts/sophgo/mango-clock-socket0.dtsi | 124 + .../boot/dts/sophgo/mango-clock-socket1.dtsi | 124 + - .../boot/dts/sophgo/mango-cpus-socket0.dtsi | 1148 ++ - .../boot/dts/sophgo/mango-cpus-socket1.dtsi | 1149 ++ + .../boot/dts/sophgo/mango-cpus-socket0.dtsi | 2089 ++ + .../boot/dts/sophgo/mango-cpus-socket1.dtsi | 2090 ++ .../boot/dts/sophgo/mango-milkv-pioneer.dts | 170 + .../riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi | 81 + .../dts/sophgo/mango-pcie-3rc-capricorn.dtsi | 116 + @@ -71,14 +77,18 @@ Signed-off-by: Mingzheng Xing arch/riscv/configs/th1520_defconfig | 470 + arch/riscv/include/asm/barrier.h | 22 + arch/riscv/include/asm/errata_list.h | 32 +- + arch/riscv/include/asm/hwcap.h | 1 + arch/riscv/include/asm/io.h | 4 + arch/riscv/include/asm/membarrier.h | 19 + + arch/riscv/include/asm/pgalloc.h | 53 +- arch/riscv/include/asm/pgtable-64.h | 14 +- - arch/riscv/include/asm/pgtable.h | 3 +- + arch/riscv/include/asm/pgtable.h | 9 +- arch/riscv/include/asm/sbi.h | 9 + arch/riscv/include/asm/sparsemem.h | 2 +- arch/riscv/include/asm/switch_to.h | 15 + arch/riscv/include/asm/sync_core.h | 29 + + arch/riscv/include/asm/tlb.h | 18 + + arch/riscv/kernel/cpufeature.c | 1 + arch/riscv/kernel/module.c | 83 +- arch/riscv/kernel/process.c | 3 + arch/riscv/kernel/sbi-ipi.c | 46 +- @@ -87,6 +97,9 @@ Signed-off-by: Mingzheng Xing arch/riscv/mm/dma-noncoherent.c | 9 +- arch/riscv/mm/pgtable.c | 2 + arch/riscv/mm/tlbflush.c | 31 + + arch/x86/include/asm/hw_irq.h | 2 - + arch/x86/mm/pgtable.c | 3 + + drivers/base/platform-msi.c | 149 +- drivers/char/ipmi/ipmi_si_hardcode.c | 26 +- drivers/char/ipmi/ipmi_si_intf.c | 3 +- drivers/char/ipmi/ipmi_si_pci.c | 6 + @@ -116,6 +129,8 @@ Signed-off-by: Mingzheng Xing drivers/cpufreq/th1520-cpufreq.c | 584 + .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 106 +- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 11 + + drivers/dma/mv_xor_v2.c | 8 +- + drivers/dma/qcom/hidma.c | 6 +- drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/xuantie/Kconfig | 23 + @@ -128,7 +143,7 @@ Signed-off-by: Mingzheng Xing drivers/gpu/drm/Kconfig | 4 + drivers/gpu/drm/Makefile | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 + - drivers/gpu/drm/amd/display/Kconfig | 1 + + drivers/gpu/drm/amd/display/Kconfig | 5 +- .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 6 +- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 198 +- @@ -775,8 +790,21 @@ Signed-off-by: Mingzheng Xing drivers/iio/adc/Makefile | 1 + drivers/iio/adc/th1520-adc.c | 573 + drivers/iio/adc/th1520-adc.h | 192 + + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 5 +- + drivers/irqchip/Kconfig | 25 + + drivers/irqchip/Makefile | 3 + + drivers/irqchip/irq-riscv-aplic-direct.c | 323 + + drivers/irqchip/irq-riscv-aplic-main.c | 211 + + drivers/irqchip/irq-riscv-aplic-main.h | 52 + + drivers/irqchip/irq-riscv-aplic-msi.c | 278 + + drivers/irqchip/irq-riscv-imsic-early.c | 201 + + drivers/irqchip/irq-riscv-imsic-platform.c | 375 + + drivers/irqchip/irq-riscv-imsic-state.c | 865 + + drivers/irqchip/irq-riscv-imsic-state.h | 108 + + drivers/irqchip/irq-riscv-intc.c | 45 +- drivers/mailbox/Kconfig | 8 + drivers/mailbox/Makefile | 2 + + drivers/mailbox/bcm-flexrm-mailbox.c | 8 +- drivers/mailbox/th1520-mailbox.c | 614 + drivers/mmc/host/Kconfig | 14 + drivers/mmc/host/Makefile | 1 + @@ -939,6 +967,7 @@ Signed-off-by: Mingzheng Xing .../controller/cadence/pcie-cadence-sophgo.h | 17 + drivers/pci/msi/msi.c | 97 +- drivers/pci/pcie/portdrv.c | 2 +- + drivers/perf/arm_smmuv3_pmu.c | 4 +- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 3 +- drivers/phy/synopsys/Kconfig | 13 + @@ -1186,6 +1215,7 @@ Signed-off-by: Mingzheng Xing drivers/tty/serial/8250/8250_dma.c | 134 +- drivers/tty/serial/8250/8250_dw.c | 2 +- drivers/tty/serial/8250/8250_port.c | 12 +- + drivers/ufs/host/ufs-qcom.c | 8 +- drivers/usb/dwc3/Kconfig | 20 + drivers/usb/dwc3/Makefile | 2 + drivers/usb/dwc3/core.c | 22 +- @@ -1194,6 +1224,7 @@ Signed-off-by: Mingzheng Xing drivers/watchdog/Makefile | 1 + drivers/watchdog/dw_wdt.c | 13 +- drivers/watchdog/th1520_wdt.c | 393 + + include/asm-generic/pgalloc.h | 7 +- include/drm/bridge/dw_hdmi.h | 5 + .../dt-bindings/clock/sophgo-mango-clock.h | 165 + include/dt-bindings/clock/sophgo.h | 15 + @@ -1209,10 +1240,18 @@ Signed-off-by: Mingzheng Xing .../dt-bindings/reset/xuantie,th1520-reset.h | 28 + .../dt-bindings/soc/th1520_system_status.h | 38 + .../dt-bindings/soc/xuantie,th1520-iopmp.h | 41 + - include/linux/cpuhotplug.h | 1 + + include/linux/cpuhotplug.h | 2 + + include/linux/cpumask.h | 17 + + include/linux/find.h | 27 + include/linux/firmware/xuantie/ipc.h | 167 + include/linux/firmware/xuantie/th1520_event.h | 35 + + include/linux/irqchip/riscv-aplic.h | 145 + + include/linux/irqchip/riscv-imsic.h | 87 + + include/linux/irqdomain.h | 17 + + include/linux/irqdomain_defs.h | 2 + include/linux/mlx4/device.h | 2 +- + include/linux/mm.h | 16 + + include/linux/msi.h | 28 +- include/linux/sync_core.h | 16 +- include/linux/th1520_proc_debug.h | 13 + include/linux/th1520_rpmsg.h | 99 + @@ -1221,11 +1260,15 @@ Signed-off-by: Mingzheng Xing include/uapi/drm/drm_fourcc.h | 90 + include/uapi/drm/vs_drm.h | 50 + init/Kconfig | 3 + + kernel/irq/irqdomain.c | 28 +- + kernel/irq/matrix.c | 28 +- + kernel/irq/msi.c | 184 +- kernel/panic.c | 8 + kernel/sched/core.c | 11 +- kernel/sched/fair.c | 3 + kernel/sched/membarrier.c | 13 +- kernel/time/tick-oneshot.c | 2 +- + lib/find_bit.c | 12 + mm/memblock.c | 6 +- mm/pgtable-generic.c | 1 + net/rfkill/Makefile | 1 + @@ -1268,10 +1311,12 @@ Signed-off-by: Mingzheng Xing .../riscv/thead/c900-legacy/microarch.json | 80 + .../arch/riscv/thead/th1520-ddr/metrics.json | 713 + .../thead/th1520-ddr/uncore-ddr-pmu.json | 1550 ++ - 1263 files changed, 554053 insertions(+), 572 deletions(-) + 1306 files changed, 559520 insertions(+), 723 deletions(-) create mode 100644 Documentation/devicetree/bindings/hwlock/xuantie,th1520-hwspinlock.yaml create mode 100644 Documentation/devicetree/bindings/iio/adc/thead,th1520-adc.yaml create mode 100644 Documentation/devicetree/bindings/iio/adc/xuantie,th1520-adc.yaml + create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml + create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml create mode 100644 Documentation/devicetree/bindings/mailbox/xuantie-th1520-mailbox.txt create mode 100644 Documentation/devicetree/bindings/net/xuantie,dwmac.yaml create mode 100644 Documentation/devicetree/bindings/nvmem/xuantie,th1520-efuse.txt @@ -1959,6 +2004,14 @@ Signed-off-by: Mingzheng Xing create mode 100644 drivers/i2c/busses/i2c-designware-master_dma.h create mode 100644 drivers/iio/adc/th1520-adc.c create mode 100644 drivers/iio/adc/th1520-adc.h + create mode 100644 drivers/irqchip/irq-riscv-aplic-direct.c + create mode 100644 drivers/irqchip/irq-riscv-aplic-main.c + create mode 100644 drivers/irqchip/irq-riscv-aplic-main.h + create mode 100644 drivers/irqchip/irq-riscv-aplic-msi.c + create mode 100644 drivers/irqchip/irq-riscv-imsic-early.c + create mode 100644 drivers/irqchip/irq-riscv-imsic-platform.c + create mode 100644 drivers/irqchip/irq-riscv-imsic-state.c + create mode 100644 drivers/irqchip/irq-riscv-imsic-state.h create mode 100644 drivers/mailbox/th1520-mailbox.c create mode 100644 drivers/mmc/host/sdhci-sophgo.c create mode 100644 drivers/mmc/host/sdhci-sophgo.h @@ -2338,6 +2391,8 @@ Signed-off-by: Mingzheng Xing create mode 100644 include/dt-bindings/soc/xuantie,th1520-iopmp.h create mode 100644 include/linux/firmware/xuantie/ipc.h create mode 100644 include/linux/firmware/xuantie/th1520_event.h + create mode 100644 include/linux/irqchip/riscv-aplic.h + create mode 100644 include/linux/irqchip/riscv-imsic.h create mode 100644 include/linux/th1520_proc_debug.h create mode 100644 include/linux/th1520_rpmsg.h create mode 100644 include/soc/xuantie/th1520_system_monitor.h @@ -2528,6 +2583,362 @@ index 000000000000..a4bb8f1b0e17 + /* ADC pin is proprietary,no need to config pinctrl */ + status = "disabled"; + }; +diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml +new file mode 100644 +index 000000000000..190a6499c932 +--- /dev/null ++++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml +@@ -0,0 +1,172 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/interrupt-controller/riscv,aplic.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: RISC-V Advanced Platform Level Interrupt Controller (APLIC) ++ ++maintainers: ++ - Anup Patel ++ ++description: ++ The RISC-V advanced interrupt architecture (AIA) defines an advanced ++ platform level interrupt controller (APLIC) for handling wired interrupts ++ in a RISC-V platform. The RISC-V AIA specification can be found at ++ https://github.com/riscv/riscv-aia. ++ ++ The RISC-V APLIC is implemented as hierarchical APLIC domains where all ++ interrupt sources connect to the root APLIC domain and a parent APLIC ++ domain can delegate interrupt sources to it's child APLIC domains. There ++ is one device tree node for each APLIC domain. ++ ++allOf: ++ - $ref: /schemas/interrupt-controller.yaml# ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - qemu,aplic ++ - const: riscv,aplic ++ ++ reg: ++ maxItems: 1 ++ ++ interrupt-controller: true ++ ++ "#interrupt-cells": ++ const: 2 ++ ++ interrupts-extended: ++ minItems: 1 ++ maxItems: 16384 ++ description: ++ Given APLIC domain directly injects external interrupts to a set of ++ RISC-V HARTS (or CPUs). Each node pointed to should be a riscv,cpu-intc ++ node, which has a CPU node (i.e. RISC-V HART) as parent. ++ ++ msi-parent: ++ description: ++ Given APLIC domain forwards wired interrupts as MSIs to a AIA incoming ++ message signaled interrupt controller (IMSIC). If both "msi-parent" and ++ "interrupts-extended" properties are present then it means the APLIC ++ domain supports both MSI mode and Direct mode in HW. In this case, the ++ APLIC driver has to choose between MSI mode or Direct mode. ++ ++ riscv,num-sources: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ minimum: 1 ++ maximum: 1023 ++ description: ++ Specifies the number of wired interrupt sources supported by this ++ APLIC domain. ++ ++ riscv,children: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ minItems: 1 ++ maxItems: 1024 ++ items: ++ maxItems: 1 ++ description: ++ A list of child APLIC domains for the given APLIC domain. Each child ++ APLIC domain is assigned a child index in increasing order, with the ++ first child APLIC domain assigned child index 0. The APLIC domain child ++ index is used by firmware to delegate interrupts from the given APLIC ++ domain to a particular child APLIC domain. ++ ++ riscv,delegation: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ minItems: 1 ++ maxItems: 1024 ++ items: ++ items: ++ - description: child APLIC domain phandle ++ - description: first interrupt number of the parent APLIC domain (inclusive) ++ - description: last interrupt number of the parent APLIC domain (inclusive) ++ description: ++ A interrupt delegation list where each entry is a triple consisting ++ of child APLIC domain phandle, first interrupt number of the parent ++ APLIC domain, and last interrupt number of the parent APLIC domain. ++ Firmware must configure interrupt delegation registers based on ++ interrupt delegation list. ++ ++dependencies: ++ riscv,delegation: [ "riscv,children" ] ++ ++required: ++ - compatible ++ - reg ++ - interrupt-controller ++ - "#interrupt-cells" ++ - riscv,num-sources ++ ++anyOf: ++ - required: ++ - interrupts-extended ++ - required: ++ - msi-parent ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ // Example 1 (APLIC domains directly injecting interrupt to HARTs): ++ ++ interrupt-controller@c000000 { ++ compatible = "qemu,aplic", "riscv,aplic"; ++ interrupts-extended = <&cpu1_intc 11>, ++ <&cpu2_intc 11>, ++ <&cpu3_intc 11>, ++ <&cpu4_intc 11>; ++ reg = <0xc000000 0x4080>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ riscv,num-sources = <63>; ++ riscv,children = <&aplic1>, <&aplic2>; ++ riscv,delegation = <&aplic1 1 63>; ++ }; ++ ++ aplic1: interrupt-controller@d000000 { ++ compatible = "qemu,aplic", "riscv,aplic"; ++ interrupts-extended = <&cpu1_intc 9>, ++ <&cpu2_intc 9>; ++ reg = <0xd000000 0x4080>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ riscv,num-sources = <63>; ++ }; ++ ++ aplic2: interrupt-controller@e000000 { ++ compatible = "qemu,aplic", "riscv,aplic"; ++ interrupts-extended = <&cpu3_intc 9>, ++ <&cpu4_intc 9>; ++ reg = <0xe000000 0x4080>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ riscv,num-sources = <63>; ++ }; ++ ++ - | ++ // Example 2 (APLIC domains forwarding interrupts as MSIs): ++ ++ interrupt-controller@c000000 { ++ compatible = "qemu,aplic", "riscv,aplic"; ++ msi-parent = <&imsic_mlevel>; ++ reg = <0xc000000 0x4000>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ riscv,num-sources = <63>; ++ riscv,children = <&aplic3>; ++ riscv,delegation = <&aplic3 1 63>; ++ }; ++ ++ aplic3: interrupt-controller@d000000 { ++ compatible = "qemu,aplic", "riscv,aplic"; ++ msi-parent = <&imsic_slevel>; ++ reg = <0xd000000 0x4000>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ riscv,num-sources = <63>; ++ }; ++... +diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml +new file mode 100644 +index 000000000000..84976f17a4a1 +--- /dev/null ++++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml +@@ -0,0 +1,172 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/interrupt-controller/riscv,imsics.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: RISC-V Incoming MSI Controller (IMSIC) ++ ++maintainers: ++ - Anup Patel ++ ++description: | ++ The RISC-V advanced interrupt architecture (AIA) defines a per-CPU incoming ++ MSI controller (IMSIC) for handling MSIs in a RISC-V platform. The RISC-V ++ AIA specification can be found at https://github.com/riscv/riscv-aia. ++ ++ The IMSIC is a per-CPU (or per-HART) device with separate interrupt file ++ for each privilege level (machine or supervisor). The configuration of ++ a IMSIC interrupt file is done using AIA CSRs and it also has a 4KB MMIO ++ space to receive MSIs from devices. Each IMSIC interrupt file supports a ++ fixed number of interrupt identities (to distinguish MSIs from devices) ++ which is same for given privilege level across CPUs (or HARTs). ++ ++ The device tree of a RISC-V platform will have one IMSIC device tree node ++ for each privilege level (machine or supervisor) which collectively describe ++ IMSIC interrupt files at that privilege level across CPUs (or HARTs). ++ ++ The arrangement of IMSIC interrupt files in MMIO space of a RISC-V platform ++ follows a particular scheme defined by the RISC-V AIA specification. A IMSIC ++ group is a set of IMSIC interrupt files co-located in MMIO space and we can ++ have multiple IMSIC groups (i.e. clusters, sockets, chiplets, etc) in a ++ RISC-V platform. The MSI target address of a IMSIC interrupt file at given ++ privilege level (machine or supervisor) encodes group index, HART index, ++ and guest index (shown below). ++ ++ XLEN-1 > (HART Index MSB) 12 0 ++ | | | | ++ ------------------------------------------------------------- ++ |xxxxxx|Group Index|xxxxxxxxxxx|HART Index|Guest Index| 0 | ++ ------------------------------------------------------------- ++ ++allOf: ++ - $ref: /schemas/interrupt-controller.yaml# ++ - $ref: /schemas/interrupt-controller/msi-controller.yaml# ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - qemu,imsics ++ - const: riscv,imsics ++ ++ reg: ++ minItems: 1 ++ maxItems: 16384 ++ description: ++ Base address of each IMSIC group. ++ ++ interrupt-controller: true ++ ++ "#interrupt-cells": ++ const: 0 ++ ++ msi-controller: true ++ ++ "#msi-cells": ++ const: 0 ++ ++ interrupts-extended: ++ minItems: 1 ++ maxItems: 16384 ++ description: ++ This property represents the set of CPUs (or HARTs) for which given ++ device tree node describes the IMSIC interrupt files. Each node pointed ++ to should be a riscv,cpu-intc node, which has a CPU node (i.e. RISC-V ++ HART) as parent. ++ ++ riscv,num-ids: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ minimum: 63 ++ maximum: 2047 ++ description: ++ Number of interrupt identities supported by IMSIC interrupt file. ++ ++ riscv,num-guest-ids: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ minimum: 63 ++ maximum: 2047 ++ description: ++ Number of interrupt identities are supported by IMSIC guest interrupt ++ file. When not specified it is assumed to be same as specified by the ++ riscv,num-ids property. ++ ++ riscv,guest-index-bits: ++ minimum: 0 ++ maximum: 7 ++ default: 0 ++ description: ++ Number of guest index bits in the MSI target address. ++ ++ riscv,hart-index-bits: ++ minimum: 0 ++ maximum: 15 ++ description: ++ Number of HART index bits in the MSI target address. When not ++ specified it is calculated based on the interrupts-extended property. ++ ++ riscv,group-index-bits: ++ minimum: 0 ++ maximum: 7 ++ default: 0 ++ description: ++ Number of group index bits in the MSI target address. ++ ++ riscv,group-index-shift: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ minimum: 0 ++ maximum: 55 ++ default: 24 ++ description: ++ The least significant bit position of the group index bits in the ++ MSI target address. ++ ++required: ++ - compatible ++ - reg ++ - interrupt-controller ++ - msi-controller ++ - "#msi-cells" ++ - interrupts-extended ++ - riscv,num-ids ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ // Example 1 (Machine-level IMSIC files with just one group): ++ ++ interrupt-controller@24000000 { ++ compatible = "qemu,imsics", "riscv,imsics"; ++ interrupts-extended = <&cpu1_intc 11>, ++ <&cpu2_intc 11>, ++ <&cpu3_intc 11>, ++ <&cpu4_intc 11>; ++ reg = <0x28000000 0x4000>; ++ interrupt-controller; ++ #interrupt-cells = <0>; ++ msi-controller; ++ #msi-cells = <0>; ++ riscv,num-ids = <127>; ++ }; ++ ++ - | ++ // Example 2 (Supervisor-level IMSIC files with two groups): ++ ++ interrupt-controller@28000000 { ++ compatible = "qemu,imsics", "riscv,imsics"; ++ interrupts-extended = <&cpu1_intc 9>, ++ <&cpu2_intc 9>, ++ <&cpu3_intc 9>, ++ <&cpu4_intc 9>; ++ reg = <0x28000000 0x2000>, /* Group0 IMSICs */ ++ <0x29000000 0x2000>; /* Group1 IMSICs */ ++ interrupt-controller; ++ #interrupt-cells = <0>; ++ msi-controller; ++ #msi-cells = <0>; ++ riscv,num-ids = <127>; ++ riscv,group-index-bits = <1>; ++ riscv,group-index-shift = <24>; ++ }; ++... diff --git a/Documentation/devicetree/bindings/mailbox/xuantie-th1520-mailbox.txt b/Documentation/devicetree/bindings/mailbox/xuantie-th1520-mailbox.txt new file mode 100644 index 000000000000..e93195bdb651 @@ -3211,6 +3622,23 @@ index 000000000000..6182bf93d2dc + #reset-cells = <1>; + }; + }; +diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml +index cc1f546fdbdc..36ff6749fbba 100644 +--- a/Documentation/devicetree/bindings/riscv/extensions.yaml ++++ b/Documentation/devicetree/bindings/riscv/extensions.yaml +@@ -128,6 +128,12 @@ properties: + changes to interrupts as frozen at commit ccbddab ("Merge pull + request #42 from riscv/jhauser-2023-RC4") of riscv-aia. + ++ - const: smstateen ++ description: | ++ The standard Smstateen extension for controlling access to CSRs ++ added by other RISC-V extensions in H/S/VS/U/VU modes and as ++ ratified at commit a28bfae (Ratified (#7)) of riscv-state-enable. ++ + - const: ssaia + description: | + The standard Ssaia supervisor-level extension for the advanced diff --git a/Documentation/devicetree/bindings/rtc/xgene-rtc.txt b/Documentation/devicetree/bindings/rtc/xgene-rtc.txt index fd195c358446..25ba8cf0cc31 100644 --- a/Documentation/devicetree/bindings/rtc/xgene-rtc.txt @@ -3947,10 +4375,10 @@ index 000000000000..2387804b1c63 +The barrier matches a full barrier in the proximity of the membarrier system call +entry, cf. membarrier_{private,global}_expedited(). diff --git a/MAINTAINERS b/MAINTAINERS -index 008a26b0f027..2fb1fc12a169 100644 +index 219b3d11ee43..366530842ec2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -13773,7 +13773,9 @@ M: Mathieu Desnoyers +@@ -13774,7 +13774,9 @@ M: Mathieu Desnoyers M: "Paul E. McKenney" L: linux-kernel@vger.kernel.org S: Supported @@ -3960,7 +4388,28 @@ index 008a26b0f027..2fb1fc12a169 100644 F: include/uapi/linux/membarrier.h F: kernel/sched/membarrier.c -@@ -18586,6 +18588,8 @@ M: Fu Wei +@@ -18516,6 +18518,20 @@ S: Maintained + F: drivers/mtd/nand/raw/r852.c + F: drivers/mtd/nand/raw/r852.h + ++RISC-V AIA DRIVERS ++M: Anup Patel ++L: linux-riscv@lists.infradead.org ++S: Maintained ++F: Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml ++F: Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml ++F: drivers/irqchip/irq-riscv-aplic-*.c ++F: drivers/irqchip/irq-riscv-aplic-*.h ++F: drivers/irqchip/irq-riscv-imsic-*.c ++F: drivers/irqchip/irq-riscv-imsic-*.h ++F: drivers/irqchip/irq-riscv-intc.c ++F: include/linux/irqchip/riscv-aplic.h ++F: include/linux/irqchip/riscv-imsic.h ++ + RISC-V ARCHITECTURE + M: Paul Walmsley + M: Palmer Dabbelt +@@ -18587,6 +18603,8 @@ M: Fu Wei L: linux-riscv@lists.infradead.org S: Maintained F: arch/riscv/boot/dts/thead/ @@ -3969,8 +4418,48 @@ index 008a26b0f027..2fb1fc12a169 100644 RNBD BLOCK DRIVERS M: Md. Haris Iqbal +diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h +index 2c29239d05c3..846c563689a8 100644 +--- a/arch/arm64/include/asm/tlb.h ++++ b/arch/arm64/include/asm/tlb.h +@@ -96,7 +96,10 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, + static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp, + unsigned long addr) + { +- tlb_remove_ptdesc(tlb, virt_to_ptdesc(pudp)); ++ struct ptdesc *ptdesc = virt_to_ptdesc(pudp); ++ ++ pagetable_pud_dtor(ptdesc); ++ tlb_remove_ptdesc(tlb, ptdesc); + } + #endif + +diff --git a/arch/loongarch/include/asm/pgalloc.h b/arch/loongarch/include/asm/pgalloc.h +index c9f9895f237d..a7b9c9e73593 100644 +--- a/arch/loongarch/include/asm/pgalloc.h ++++ b/arch/loongarch/include/asm/pgalloc.h +@@ -95,6 +95,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) + + if (!ptdesc) + return NULL; ++ pagetable_pud_ctor(ptdesc); + pud = ptdesc_address(ptdesc); + + pud_init(pud); +diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h +index 40e40a7eb94a..f4440edcd8fe 100644 +--- a/arch/mips/include/asm/pgalloc.h ++++ b/arch/mips/include/asm/pgalloc.h +@@ -95,6 +95,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) + + if (!ptdesc) + return NULL; ++ pagetable_pud_ctor(ptdesc); + pud = ptdesc_address(ptdesc); + + pud_init(pud); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig -index 3be10e723b2c..70568f639ef0 100644 +index 3be10e723b2c..7b9125dd1209 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -28,18 +28,22 @@ config RISCV @@ -4005,7 +4494,32 @@ index 3be10e723b2c..70568f639ef0 100644 select EDAC_SUPPORT select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) select GENERIC_ARCH_TOPOLOGY -@@ -223,6 +227,20 @@ config KASAN_SHADOW_OFFSET +@@ -119,6 +123,7 @@ config RISCV + select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION + select HAVE_EBPF_JIT if MMU ++ select HAVE_FAST_GUP if MMU + select HAVE_FUNCTION_ARG_ACCESS_API + select HAVE_FUNCTION_ERROR_INJECTION + select HAVE_GCC_PLUGINS +@@ -147,6 +152,7 @@ config RISCV + select IRQ_FORCED_THREADING + select KASAN_VMALLOC if KASAN + select LOCK_MM_AND_FIND_VMA ++ select MMU_GATHER_RCU_TABLE_FREE if SMP && MMU + select MODULES_USE_ELF_RELA if MODULES + select MODULE_SECTIONS if MODULES + select OF +@@ -155,6 +161,8 @@ config RISCV + select PCI_DOMAINS_GENERIC if PCI + select PCI_MSI if PCI + select RISCV_ALTERNATIVE if !XIP_KERNEL ++ select RISCV_APLIC ++ select RISCV_IMSIC + select RISCV_INTC + select RISCV_TIMER if RISCV_SBI + select SIFIVE_PLIC +@@ -223,6 +231,20 @@ config KASAN_SHADOW_OFFSET default 0xdfffffff00000000 if 64BIT default 0xffffffff if 32BIT @@ -4026,7 +4540,7 @@ index 3be10e723b2c..70568f639ef0 100644 config ARCH_FLATMEM_ENABLE def_bool !NUMA -@@ -281,6 +299,7 @@ config RISCV_DMA_NONCOHERENT +@@ -281,6 +303,7 @@ config RISCV_DMA_NONCOHERENT select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE select DMA_BOUNCE_UNALIGNED_KMALLOC if SWIOTLB @@ -4034,7 +4548,7 @@ index 3be10e723b2c..70568f639ef0 100644 config RISCV_NONSTANDARD_CACHE_OPS bool -@@ -507,7 +526,7 @@ config RISCV_ISA_V +@@ -507,7 +530,7 @@ config RISCV_ISA_V depends on TOOLCHAIN_HAS_V depends on FPU select DYNAMIC_SIGFRAME @@ -4043,7 +4557,7 @@ index 3be10e723b2c..70568f639ef0 100644 help Say N here if you want to disable all vector related procedure in the kernel. -@@ -697,6 +716,20 @@ config ARCH_SUPPORTS_KEXEC_PURGATORY +@@ -697,6 +720,20 @@ config ARCH_SUPPORTS_KEXEC_PURGATORY config ARCH_SUPPORTS_CRASH_DUMP def_bool y @@ -5147,10 +5661,15 @@ index 000000000000..cfe34495e4fd +}; diff --git a/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi new file mode 100644 -index 000000000000..7efc9741f3e7 +index 000000000000..5e3e697f1daa --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi -@@ -0,0 +1,1148 @@ +@@ -0,0 +1,2089 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ +/ { + cpus { + #address-cells = <1>; @@ -5402,909 +5921,1850 @@ index 000000000000..7efc9741f3e7 + }; + + cpu0: cpu@0 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <0>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu0_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu1: cpu@1 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <1>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu1_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu2: cpu@2 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <2>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu2_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu3: cpu@3 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <3>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu3_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu4: cpu@4 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <4>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu4_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu5: cpu@5 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <5>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu5_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu6: cpu@6 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <6>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu6_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu7: cpu@7 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <7>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu7_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu8: cpu@8 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <8>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu8_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu9: cpu@9 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <9>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu9_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu10: cpu@10 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <10>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu10_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu11: cpu@11 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <11>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu11_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu12: cpu@12 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <12>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu12_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu13: cpu@13 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <13>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu13_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu14: cpu@14 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <14>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu14_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu15: cpu@15 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <15>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu15_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu16: cpu@16 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <16>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu16_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu17: cpu@17 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <17>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu17_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu18: cpu@18 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <18>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu18_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu19: cpu@19 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <19>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu19_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu20: cpu@20 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <20>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu20_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu21: cpu@21 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <21>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu21_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu22: cpu@22 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <22>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu22_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu23: cpu@23 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; -+ reg = <23>; -+ status = "okay"; -+ compatible = "riscv"; + riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <23>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; + mmu-type = "riscv,sv39"; + numa-node-id = <0>; ++ + cpu23_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu24: cpu@24 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <24>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu24_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu25: cpu@25 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <25>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu25_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu26: cpu@26 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <26>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu26_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu27: cpu@27 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <27>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu27_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu28: cpu@28 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <28>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu28_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu29: cpu@29 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <29>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu29_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu30: cpu@30 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <30>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu30_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu31: cpu@31 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; -+ reg = <31>; -+ status = "okay"; -+ compatible = "riscv"; + riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <31>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; + mmu-type = "riscv,sv39"; + numa-node-id = <1>; ++ + cpu31_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu32: cpu@32 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <32>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu32_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu33: cpu@33 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <33>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu33_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu34: cpu@34 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <34>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu34_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu35: cpu@35 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <35>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu35_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu36: cpu@36 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <36>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu36_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu37: cpu@37 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <37>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu37_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu38: cpu@38 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <38>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu38_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu39: cpu@39 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <39>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu39_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu40: cpu@40 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <40>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu40_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu41: cpu@41 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <41>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu41_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu42: cpu@42 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <42>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu42_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu43: cpu@43 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <43>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu43_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu44: cpu@44 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <44>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu44_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu45: cpu@45 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <45>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu45_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu46: cpu@46 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <46>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu46_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu47: cpu@47 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <47>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu47_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu48: cpu@48 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <48>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu48_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu49: cpu@49 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <49>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu49_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu50: cpu@50 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <50>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu50_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu51: cpu@51 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <51>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu51_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu52: cpu@52 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <52>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu52_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu53: cpu@53 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <53>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu53_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu54: cpu@54 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <54>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu54_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu55: cpu@55 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; -+ reg = <55>; -+ status = "okay"; -+ compatible = "riscv"; + riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <55>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; + mmu-type = "riscv,sv39"; + numa-node-id = <2>; ++ + cpu55_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu56: cpu@56 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <56>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu56_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu57: cpu@57 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <57>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu57_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu58: cpu@58 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <58>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu58_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu59: cpu@59 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <59>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu59_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu60: cpu@60 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <60>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu60_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu61: cpu@61 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <61>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu61_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu62: cpu@62 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; -+ reg = <62>; -+ status = "okay"; -+ compatible = "riscv"; + riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <62>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu62_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu63: cpu@63 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; -+ reg = <63>; -+ status = "okay"; -+ compatible = "riscv"; + riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <63>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; + mmu-type = "riscv,sv39"; + numa-node-id = <3>; ++ + cpu63_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ ++ l2_cache0: cache-controller-0 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache1: cache-controller-1 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache2: cache-controller-2 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache3: cache-controller-3 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache4: cache-controller-4 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache5: cache-controller-5 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache6: cache-controller-6 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache7: cache-controller-7 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache8: cache-controller-8 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache9: cache-controller-9 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache10: cache-controller-10 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache11: cache-controller-11 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache12: cache-controller-12 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache13: cache-controller-13 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache14: cache-controller-14 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l2_cache15: cache-controller-15 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache0>; ++ }; ++ ++ l3_cache0: cache-controller-130 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <3>; ++ cache-size = <67108864>; ++ cache-sets = <4096>; ++ cache-unified; ++ }; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi new file mode 100644 -index 000000000000..255306410f40 +index 000000000000..f8e2800c51b9 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi -@@ -0,0 +1,1149 @@ +@@ -0,0 +1,2090 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ +/ { + cpus { + #address-cells = <1>; @@ -6555,903 +8015,1839 @@ index 000000000000..255306410f40 + }; + }; + -+ + cpu64: cpu@64 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <64>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache16>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu64_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu65: cpu@65 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <65>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache16>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu65_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu66: cpu@66 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <66>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache16>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu66_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu67: cpu@67 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <67>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache16>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu67_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu68: cpu@68 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <68>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache17>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu68_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu69: cpu@69 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <69>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache17>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu69_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu70: cpu@70 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <70>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache17>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu70_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu71: cpu@71 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <71>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache17>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu71_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu72: cpu@72 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <72>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache20>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu72_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu73: cpu@73 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <73>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache20>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu73_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu74: cpu@74 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <74>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache20>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu74_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu75: cpu@75 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <75>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache20>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu75_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu76: cpu@76 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <76>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache21>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu76_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu77: cpu@77 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <77>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache21>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu77_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu78: cpu@78 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <78>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache21>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu78_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu79: cpu@79 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <79>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache21>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu79_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu80: cpu@80 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <80>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache18>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu80_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu81: cpu@81 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <81>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache18>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu81_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu82: cpu@82 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <82>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache18>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu82_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu83: cpu@83 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <83>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache18>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu83_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu84: cpu@84 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <84>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache19>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu84_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu85: cpu@85 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <85>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache19>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu85_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu86: cpu@86 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <86>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache19>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu86_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu87: cpu@87 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <87>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache19>; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; ++ + cpu87_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu88: cpu@88 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <88>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache22>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu88_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu89: cpu@89 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <89>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache22>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu89_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu90: cpu@90 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <90>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache22>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu90_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu91: cpu@91 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <91>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache22>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu91_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu92: cpu@92 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <92>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache23>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu92_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu93: cpu@93 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <93>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache23>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu93_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu94: cpu@94 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <94>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache23>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu94_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu95: cpu@95 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <95>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache23>; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; ++ + cpu95_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu96: cpu@96 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <96>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache24>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu96_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu97: cpu@97 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <97>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache24>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu97_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu98: cpu@98 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <98>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache24>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu98_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu99: cpu@99 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <99>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache24>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu99_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu100: cpu@100 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <100>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache25>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu100_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu101: cpu@101 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <101>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache25>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu101_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu102: cpu@102 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <102>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache25>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu102_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu103: cpu@103 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <103>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache25>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu103_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu104: cpu@104 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <104>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache28>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu104_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu105: cpu@105 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <105>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache28>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu105_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu106: cpu@106 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <106>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache28>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu106_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu107: cpu@107 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <107>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache28>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu107_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu108: cpu@108 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <108>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache29>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu108_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu109: cpu@109 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <109>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache29>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu109_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu110: cpu@110 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <110>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache29>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu110_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu111: cpu@111 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <111>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache29>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu111_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu112: cpu@112 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <112>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache26>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu112_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu113: cpu@113 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <113>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache26>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu113_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu114: cpu@114 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <114>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache26>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu114_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu115: cpu@115 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <115>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache26>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu115_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu116: cpu@116 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <116>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache27>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu116_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu117: cpu@117 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <117>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache27>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu117_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu118: cpu@118 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <118>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache27>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu118_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu119: cpu@119 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <119>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache27>; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; ++ + cpu119_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu120: cpu@120 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <120>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache30>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu120_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu121: cpu@121 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <121>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache30>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu121_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu122: cpu@122 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <122>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache30>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu122_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu123: cpu@123 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <123>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache30>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu123_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu124: cpu@124 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <124>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache31>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu124_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu125: cpu@125 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <125>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache31>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu125_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu126: cpu@126 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <126>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache31>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu126_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ + cpu127: cpu@127 { ++ compatible = "thead,c920", "riscv"; + device_type = "cpu"; ++ riscv,isa = "rv64imafdcv"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; + reg = <127>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdc"; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache31>; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; ++ + cpu127_intc: interrupt-controller { -+ #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; ++ #interrupt-cells = <1>; + }; + }; ++ ++ l2_cache16: cache-controller-16 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache17: cache-controller-17 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache18: cache-controller-18 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache19: cache-controller-19 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache20: cache-controller-20 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache21: cache-controller-21 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache22: cache-controller-22 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache23: cache-controller-23 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache24: cache-controller-24 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache25: cache-controller-25 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache26: cache-controller-26 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache27: cache-controller-27 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache28: cache-controller-28 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache29: cache-controller-29 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache30: cache-controller-30 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l2_cache31: cache-controller-31 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ next-level-cache = <&l3_cache1>; ++ }; ++ ++ l3_cache1: cache-controller-131 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <3>; ++ cache-size = <67108864>; ++ cache-sets = <4096>; ++ cache-unified; ++ }; ++ + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts @@ -19120,7 +21516,7 @@ index 110752594228..2b1f98b7e9bf 100644 * This is a very specific barrier: it's currently only used in two places in * the kernel, both in the scheduler. See include/linux/spinlock.h for the two diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h -index d3f3c237adad..d415c50f22e8 100644 +index d3f3c237adad..c7fd111e3a50 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -128,9 +128,12 @@ asm volatile(ALTERNATIVE( \ @@ -19147,11 +21543,11 @@ index d3f3c237adad..d415c50f22e8 100644 + "mv a0, %1\n\t" \ + "j 2f\n\t" \ + "3:\n\t" \ -+ "cbo." __stringify(_op) " (a0)\n\t" \ ++ CBO_##_op(a0) \ + "add a0, a0, %0\n\t" \ + "2:\n\t" \ + "bltu a0, %2, 3b\n\t" \ -+ "nop", 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ ++ "nop", 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ + "mv a0, %3\n\t" \ + "j 2f\n\t" \ + "3:\n\t" \ @@ -19171,6 +21567,18 @@ index d3f3c237adad..d415c50f22e8 100644 #define THEAD_C9XX_RV_IRQ_PMU 17 #define THEAD_C9XX_CSR_SCOUNTEROF 0x5c5 +diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h +index f4157034efa9..5e8a89b38091 100644 +--- a/arch/riscv/include/asm/hwcap.h ++++ b/arch/riscv/include/asm/hwcap.h +@@ -58,6 +58,7 @@ + #define RISCV_ISA_EXT_ZICSR 40 + #define RISCV_ISA_EXT_ZIFENCEI 41 + #define RISCV_ISA_EXT_ZIHPM 42 ++#define RISCV_ISA_EXT_SMSTATEEN 43 + + #define RISCV_ISA_EXT_MAX 64 + diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index 42497d487a17..bbdc3c7ed6ca 100644 --- a/arch/riscv/include/asm/io.h @@ -19214,6 +21622,87 @@ index 6c016ebb5020..47b240d0d596 100644 * Matches a full barrier in the proximity of the membarrier * system call entry. */ +diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h +index d169a4f41a2e..deaf971253a2 100644 +--- a/arch/riscv/include/asm/pgalloc.h ++++ b/arch/riscv/include/asm/pgalloc.h +@@ -95,7 +95,19 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud) + __pud_free(mm, pud); + } + +-#define __pud_free_tlb(tlb, pud, addr) pud_free((tlb)->mm, pud) ++static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, ++ unsigned long addr) ++{ ++ if (pgtable_l4_enabled) { ++ struct ptdesc *ptdesc = virt_to_ptdesc(pud); ++ ++ pagetable_pud_dtor(ptdesc); ++ if (riscv_use_ipi_for_rfence()) ++ tlb_remove_page_ptdesc(tlb, ptdesc); ++ else ++ tlb_remove_ptdesc(tlb, ptdesc); ++ } ++} + + #define p4d_alloc_one p4d_alloc_one + static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr) +@@ -124,7 +136,16 @@ static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d) + __p4d_free(mm, p4d); + } + +-#define __p4d_free_tlb(tlb, p4d, addr) p4d_free((tlb)->mm, p4d) ++static inline void __p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d, ++ unsigned long addr) ++{ ++ if (pgtable_l5_enabled) { ++ if (riscv_use_ipi_for_rfence()) ++ tlb_remove_page_ptdesc(tlb, virt_to_ptdesc(p4d)); ++ else ++ tlb_remove_ptdesc(tlb, virt_to_ptdesc(p4d)); ++ } ++} + #endif /* __PAGETABLE_PMD_FOLDED */ + + static inline void sync_kernel_mappings(pgd_t *pgd) +@@ -149,15 +170,31 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) + + #ifndef __PAGETABLE_PMD_FOLDED + +-#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) ++static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, ++ unsigned long addr) ++{ ++ struct ptdesc *ptdesc = virt_to_ptdesc(pmd); ++ ++ pagetable_pmd_dtor(ptdesc); ++ if (riscv_use_ipi_for_rfence()) ++ tlb_remove_page_ptdesc(tlb, ptdesc); ++ else ++ tlb_remove_ptdesc(tlb, ptdesc); ++} + + #endif /* __PAGETABLE_PMD_FOLDED */ + +-#define __pte_free_tlb(tlb, pte, buf) \ +-do { \ +- pagetable_pte_dtor(page_ptdesc(pte)); \ +- tlb_remove_page_ptdesc((tlb), page_ptdesc(pte));\ +-} while (0) ++static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, ++ unsigned long addr) ++{ ++ struct ptdesc *ptdesc = page_ptdesc(pte); ++ ++ pagetable_pte_dtor(ptdesc); ++ if (riscv_use_ipi_for_rfence()) ++ tlb_remove_page_ptdesc(tlb, ptdesc); ++ else ++ tlb_remove_ptdesc(tlb, ptdesc); ++} + #endif /* CONFIG_MMU */ + + #endif /* _ASM_RISCV_PGALLOC_H */ diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 3272ca7a5270..b99bd66107a6 100644 --- a/arch/riscv/include/asm/pgtable-64.h @@ -19243,7 +21732,7 @@ index 3272ca7a5270..b99bd66107a6 100644 static inline u64 riscv_page_mtmask(void) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h -index 63d8a84826e9..e3b1f4515f20 100644 +index 63d8a84826e9..63f5eeff43d0 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -205,7 +205,8 @@ extern struct pt_alloc_ops pt_ops __initdata; @@ -19256,6 +21745,19 @@ index 63d8a84826e9..e3b1f4515f20 100644 #define PAGE_KERNEL_IO __pgprot(_PAGE_IOREMAP) extern pgd_t swapper_pg_dir[]; +@@ -663,6 +664,12 @@ static inline int pmd_write(pmd_t pmd) + return pte_write(pmd_pte(pmd)); + } + ++#define pud_write pud_write ++static inline int pud_write(pud_t pud) ++{ ++ return pte_write(pud_pte(pud)); ++} ++ + static inline int pmd_dirty(pmd_t pmd) + { + return pte_dirty(pmd_pte(pmd)); diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 3ed853b8a8c8..8d261a317175 100644 --- a/arch/riscv/include/asm/sbi.h @@ -19357,6 +21859,47 @@ index 000000000000..9153016da8f1 +#endif /* CONFIG_SMP */ + +#endif /* _ASM_RISCV_SYNC_CORE_H */ +diff --git a/arch/riscv/include/asm/tlb.h b/arch/riscv/include/asm/tlb.h +index 50b63b5c15bd..1f6c38420d8e 100644 +--- a/arch/riscv/include/asm/tlb.h ++++ b/arch/riscv/include/asm/tlb.h +@@ -10,6 +10,24 @@ struct mmu_gather; + + static void tlb_flush(struct mmu_gather *tlb); + ++#ifdef CONFIG_MMU ++#include ++ ++/* ++ * While riscv platforms with riscv_ipi_for_rfence as true require an IPI to ++ * perform TLB shootdown, some platforms with riscv_ipi_for_rfence as false use ++ * SBI to perform TLB shootdown. To keep software pagetable walkers safe in this ++ * case we switch to RCU based table free (MMU_GATHER_RCU_TABLE_FREE). See the ++ * comment below 'ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE' in include/asm-generic/tlb.h ++ * for more details. ++ */ ++static inline void __tlb_remove_table(void *table) ++{ ++ free_page_and_swap_cache(table); ++} ++ ++#endif /* CONFIG_MMU */ ++ + #define tlb_flush tlb_flush + #include + +diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c +index bb5fb2b820a2..6fdb7d166a41 100644 +--- a/arch/riscv/kernel/cpufeature.c ++++ b/arch/riscv/kernel/cpufeature.c +@@ -176,6 +176,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { + __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), + __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS), + __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), ++ __RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN), + __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), + __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), + __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c index df4f6fec5d17..ced5a09abaaa 100644 --- a/arch/riscv/kernel/module.c @@ -19763,6 +22306,211 @@ index 324e8cd9b502..a9f4af9f7f3f 100644 for (i = 0; i < nr_ptes_in_range; ++i) { local_flush_tlb_page_asid(start, asid); start += stride; +diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h +index 551829884734..dcfaa3812306 100644 +--- a/arch/x86/include/asm/hw_irq.h ++++ b/arch/x86/include/asm/hw_irq.h +@@ -16,8 +16,6 @@ + + #include + +-#define IRQ_MATRIX_BITS NR_VECTORS +- + #ifndef __ASSEMBLY__ + + #include +diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c +index 8e1ef5345b7a..a67bb8f982bd 100644 +--- a/arch/x86/mm/pgtable.c ++++ b/arch/x86/mm/pgtable.c +@@ -76,6 +76,9 @@ void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) + #if CONFIG_PGTABLE_LEVELS > 3 + void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud) + { ++ struct ptdesc *ptdesc = virt_to_ptdesc(pud); ++ ++ pagetable_pud_dtor(ptdesc); + paravirt_release_pud(__pa(pud) >> PAGE_SHIFT); + paravirt_tlb_remove_table(tlb, virt_to_page(pud)); + } +diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c +index 3348d4db5f1b..0d01890160f3 100644 +--- a/drivers/base/platform-msi.c ++++ b/drivers/base/platform-msi.c +@@ -13,6 +13,8 @@ + #include + #include + ++/* Begin of removal area. Once everything is converted over. Cleanup the includes too! */ ++ + #define DEV_ID_SHIFT 21 + #define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT)) + +@@ -204,8 +206,8 @@ static void platform_msi_free_priv_data(struct device *dev) + * Returns: + * Zero for success, or an error code in case of failure + */ +-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, +- irq_write_msi_msg_t write_msi_msg) ++static int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, ++ irq_write_msi_msg_t write_msi_msg) + { + int err; + +@@ -219,48 +221,6 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, + + return err; + } +-EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs); +- +-#ifdef CONFIG_HISI_VIRTCCA_CODA +-/** +- * platform_msi_domain_alloc_range_irqs - Allocate specific scope MSI interrupts for @dev +- * @dev: The device for which to allocate interrupts +- * @start: The start index of msi +- * @end: The end index of msi +- * @write_msi_msg: The function for writing msi message +- * +- * %0 if alloc irqs success +- * %error_code if alloc irqs failed +- * %-EINVAL if platform_data is null +- */ +-int platform_msi_domain_alloc_range_irqs(struct device *dev, unsigned int start, +- unsigned int end, irq_write_msi_msg_t write_msi_msg) +-{ +- int err; +- +- if (!dev->msi.data->platform_data) +- return -EINVAL; +- +- dev->msi.data->platform_data->write_msg = write_msi_msg; +- err = msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, start, end); +- if (err) +- platform_msi_free_priv_data(dev); +- +- return err; +-} +-EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_range_irqs); +-#endif +- +-/** +- * platform_msi_domain_free_irqs - Free MSI interrupts for @dev +- * @dev: The device for which to free interrupts +- */ +-void platform_msi_domain_free_irqs(struct device *dev) +-{ +- msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN); +- platform_msi_free_priv_data(dev); +-} +-EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs); + + /** + * platform_msi_get_host_data - Query the private data associated with +@@ -380,3 +340,104 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir + + return msi_domain_populate_irqs(domain->parent, dev, virq, nr_irqs, &data->arg); + } ++ ++/* End of removal area */ ++ ++/* Real per device domain interfaces */ ++ ++/* ++ * This indirection can go when platform_device_msi_init_and_alloc_irqs() ++ * is switched to a proper irq_chip::irq_write_msi_msg() callback. Keep it ++ * simple for now. ++ */ ++static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ irq_write_msi_msg_t cb = d->chip_data; ++ ++ cb(irq_data_get_msi_desc(d), msg); ++} ++ ++static void platform_msi_set_desc_byindex(msi_alloc_info_t *arg, struct msi_desc *desc) ++{ ++ arg->desc = desc; ++ arg->hwirq = desc->msi_index; ++} ++ ++static const struct msi_domain_template platform_msi_template = { ++ .chip = { ++ .name = "pMSI", ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_write_msi_msg = platform_msi_write_msi_msg, ++ /* The rest is filled in by the platform MSI parent */ ++ }, ++ ++ .ops = { ++ .set_desc = platform_msi_set_desc_byindex, ++ }, ++ ++ .info = { ++ .bus_token = DOMAIN_BUS_DEVICE_MSI, ++ }, ++}; ++ ++/** ++ * platform_device_msi_init_and_alloc_irqs - Initialize platform device MSI ++ * and allocate interrupts for @dev ++ * @dev: The device for which to allocate interrupts ++ * @nvec: The number of interrupts to allocate ++ * @write_msi_msg: Callback to write an interrupt message for @dev ++ * ++ * Returns: ++ * Zero for success, or an error code in case of failure ++ * ++ * This creates a MSI domain on @dev which has @dev->msi.domain as ++ * parent. The parent domain sets up the new domain. The domain has ++ * a fixed size of @nvec. The domain is managed by devres and will ++ * be removed when the device is removed. ++ * ++ * Note: For migration purposes this falls back to the original platform_msi code ++ * up to the point where all platforms have been converted to the MSI ++ * parent model. ++ */ ++int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec, ++ irq_write_msi_msg_t write_msi_msg) ++{ ++ struct irq_domain *domain = dev->msi.domain; ++ ++ if (!domain || !write_msi_msg) ++ return -EINVAL; ++ ++ /* Migration support. Will go away once everything is converted */ ++ if (!irq_domain_is_msi_parent(domain)) ++ return platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg); ++ ++ /* ++ * @write_msi_msg is stored in the resulting msi_domain_info::data. ++ * The underlying domain creation mechanism will assign that ++ * callback to the resulting irq chip. ++ */ ++ if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, ++ &platform_msi_template, ++ nvec, NULL, write_msi_msg)) ++ return -ENODEV; ++ ++ return msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1); ++} ++EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs); ++ ++/** ++ * platform_device_msi_free_irqs_all - Free all interrupts for @dev ++ * @dev: The device for which to free interrupts ++ */ ++void platform_device_msi_free_irqs_all(struct device *dev) ++{ ++ struct irq_domain *domain = dev->msi.domain; ++ ++ msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN); ++ ++ /* Migration support. Will go away once everything is converted */ ++ if (!irq_domain_is_msi_parent(domain)) ++ platform_msi_free_priv_data(dev); ++} ++EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all); diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c index 0c92fa3eee88..3cb4ceb53635 100644 --- a/drivers/char/ipmi/ipmi_si_hardcode.c @@ -25022,10 +27770,10 @@ index 000000000000..8bf7a18776f8 + return clk; +} diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig -index 1389f095e2e5..0f821fa01df8 100644 +index 6432eb93a80f..79434f69518c 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig -@@ -366,5 +366,14 @@ config QORIQ_CPUFREQ +@@ -365,5 +365,14 @@ config QORIQ_CPUFREQ This adds the CPUFreq driver support for Freescale QorIQ SoCs which are capable of changing the CPU's frequency dynamically. @@ -25917,6 +28665,63 @@ index 8521530a34ec..1e4080928e02 100644 #define CH_BLOCK_TS 0x010 /* R/W Chan Block Transfer Size */ #define CH_CTL 0x018 /* R/W Chan Control */ #define CH_CTL_L 0x018 /* R/W Chan Control 00-31 */ +diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c +index 0e1e9ca1c005..cd2b9a6ab621 100644 +--- a/drivers/dma/mv_xor_v2.c ++++ b/drivers/dma/mv_xor_v2.c +@@ -747,8 +747,8 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + if (IS_ERR(xor_dev->clk)) + return PTR_ERR(xor_dev->clk); + +- ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1, +- mv_xor_v2_set_msi_msg); ++ ret = platform_device_msi_init_and_alloc_irqs(&pdev->dev, 1, ++ mv_xor_v2_set_msi_msg); + if (ret) + return ret; + +@@ -851,7 +851,7 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + xor_dev->desc_size * MV_XOR_V2_DESC_NUM, + xor_dev->hw_desq_virt, xor_dev->hw_desq); + free_msi_irqs: +- platform_msi_domain_free_irqs(&pdev->dev); ++ platform_device_msi_free_irqs_all(&pdev->dev); + return ret; + } + +@@ -867,7 +867,7 @@ static int mv_xor_v2_remove(struct platform_device *pdev) + + devm_free_irq(&pdev->dev, xor_dev->irq, xor_dev); + +- platform_msi_domain_free_irqs(&pdev->dev); ++ platform_device_msi_free_irqs_all(&pdev->dev); + + tasklet_kill(&xor_dev->irq_tasklet); + +diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c +index 834ae519c15d..f2b299c23b1e 100644 +--- a/drivers/dma/qcom/hidma.c ++++ b/drivers/dma/qcom/hidma.c +@@ -696,7 +696,7 @@ static void hidma_free_msis(struct hidma_dev *dmadev) + devm_free_irq(dev, virq, &dmadev->lldev); + } + +- platform_msi_domain_free_irqs(dev); ++ platform_device_msi_free_irqs_all(dev); + #endif + } + +@@ -706,8 +706,8 @@ static int hidma_request_msi(struct hidma_dev *dmadev, + #ifdef CONFIG_GENERIC_MSI_IRQ + int rc, i, virq; + +- rc = platform_msi_domain_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS, +- hidma_write_msi_msg); ++ rc = platform_device_msi_init_and_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS, ++ hidma_write_msi_msg); + if (rc) + return rc; + diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index cc4716c037a6..a8c03e495ac4 100644 --- a/drivers/firmware/Kconfig @@ -27004,7 +29809,7 @@ index a5b92adb8aff..486d14f1495a 100644 tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index b120267fbe40..dc7644145a1f 100644 +index 7ba2ec90c3f7..183e306f0c6e 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -184,6 +184,7 @@ obj-y += hisilicon/ @@ -27016,7 +29821,7 @@ index b120267fbe40..dc7644145a1f 100644 obj-$(CONFIG_DRM_XEN) += xen/ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/ @@ -200,3 +201,4 @@ obj-$(CONFIG_DRM_SPRD) += sprd/ - obj-$(CONFIG_DRM_LOONGSON) += loongson/ + obj-y += loongson/ obj-$(CONFIG_DRM_PHYTIUM) += phytium/ obj-$(CONFIG_HYDCU_FIXUP_HEADER) += hygon/hydcu-fixup-header/ +obj-$(CONFIG_DRM_VERISILICON) += verisilicon/ @@ -27034,14 +29839,18 @@ index c3d9ca137bea..465409a6114e 100644 return 0; diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig -index 901d1961b739..90489b55efa7 100644 +index 901d1961b739..49b33b2f6701 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig -@@ -9,6 +9,7 @@ config DRM_AMD_DC +@@ -8,7 +8,10 @@ config DRM_AMD_DC + depends on BROKEN || !CC_IS_CLANG || ARM64 || RISCV || SPARC64 || X86_64 select SND_HDA_COMPONENT if SND_HDA_CORE # !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752 - select DRM_AMD_DC_FP if (X86 || LOONGARCH || (PPC64 && ALTIVEC) || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) -+ select DRM_AMD_DC_DCN if RISCV && FPU +- select DRM_AMD_DC_FP if (X86 || LOONGARCH || (PPC64 && ALTIVEC) || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) ++ select DRM_AMD_DC_FP if ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG ++ select DRM_AMD_DC_FP if PPC64 && ALTIVEC ++ select DRM_AMD_DC_FP if RISCV && FPU ++ select DRM_AMD_DC_FP if LOONGARCH || X86 help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and @@ -346394,7 +349203,7 @@ index 000000000000..913746dc5387 + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index f15e364622e7..f022b98b1b90 100644 +index 738519b0a9cb..4f03df727b07 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o @@ -347853,6 +350662,2642 @@ index 000000000000..8a4f21e1cb17 + /* lock to protect against multiple access to the device */ + struct mutex mlock; +}; +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index 6ef522ce745b..d16d701a4447 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -4320,7 +4320,8 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr) + static void arm_smmu_free_msis(void *data) + { + struct device *dev = data; +- platform_msi_domain_free_irqs(dev); ++ ++ platform_device_msi_free_irqs_all(dev); + } + + static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) +@@ -4377,7 +4378,7 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu) + } + + /* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */ +- ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg); ++ ret = platform_device_msi_init_and_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg); + if (ret) { + dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n"); + return; +diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig +index 6edafab595e6..73546cc81c5a 100644 +--- a/drivers/irqchip/Kconfig ++++ b/drivers/irqchip/Kconfig +@@ -602,6 +602,31 @@ config RISCV_INTC + depends on RISCV + select IRQ_DOMAIN_HIERARCHY + ++config RISCV_APLIC ++ bool ++ depends on RISCV ++ select IRQ_DOMAIN_HIERARCHY ++ ++config RISCV_APLIC_MSI ++ bool ++ depends on RISCV_APLIC ++ select GENERIC_MSI_IRQ ++ default RISCV_APLIC ++ ++config RISCV_IMSIC ++ bool ++ depends on RISCV ++ select IRQ_DOMAIN_HIERARCHY ++ select GENERIC_IRQ_MATRIX_ALLOCATOR ++ select GENERIC_MSI_IRQ ++ ++config RISCV_IMSIC_PCI ++ bool ++ depends on RISCV_IMSIC ++ depends on PCI ++ depends on PCI_MSI ++ default RISCV_IMSIC ++ + config SIFIVE_PLIC + bool + depends on RISCV +diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile +index f4697c1a39c0..51b46cab7a2f 100644 +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -103,6 +103,9 @@ obj-$(CONFIG_QCOM_MPM) += irq-qcom-mpm.o + obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o + obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o + obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o ++obj-$(CONFIG_RISCV_APLIC) += irq-riscv-aplic-main.o irq-riscv-aplic-direct.o ++obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o ++obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o + obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o + obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o + obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o +diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c +new file mode 100644 +index 000000000000..4a3ffe856d6c +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-aplic-direct.c +@@ -0,0 +1,323 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "irq-riscv-aplic-main.h" ++ ++#define APLIC_DISABLE_IDELIVERY 0 ++#define APLIC_ENABLE_IDELIVERY 1 ++#define APLIC_DISABLE_ITHRESHOLD 1 ++#define APLIC_ENABLE_ITHRESHOLD 0 ++ ++struct aplic_direct { ++ struct aplic_priv priv; ++ struct irq_domain *irqdomain; ++ struct cpumask lmask; ++}; ++ ++struct aplic_idc { ++ unsigned int hart_index; ++ void __iomem *regs; ++ struct aplic_direct *direct; ++}; ++ ++static unsigned int aplic_direct_parent_irq; ++static DEFINE_PER_CPU(struct aplic_idc, aplic_idcs); ++ ++static void aplic_direct_irq_eoi(struct irq_data *d) ++{ ++ /* ++ * The fasteoi_handler requires irq_eoi() callback hence ++ * provide a dummy handler. ++ */ ++} ++ ++#ifdef CONFIG_SMP ++static int aplic_direct_set_affinity(struct irq_data *d, const struct cpumask *mask_val, ++ bool force) ++{ ++ struct aplic_priv *priv = irq_data_get_irq_chip_data(d); ++ struct aplic_direct *direct = container_of(priv, struct aplic_direct, priv); ++ struct aplic_idc *idc; ++ unsigned int cpu, val; ++ void __iomem *target; ++ ++ if (force) ++ cpu = cpumask_first_and(&direct->lmask, mask_val); ++ else ++ cpu = cpumask_first_and_and(&direct->lmask, mask_val, cpu_online_mask); ++ ++ if (cpu >= nr_cpu_ids) ++ return -EINVAL; ++ ++ idc = per_cpu_ptr(&aplic_idcs, cpu); ++ target = priv->regs + APLIC_TARGET_BASE + (d->hwirq - 1) * sizeof(u32); ++ val = FIELD_PREP(APLIC_TARGET_HART_IDX, idc->hart_index); ++ val |= FIELD_PREP(APLIC_TARGET_IPRIO, APLIC_DEFAULT_PRIORITY); ++ writel(val, target); ++ ++ irq_data_update_effective_affinity(d, cpumask_of(cpu)); ++ ++ return IRQ_SET_MASK_OK_DONE; ++} ++#endif ++ ++static struct irq_chip aplic_direct_chip = { ++ .name = "APLIC-DIRECT", ++ .irq_mask = aplic_irq_mask, ++ .irq_unmask = aplic_irq_unmask, ++ .irq_set_type = aplic_irq_set_type, ++ .irq_eoi = aplic_direct_irq_eoi, ++#ifdef CONFIG_SMP ++ .irq_set_affinity = aplic_direct_set_affinity, ++#endif ++ .flags = IRQCHIP_SET_TYPE_MASKED | ++ IRQCHIP_SKIP_SET_WAKE | ++ IRQCHIP_MASK_ON_SUSPEND, ++}; ++ ++static int aplic_direct_irqdomain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, ++ unsigned long *hwirq, unsigned int *type) ++{ ++ struct aplic_priv *priv = d->host_data; ++ ++ return aplic_irqdomain_translate(fwspec, priv->gsi_base, hwirq, type); ++} ++ ++static int aplic_direct_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *arg) ++{ ++ struct aplic_priv *priv = domain->host_data; ++ struct aplic_direct *direct = container_of(priv, struct aplic_direct, priv); ++ struct irq_fwspec *fwspec = arg; ++ irq_hw_number_t hwirq; ++ unsigned int type; ++ int i, ret; ++ ++ ret = aplic_irqdomain_translate(fwspec, priv->gsi_base, &hwirq, &type); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < nr_irqs; i++) { ++ irq_domain_set_info(domain, virq + i, hwirq + i, &aplic_direct_chip, ++ priv, handle_fasteoi_irq, NULL, NULL); ++ irq_set_affinity(virq + i, &direct->lmask); ++ } ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops aplic_direct_irqdomain_ops = { ++ .translate = aplic_direct_irqdomain_translate, ++ .alloc = aplic_direct_irqdomain_alloc, ++ .free = irq_domain_free_irqs_top, ++}; ++ ++/* ++ * To handle an APLIC direct interrupts, we just read the CLAIMI register ++ * which will return highest priority pending interrupt and clear the ++ * pending bit of the interrupt. This process is repeated until CLAIMI ++ * register return zero value. ++ */ ++static void aplic_direct_handle_irq(struct irq_desc *desc) ++{ ++ struct aplic_idc *idc = this_cpu_ptr(&aplic_idcs); ++ struct irq_domain *irqdomain = idc->direct->irqdomain; ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ irq_hw_number_t hw_irq; ++ int irq; ++ ++ chained_irq_enter(chip, desc); ++ ++ while ((hw_irq = readl(idc->regs + APLIC_IDC_CLAIMI))) { ++ hw_irq = hw_irq >> APLIC_IDC_TOPI_ID_SHIFT; ++ irq = irq_find_mapping(irqdomain, hw_irq); ++ ++ if (unlikely(irq <= 0)) { ++ dev_warn_ratelimited(idc->direct->priv.dev, ++ "hw_irq %lu mapping not found\n", hw_irq); ++ } else { ++ generic_handle_irq(irq); ++ } ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static void aplic_idc_set_delivery(struct aplic_idc *idc, bool en) ++{ ++ u32 de = (en) ? APLIC_ENABLE_IDELIVERY : APLIC_DISABLE_IDELIVERY; ++ u32 th = (en) ? APLIC_ENABLE_ITHRESHOLD : APLIC_DISABLE_ITHRESHOLD; ++ ++ /* Priority must be less than threshold for interrupt triggering */ ++ writel(th, idc->regs + APLIC_IDC_ITHRESHOLD); ++ ++ /* Delivery must be set to 1 for interrupt triggering */ ++ writel(de, idc->regs + APLIC_IDC_IDELIVERY); ++} ++ ++static int aplic_direct_dying_cpu(unsigned int cpu) ++{ ++ if (aplic_direct_parent_irq) ++ disable_percpu_irq(aplic_direct_parent_irq); ++ ++ return 0; ++} ++ ++static int aplic_direct_starting_cpu(unsigned int cpu) ++{ ++ if (aplic_direct_parent_irq) { ++ enable_percpu_irq(aplic_direct_parent_irq, ++ irq_get_trigger_type(aplic_direct_parent_irq)); ++ } ++ ++ return 0; ++} ++ ++static int aplic_direct_parse_parent_hwirq(struct device *dev, u32 index, ++ u32 *parent_hwirq, unsigned long *parent_hartid) ++{ ++ struct of_phandle_args parent; ++ int rc; ++ ++ /* ++ * Currently, only OF fwnode is supported so extend this ++ * function for ACPI support. ++ */ ++ if (!is_of_node(dev->fwnode)) ++ return -EINVAL; ++ ++ rc = of_irq_parse_one(to_of_node(dev->fwnode), index, &parent); ++ if (rc) ++ return rc; ++ ++ rc = riscv_of_parent_hartid(parent.np, parent_hartid); ++ if (rc) ++ return rc; ++ ++ *parent_hwirq = parent.args[0]; ++ return 0; ++} ++ ++int aplic_direct_setup(struct device *dev, void __iomem *regs) ++{ ++ int i, j, rc, cpu, current_cpu, setup_count = 0; ++ struct aplic_direct *direct; ++ struct irq_domain *domain; ++ struct aplic_priv *priv; ++ struct aplic_idc *idc; ++ unsigned long hartid; ++ u32 v, hwirq; ++ ++ direct = devm_kzalloc(dev, sizeof(*direct), GFP_KERNEL); ++ if (!direct) ++ return -ENOMEM; ++ priv = &direct->priv; ++ ++ rc = aplic_setup_priv(priv, dev, regs); ++ if (rc) { ++ dev_err(dev, "failed to create APLIC context\n"); ++ return rc; ++ } ++ ++ /* Setup per-CPU IDC and target CPU mask */ ++ current_cpu = get_cpu(); ++ for (i = 0; i < priv->nr_idcs; i++) { ++ rc = aplic_direct_parse_parent_hwirq(dev, i, &hwirq, &hartid); ++ if (rc) { ++ dev_warn(dev, "parent irq for IDC%d not found\n", i); ++ continue; ++ } ++ ++ /* ++ * Skip interrupts other than external interrupts for ++ * current privilege level. ++ */ ++ if (hwirq != RV_IRQ_EXT) ++ continue; ++ ++ cpu = riscv_hartid_to_cpuid(hartid); ++ if (cpu < 0) { ++ dev_warn(dev, "invalid cpuid for IDC%d\n", i); ++ continue; ++ } ++ ++ cpumask_set_cpu(cpu, &direct->lmask); ++ ++ idc = per_cpu_ptr(&aplic_idcs, cpu); ++ idc->hart_index = i; ++ idc->regs = priv->regs + APLIC_IDC_BASE + i * APLIC_IDC_SIZE; ++ idc->direct = direct; ++ ++ aplic_idc_set_delivery(idc, true); ++ ++ /* ++ * Boot cpu might not have APLIC hart_index = 0 so check ++ * and update target registers of all interrupts. ++ */ ++ if (cpu == current_cpu && idc->hart_index) { ++ v = FIELD_PREP(APLIC_TARGET_HART_IDX, idc->hart_index); ++ v |= FIELD_PREP(APLIC_TARGET_IPRIO, APLIC_DEFAULT_PRIORITY); ++ for (j = 1; j <= priv->nr_irqs; j++) ++ writel(v, priv->regs + APLIC_TARGET_BASE + (j - 1) * sizeof(u32)); ++ } ++ ++ setup_count++; ++ } ++ put_cpu(); ++ ++ /* Find parent domain and register chained handler */ ++ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), ++ DOMAIN_BUS_ANY); ++ if (!aplic_direct_parent_irq && domain) { ++ aplic_direct_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT); ++ if (aplic_direct_parent_irq) { ++ irq_set_chained_handler(aplic_direct_parent_irq, ++ aplic_direct_handle_irq); ++ ++ /* ++ * Setup CPUHP notifier to enable parent ++ * interrupt on all CPUs ++ */ ++ cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, ++ "irqchip/riscv/aplic:starting", ++ aplic_direct_starting_cpu, ++ aplic_direct_dying_cpu); ++ } ++ } ++ ++ /* Fail if we were not able to setup IDC for any CPU */ ++ if (!setup_count) ++ return -ENODEV; ++ ++ /* Setup global config and interrupt delivery */ ++ aplic_init_hw_global(priv, false); ++ ++ /* Create irq domain instance for the APLIC */ ++ direct->irqdomain = irq_domain_create_linear(dev->fwnode, priv->nr_irqs + 1, ++ &aplic_direct_irqdomain_ops, priv); ++ if (!direct->irqdomain) { ++ dev_err(dev, "failed to create direct irq domain\n"); ++ return -ENOMEM; ++ } ++ ++ /* Advertise the interrupt controller */ ++ dev_info(dev, "%d interrupts directly connected to %d CPUs\n", ++ priv->nr_irqs, priv->nr_idcs); ++ ++ return 0; ++} +diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c +new file mode 100644 +index 000000000000..4ed7a1db7776 +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-aplic-main.c +@@ -0,0 +1,211 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "irq-riscv-aplic-main.h" ++ ++void aplic_irq_unmask(struct irq_data *d) ++{ ++ struct aplic_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ writel(d->hwirq, priv->regs + APLIC_SETIENUM); ++} ++ ++void aplic_irq_mask(struct irq_data *d) ++{ ++ struct aplic_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ writel(d->hwirq, priv->regs + APLIC_CLRIENUM); ++} ++ ++int aplic_irq_set_type(struct irq_data *d, unsigned int type) ++{ ++ struct aplic_priv *priv = irq_data_get_irq_chip_data(d); ++ void __iomem *sourcecfg; ++ u32 val = 0; ++ ++ switch (type) { ++ case IRQ_TYPE_NONE: ++ val = APLIC_SOURCECFG_SM_INACTIVE; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ val = APLIC_SOURCECFG_SM_LEVEL_LOW; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ val = APLIC_SOURCECFG_SM_LEVEL_HIGH; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ val = APLIC_SOURCECFG_SM_EDGE_FALL; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ val = APLIC_SOURCECFG_SM_EDGE_RISE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ sourcecfg = priv->regs + APLIC_SOURCECFG_BASE; ++ sourcecfg += (d->hwirq - 1) * sizeof(u32); ++ writel(val, sourcecfg); ++ ++ return 0; ++} ++ ++int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base, ++ unsigned long *hwirq, unsigned int *type) ++{ ++ if (WARN_ON(fwspec->param_count < 2)) ++ return -EINVAL; ++ if (WARN_ON(!fwspec->param[0])) ++ return -EINVAL; ++ ++ /* For DT, gsi_base is always zero. */ ++ *hwirq = fwspec->param[0] - gsi_base; ++ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; ++ ++ WARN_ON(*type == IRQ_TYPE_NONE); ++ ++ return 0; ++} ++ ++void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode) ++{ ++ u32 val; ++#ifdef CONFIG_RISCV_M_MODE ++ u32 valh; ++ ++ if (msi_mode) { ++ val = lower_32_bits(priv->msicfg.base_ppn); ++ valh = FIELD_PREP(APLIC_xMSICFGADDRH_BAPPN, upper_32_bits(priv->msicfg.base_ppn)); ++ valh |= FIELD_PREP(APLIC_xMSICFGADDRH_LHXW, priv->msicfg.lhxw); ++ valh |= FIELD_PREP(APLIC_xMSICFGADDRH_HHXW, priv->msicfg.hhxw); ++ valh |= FIELD_PREP(APLIC_xMSICFGADDRH_LHXS, priv->msicfg.lhxs); ++ valh |= FIELD_PREP(APLIC_xMSICFGADDRH_HHXS, priv->msicfg.hhxs); ++ writel(val, priv->regs + APLIC_xMSICFGADDR); ++ writel(valh, priv->regs + APLIC_xMSICFGADDRH); ++ } ++#endif ++ ++ /* Setup APLIC domaincfg register */ ++ val = readl(priv->regs + APLIC_DOMAINCFG); ++ val |= APLIC_DOMAINCFG_IE; ++ if (msi_mode) ++ val |= APLIC_DOMAINCFG_DM; ++ writel(val, priv->regs + APLIC_DOMAINCFG); ++ if (readl(priv->regs + APLIC_DOMAINCFG) != val) ++ dev_warn(priv->dev, "unable to write 0x%x in domaincfg\n", val); ++} ++ ++static void aplic_init_hw_irqs(struct aplic_priv *priv) ++{ ++ int i; ++ ++ /* Disable all interrupts */ ++ for (i = 0; i <= priv->nr_irqs; i += 32) ++ writel(-1U, priv->regs + APLIC_CLRIE_BASE + (i / 32) * sizeof(u32)); ++ ++ /* Set interrupt type and default priority for all interrupts */ ++ for (i = 1; i <= priv->nr_irqs; i++) { ++ writel(0, priv->regs + APLIC_SOURCECFG_BASE + (i - 1) * sizeof(u32)); ++ writel(APLIC_DEFAULT_PRIORITY, ++ priv->regs + APLIC_TARGET_BASE + (i - 1) * sizeof(u32)); ++ } ++ ++ /* Clear APLIC domaincfg */ ++ writel(0, priv->regs + APLIC_DOMAINCFG); ++} ++ ++int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs) ++{ ++ struct device_node *np = to_of_node(dev->fwnode); ++ struct of_phandle_args parent; ++ int rc; ++ ++ /* ++ * Currently, only OF fwnode is supported so extend this ++ * function for ACPI support. ++ */ ++ if (!np) ++ return -EINVAL; ++ ++ /* Save device pointer and register base */ ++ priv->dev = dev; ++ priv->regs = regs; ++ ++ /* Find out number of interrupt sources */ ++ rc = of_property_read_u32(np, "riscv,num-sources", &priv->nr_irqs); ++ if (rc) { ++ dev_err(dev, "failed to get number of interrupt sources\n"); ++ return rc; ++ } ++ ++ /* ++ * Find out number of IDCs based on parent interrupts ++ * ++ * If "msi-parent" property is present then we ignore the ++ * APLIC IDCs which forces the APLIC driver to use MSI mode. ++ */ ++ if (!of_property_present(np, "msi-parent")) { ++ while (!of_irq_parse_one(np, priv->nr_idcs, &parent)) ++ priv->nr_idcs++; ++ } ++ ++ /* Setup initial state APLIC interrupts */ ++ aplic_init_hw_irqs(priv); ++ ++ return 0; ++} ++ ++static int aplic_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ bool msi_mode = false; ++ void __iomem *regs; ++ int rc; ++ ++ /* Map the MMIO registers */ ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) { ++ dev_err(dev, "failed map MMIO registers\n"); ++ return PTR_ERR(regs); ++ } ++ ++ /* ++ * If msi-parent property is present then setup APLIC MSI ++ * mode otherwise setup APLIC direct mode. ++ */ ++ msi_mode = of_property_present(to_of_node(dev->fwnode), "msi-parent"); ++ if (msi_mode) ++ rc = aplic_msi_setup(dev, regs); ++ else ++ rc = aplic_direct_setup(dev, regs); ++ if (rc) ++ dev_err_probe(dev, rc, "failed to setup APLIC in %s mode\n", ++ msi_mode ? "MSI" : "direct"); ++ ++ return rc; ++} ++ ++static const struct of_device_id aplic_match[] = { ++ { .compatible = "riscv,aplic" }, ++ {} ++}; ++ ++static struct platform_driver aplic_driver = { ++ .driver = { ++ .name = "riscv-aplic", ++ .of_match_table = aplic_match, ++ }, ++ .probe = aplic_probe, ++}; ++builtin_platform_driver(aplic_driver); +diff --git a/drivers/irqchip/irq-riscv-aplic-main.h b/drivers/irqchip/irq-riscv-aplic-main.h +new file mode 100644 +index 000000000000..4393927d8c80 +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-aplic-main.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#ifndef _IRQ_RISCV_APLIC_MAIN_H ++#define _IRQ_RISCV_APLIC_MAIN_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define APLIC_DEFAULT_PRIORITY 1 ++ ++struct aplic_msicfg { ++ phys_addr_t base_ppn; ++ u32 hhxs; ++ u32 hhxw; ++ u32 lhxs; ++ u32 lhxw; ++}; ++ ++struct aplic_priv { ++ struct device *dev; ++ u32 gsi_base; ++ u32 nr_irqs; ++ u32 nr_idcs; ++ void __iomem *regs; ++ struct aplic_msicfg msicfg; ++}; ++ ++void aplic_irq_unmask(struct irq_data *d); ++void aplic_irq_mask(struct irq_data *d); ++int aplic_irq_set_type(struct irq_data *d, unsigned int type); ++int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base, ++ unsigned long *hwirq, unsigned int *type); ++void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode); ++int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs); ++int aplic_direct_setup(struct device *dev, void __iomem *regs); ++#ifdef CONFIG_RISCV_APLIC_MSI ++int aplic_msi_setup(struct device *dev, void __iomem *regs); ++#else ++static inline int aplic_msi_setup(struct device *dev, void __iomem *regs) ++{ ++ return -ENODEV; ++} ++#endif ++ ++#endif +diff --git a/drivers/irqchip/irq-riscv-aplic-msi.c b/drivers/irqchip/irq-riscv-aplic-msi.c +new file mode 100644 +index 000000000000..c4a5b375a75f +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-aplic-msi.c +@@ -0,0 +1,278 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "irq-riscv-aplic-main.h" ++ ++static void aplic_msi_irq_mask(struct irq_data *d) ++{ ++ aplic_irq_mask(d); ++ irq_chip_mask_parent(d); ++} ++ ++static void aplic_msi_irq_unmask(struct irq_data *d) ++{ ++ irq_chip_unmask_parent(d); ++ aplic_irq_unmask(d); ++} ++ ++static void aplic_msi_irq_retrigger_level(struct irq_data *d) ++{ ++ struct aplic_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ switch (irqd_get_trigger_type(d)) { ++ case IRQ_TYPE_LEVEL_LOW: ++ case IRQ_TYPE_LEVEL_HIGH: ++ /* ++ * The section "4.9.2 Special consideration for level-sensitive interrupt ++ * sources" of the RISC-V AIA specification says: ++ * ++ * A second option is for the interrupt service routine to write the ++ * APLIC’s source identity number for the interrupt to the domain’s ++ * setipnum register just before exiting. This will cause the interrupt’s ++ * pending bit to be set to one again if the source is still asserting ++ * an interrupt, but not if the source is not asserting an interrupt. ++ */ ++ writel(d->hwirq, priv->regs + APLIC_SETIPNUM_LE); ++ break; ++ } ++} ++ ++static void aplic_msi_irq_eoi(struct irq_data *d) ++{ ++ /* ++ * EOI handling is required only for level-triggered interrupts ++ * when APLIC is in MSI mode. ++ */ ++ aplic_msi_irq_retrigger_level(d); ++} ++ ++static int aplic_msi_irq_set_type(struct irq_data *d, unsigned int type) ++{ ++ int rc = aplic_irq_set_type(d, type); ++ ++ if (rc) ++ return rc; ++ /* ++ * Updating sourcecfg register for level-triggered interrupts ++ * requires interrupt retriggering when APLIC is in MSI mode. ++ */ ++ aplic_msi_irq_retrigger_level(d); ++ return 0; ++} ++ ++static void aplic_msi_write_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ unsigned int group_index, hart_index, guest_index, val; ++ struct aplic_priv *priv = irq_data_get_irq_chip_data(d); ++ struct aplic_msicfg *mc = &priv->msicfg; ++ phys_addr_t tppn, tbppn, msg_addr; ++ void __iomem *target; ++ ++ /* For zeroed MSI, simply write zero into the target register */ ++ if (!msg->address_hi && !msg->address_lo && !msg->data) { ++ target = priv->regs + APLIC_TARGET_BASE; ++ target += (d->hwirq - 1) * sizeof(u32); ++ writel(0, target); ++ return; ++ } ++ ++ /* Sanity check on message data */ ++ WARN_ON(msg->data > APLIC_TARGET_EIID_MASK); ++ ++ /* Compute target MSI address */ ++ msg_addr = (((u64)msg->address_hi) << 32) | msg->address_lo; ++ tppn = msg_addr >> APLIC_xMSICFGADDR_PPN_SHIFT; ++ ++ /* Compute target HART Base PPN */ ++ tbppn = tppn; ++ tbppn &= ~APLIC_xMSICFGADDR_PPN_HART(mc->lhxs); ++ tbppn &= ~APLIC_xMSICFGADDR_PPN_LHX(mc->lhxw, mc->lhxs); ++ tbppn &= ~APLIC_xMSICFGADDR_PPN_HHX(mc->hhxw, mc->hhxs); ++ WARN_ON(tbppn != mc->base_ppn); ++ ++ /* Compute target group and hart indexes */ ++ group_index = (tppn >> APLIC_xMSICFGADDR_PPN_HHX_SHIFT(mc->hhxs)) & ++ APLIC_xMSICFGADDR_PPN_HHX_MASK(mc->hhxw); ++ hart_index = (tppn >> APLIC_xMSICFGADDR_PPN_LHX_SHIFT(mc->lhxs)) & ++ APLIC_xMSICFGADDR_PPN_LHX_MASK(mc->lhxw); ++ hart_index |= (group_index << mc->lhxw); ++ WARN_ON(hart_index > APLIC_TARGET_HART_IDX_MASK); ++ ++ /* Compute target guest index */ ++ guest_index = tppn & APLIC_xMSICFGADDR_PPN_HART(mc->lhxs); ++ WARN_ON(guest_index > APLIC_TARGET_GUEST_IDX_MASK); ++ ++ /* Update IRQ TARGET register */ ++ target = priv->regs + APLIC_TARGET_BASE; ++ target += (d->hwirq - 1) * sizeof(u32); ++ val = FIELD_PREP(APLIC_TARGET_HART_IDX, hart_index); ++ val |= FIELD_PREP(APLIC_TARGET_GUEST_IDX, guest_index); ++ val |= FIELD_PREP(APLIC_TARGET_EIID, msg->data); ++ writel(val, target); ++} ++ ++static void aplic_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) ++{ ++ arg->desc = desc; ++ arg->hwirq = (u32)desc->data.icookie.value; ++} ++ ++static int aplic_msi_translate(struct irq_domain *d, struct irq_fwspec *fwspec, ++ unsigned long *hwirq, unsigned int *type) ++{ ++ struct msi_domain_info *info = d->host_data; ++ struct aplic_priv *priv = info->data; ++ ++ return aplic_irqdomain_translate(fwspec, priv->gsi_base, hwirq, type); ++} ++ ++static const struct msi_domain_template aplic_msi_template = { ++ .chip = { ++ .name = "APLIC-MSI", ++ .irq_mask = aplic_msi_irq_mask, ++ .irq_unmask = aplic_msi_irq_unmask, ++ .irq_set_type = aplic_msi_irq_set_type, ++ .irq_eoi = aplic_msi_irq_eoi, ++#ifdef CONFIG_SMP ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++#endif ++ .irq_write_msi_msg = aplic_msi_write_msg, ++ .flags = IRQCHIP_SET_TYPE_MASKED | ++ IRQCHIP_SKIP_SET_WAKE | ++ IRQCHIP_MASK_ON_SUSPEND, ++ }, ++ ++ .ops = { ++ .set_desc = aplic_msi_set_desc, ++ .msi_translate = aplic_msi_translate, ++ }, ++ ++ .info = { ++ .bus_token = DOMAIN_BUS_WIRED_TO_MSI, ++ .flags = MSI_FLAG_USE_DEV_FWNODE, ++ .handler = handle_fasteoi_irq, ++ .handler_name = "fasteoi", ++ }, ++}; ++ ++int aplic_msi_setup(struct device *dev, void __iomem *regs) ++{ ++ const struct imsic_global_config *imsic_global; ++ struct aplic_priv *priv; ++ struct aplic_msicfg *mc; ++ phys_addr_t pa; ++ int rc; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ rc = aplic_setup_priv(priv, dev, regs); ++ if (rc) { ++ dev_err(dev, "failed to create APLIC context\n"); ++ return rc; ++ } ++ mc = &priv->msicfg; ++ ++ /* ++ * The APLIC outgoing MSI config registers assume target MSI ++ * controller to be RISC-V AIA IMSIC controller. ++ */ ++ imsic_global = imsic_get_global_config(); ++ if (!imsic_global) { ++ dev_err(dev, "IMSIC global config not found\n"); ++ return -ENODEV; ++ } ++ ++ /* Find number of guest index bits (LHXS) */ ++ mc->lhxs = imsic_global->guest_index_bits; ++ if (APLIC_xMSICFGADDRH_LHXS_MASK < mc->lhxs) { ++ dev_err(dev, "IMSIC guest index bits big for APLIC LHXS\n"); ++ return -EINVAL; ++ } ++ ++ /* Find number of HART index bits (LHXW) */ ++ mc->lhxw = imsic_global->hart_index_bits; ++ if (APLIC_xMSICFGADDRH_LHXW_MASK < mc->lhxw) { ++ dev_err(dev, "IMSIC hart index bits big for APLIC LHXW\n"); ++ return -EINVAL; ++ } ++ ++ /* Find number of group index bits (HHXW) */ ++ mc->hhxw = imsic_global->group_index_bits; ++ if (APLIC_xMSICFGADDRH_HHXW_MASK < mc->hhxw) { ++ dev_err(dev, "IMSIC group index bits big for APLIC HHXW\n"); ++ return -EINVAL; ++ } ++ ++ /* Find first bit position of group index (HHXS) */ ++ mc->hhxs = imsic_global->group_index_shift; ++ if (mc->hhxs < (2 * APLIC_xMSICFGADDR_PPN_SHIFT)) { ++ dev_err(dev, "IMSIC group index shift should be >= %d\n", ++ (2 * APLIC_xMSICFGADDR_PPN_SHIFT)); ++ return -EINVAL; ++ } ++ mc->hhxs -= (2 * APLIC_xMSICFGADDR_PPN_SHIFT); ++ if (APLIC_xMSICFGADDRH_HHXS_MASK < mc->hhxs) { ++ dev_err(dev, "IMSIC group index shift big for APLIC HHXS\n"); ++ return -EINVAL; ++ } ++ ++ /* Compute PPN base */ ++ mc->base_ppn = imsic_global->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT; ++ mc->base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(mc->lhxs); ++ mc->base_ppn &= ~APLIC_xMSICFGADDR_PPN_LHX(mc->lhxw, mc->lhxs); ++ mc->base_ppn &= ~APLIC_xMSICFGADDR_PPN_HHX(mc->hhxw, mc->hhxs); ++ ++ /* Setup global config and interrupt delivery */ ++ aplic_init_hw_global(priv, true); ++ ++ /* Set the APLIC device MSI domain if not available */ ++ if (!dev_get_msi_domain(dev)) { ++ /* ++ * The device MSI domain for OF devices is only set at the ++ * time of populating/creating OF device. If the device MSI ++ * domain is discovered later after the OF device is created ++ * then we need to set it explicitly before using any platform ++ * MSI functions. ++ * ++ * In case of APLIC device, the parent MSI domain is always ++ * IMSIC and the IMSIC MSI domains are created later through ++ * the platform driver probing so we set it explicitly here. ++ */ ++ if (is_of_node(dev->fwnode)) ++ of_msi_configure(dev, to_of_node(dev->fwnode)); ++ ++ if (!dev_get_msi_domain(dev)) ++ return -EPROBE_DEFER; ++ } ++ ++ if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, &aplic_msi_template, ++ priv->nr_irqs + 1, priv, priv)) { ++ dev_err(dev, "failed to create MSI irq domain\n"); ++ return -ENOMEM; ++ } ++ ++ /* Advertise the interrupt controller */ ++ pa = priv->msicfg.base_ppn << APLIC_xMSICFGADDR_PPN_SHIFT; ++ dev_info(dev, "%d interrupts forwared to MSI base %pa\n", priv->nr_irqs, &pa); ++ ++ return 0; ++} +diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c +new file mode 100644 +index 000000000000..886418ec06cb +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-imsic-early.c +@@ -0,0 +1,201 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#define pr_fmt(fmt) "riscv-imsic: " fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "irq-riscv-imsic-state.h" ++ ++static int imsic_parent_irq; ++ ++#ifdef CONFIG_SMP ++static void imsic_ipi_send(unsigned int cpu) ++{ ++ struct imsic_local_config *local = per_cpu_ptr(imsic->global.local, cpu); ++ ++ writel_relaxed(IMSIC_IPI_ID, local->msi_va); ++} ++ ++static void imsic_ipi_starting_cpu(void) ++{ ++ /* Enable IPIs for current CPU. */ ++ __imsic_id_set_enable(IMSIC_IPI_ID); ++} ++ ++static void imsic_ipi_dying_cpu(void) ++{ ++ /* Disable IPIs for current CPU. */ ++ __imsic_id_clear_enable(IMSIC_IPI_ID); ++} ++ ++static int __init imsic_ipi_domain_init(void) ++{ ++ int virq; ++ ++ /* Create IMSIC IPI multiplexing */ ++ virq = ipi_mux_create(IMSIC_NR_IPI, imsic_ipi_send); ++ if (virq <= 0) ++ return virq < 0 ? virq : -ENOMEM; ++ ++ /* Set vIRQ range */ ++ riscv_ipi_set_virq_range(virq, IMSIC_NR_IPI, true); ++ ++ /* Announce that IMSIC is providing IPIs */ ++ pr_info("%pfwP: providing IPIs using interrupt %d\n", imsic->fwnode, IMSIC_IPI_ID); ++ ++ return 0; ++} ++#else ++static void imsic_ipi_starting_cpu(void) { } ++static void imsic_ipi_dying_cpu(void) { } ++static int __init imsic_ipi_domain_init(void) { return 0; } ++#endif ++ ++/* ++ * To handle an interrupt, we read the TOPEI CSR and write zero in one ++ * instruction. If TOPEI CSR is non-zero then we translate TOPEI.ID to ++ * Linux interrupt number and let Linux IRQ subsystem handle it. ++ */ ++static void imsic_handle_irq(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ int err, cpu = smp_processor_id(); ++ struct imsic_vector *vec; ++ unsigned long local_id; ++ ++ chained_irq_enter(chip, desc); ++ ++ while ((local_id = csr_swap(CSR_TOPEI, 0))) { ++ local_id >>= TOPEI_ID_SHIFT; ++ ++ if (local_id == IMSIC_IPI_ID) { ++ if (IS_ENABLED(CONFIG_SMP)) ++ ipi_mux_process(); ++ continue; ++ } ++ ++ if (unlikely(!imsic->base_domain)) ++ continue; ++ ++ vec = imsic_vector_from_local_id(cpu, local_id); ++ if (!vec) { ++ pr_warn_ratelimited("vector not found for local ID 0x%lx\n", local_id); ++ continue; ++ } ++ ++ err = generic_handle_domain_irq(imsic->base_domain, vec->hwirq); ++ if (unlikely(err)) ++ pr_warn_ratelimited("hwirq 0x%x mapping not found\n", vec->hwirq); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static int imsic_starting_cpu(unsigned int cpu) ++{ ++ /* Mark per-CPU IMSIC state as online */ ++ imsic_state_online(); ++ ++ /* Enable per-CPU parent interrupt */ ++ enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq)); ++ ++ /* Setup IPIs */ ++ imsic_ipi_starting_cpu(); ++ ++ /* ++ * Interrupts identities might have been enabled/disabled while ++ * this CPU was not running so sync-up local enable/disable state. ++ */ ++ imsic_local_sync_all(); ++ ++ /* Enable local interrupt delivery */ ++ imsic_local_delivery(true); ++ ++ return 0; ++} ++ ++static int imsic_dying_cpu(unsigned int cpu) ++{ ++ /* Cleanup IPIs */ ++ imsic_ipi_dying_cpu(); ++ ++ /* Mark per-CPU IMSIC state as offline */ ++ imsic_state_offline(); ++ ++ return 0; ++} ++ ++static int __init imsic_early_probe(struct fwnode_handle *fwnode) ++{ ++ struct irq_domain *domain; ++ int rc; ++ ++ /* Find parent domain and register chained handler */ ++ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); ++ if (!domain) { ++ pr_err("%pfwP: Failed to find INTC domain\n", fwnode); ++ return -ENOENT; ++ } ++ imsic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT); ++ if (!imsic_parent_irq) { ++ pr_err("%pfwP: Failed to create INTC mapping\n", fwnode); ++ return -ENOENT; ++ } ++ ++ /* Initialize IPI domain */ ++ rc = imsic_ipi_domain_init(); ++ if (rc) { ++ pr_err("%pfwP: Failed to initialize IPI domain\n", fwnode); ++ return rc; ++ } ++ ++ /* Setup chained handler to the parent domain interrupt */ ++ irq_set_chained_handler(imsic_parent_irq, imsic_handle_irq); ++ ++ /* ++ * Setup cpuhp state (must be done after setting imsic_parent_irq) ++ * ++ * Don't disable per-CPU IMSIC file when CPU goes offline ++ * because this affects IPI and the masking/unmasking of ++ * virtual IPIs is done via generic IPI-Mux ++ */ ++ cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, "irqchip/riscv/imsic:starting", ++ imsic_starting_cpu, imsic_dying_cpu); ++ ++ return 0; ++} ++ ++static int __init imsic_early_dt_init(struct device_node *node, struct device_node *parent) ++{ ++ struct fwnode_handle *fwnode = &node->fwnode; ++ int rc; ++ ++ /* Setup IMSIC state */ ++ rc = imsic_setup_state(fwnode); ++ if (rc) { ++ pr_err("%pfwP: failed to setup state (error %d)\n", fwnode, rc); ++ return rc; ++ } ++ ++ /* Do early setup of IPIs */ ++ rc = imsic_early_probe(fwnode); ++ if (rc) ++ return rc; ++ ++ /* Ensure that OF platform device gets probed */ ++ of_node_clear_flag(node, OF_POPULATED); ++ return 0; ++} ++ ++IRQCHIP_DECLARE(riscv_imsic, "riscv,imsics", imsic_early_dt_init); +diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c +new file mode 100644 +index 000000000000..c5ec66e0bfd3 +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-imsic-platform.c +@@ -0,0 +1,375 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#define pr_fmt(fmt) "riscv-imsic: " fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "irq-riscv-imsic-state.h" ++ ++static bool imsic_cpu_page_phys(unsigned int cpu, unsigned int guest_index, ++ phys_addr_t *out_msi_pa) ++{ ++ struct imsic_global_config *global; ++ struct imsic_local_config *local; ++ ++ global = &imsic->global; ++ local = per_cpu_ptr(global->local, cpu); ++ ++ if (BIT(global->guest_index_bits) <= guest_index) ++ return false; ++ ++ if (out_msi_pa) ++ *out_msi_pa = local->msi_pa + (guest_index * IMSIC_MMIO_PAGE_SZ); ++ ++ return true; ++} ++ ++static void imsic_irq_mask(struct irq_data *d) ++{ ++ imsic_vector_mask(irq_data_get_irq_chip_data(d)); ++} ++ ++static void imsic_irq_unmask(struct irq_data *d) ++{ ++ imsic_vector_unmask(irq_data_get_irq_chip_data(d)); ++} ++ ++static int imsic_irq_retrigger(struct irq_data *d) ++{ ++ struct imsic_vector *vec = irq_data_get_irq_chip_data(d); ++ struct imsic_local_config *local; ++ ++ if (WARN_ON(!vec)) ++ return -ENOENT; ++ ++ local = per_cpu_ptr(imsic->global.local, vec->cpu); ++ writel_relaxed(vec->local_id, local->msi_va); ++ return 0; ++} ++ ++static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_msg *msg) ++{ ++ phys_addr_t msi_addr; ++ ++ if (WARN_ON(!vec)) ++ return; ++ ++ if (WARN_ON(!imsic_cpu_page_phys(vec->cpu, 0, &msi_addr))) ++ return; ++ ++ msg->address_hi = upper_32_bits(msi_addr); ++ msg->address_lo = lower_32_bits(msi_addr); ++ msg->data = vec->local_id; ++} ++ ++static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ imsic_irq_compose_vector_msg(irq_data_get_irq_chip_data(d), msg); ++} ++ ++#ifdef CONFIG_SMP ++static void imsic_msi_update_msg(struct irq_data *d, struct imsic_vector *vec) ++{ ++ struct msi_msg msg = { }; ++ ++ imsic_irq_compose_vector_msg(vec, &msg); ++ irq_data_get_irq_chip(d)->irq_write_msi_msg(d, &msg); ++} ++ ++static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask_val, ++ bool force) ++{ ++ struct imsic_vector *old_vec, *new_vec; ++ struct irq_data *pd = d->parent_data; ++ ++ old_vec = irq_data_get_irq_chip_data(pd); ++ if (WARN_ON(!old_vec)) ++ return -ENOENT; ++ ++ /* If old vector cpu belongs to the target cpumask then do nothing */ ++ if (cpumask_test_cpu(old_vec->cpu, mask_val)) ++ return IRQ_SET_MASK_OK_DONE; ++ ++ /* If move is already in-flight then return failure */ ++ if (imsic_vector_get_move(old_vec)) ++ return -EBUSY; ++ ++ /* Get a new vector on the desired set of CPUs */ ++ new_vec = imsic_vector_alloc(old_vec->hwirq, mask_val); ++ if (!new_vec) ++ return -ENOSPC; ++ ++ /* Point device to the new vector */ ++ imsic_msi_update_msg(d, new_vec); ++ ++ /* Update irq descriptors with the new vector */ ++ pd->chip_data = new_vec; ++ ++ /* Update effective affinity of parent irq data */ ++ irq_data_update_effective_affinity(pd, cpumask_of(new_vec->cpu)); ++ ++ /* Move state of the old vector to the new vector */ ++ imsic_vector_move(old_vec, new_vec); ++ ++ return IRQ_SET_MASK_OK_DONE; ++} ++#endif ++ ++static struct irq_chip imsic_irq_base_chip = { ++ .name = "IMSIC", ++ .irq_mask = imsic_irq_mask, ++ .irq_unmask = imsic_irq_unmask, ++ .irq_retrigger = imsic_irq_retrigger, ++ .irq_compose_msi_msg = imsic_irq_compose_msg, ++ .flags = IRQCHIP_SKIP_SET_WAKE | ++ IRQCHIP_MASK_ON_SUSPEND, ++}; ++ ++static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *args) ++{ ++ struct imsic_vector *vec; ++ ++ /* Multi-MSI is not supported yet. */ ++ if (nr_irqs > 1) ++ return -EOPNOTSUPP; ++ ++ vec = imsic_vector_alloc(virq, cpu_online_mask); ++ if (!vec) ++ return -ENOSPC; ++ ++ irq_domain_set_info(domain, virq, virq, &imsic_irq_base_chip, vec, ++ handle_simple_irq, NULL, NULL); ++ irq_set_noprobe(virq); ++ irq_set_affinity(virq, cpu_online_mask); ++ irq_data_update_effective_affinity(irq_get_irq_data(virq), cpumask_of(vec->cpu)); ++ ++ return 0; ++} ++ ++static void imsic_irq_domain_free(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs) ++{ ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ ++ imsic_vector_free(irq_data_get_irq_chip_data(d)); ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++} ++ ++static int imsic_irq_domain_select(struct irq_domain *domain, struct irq_fwspec *fwspec, ++ enum irq_domain_bus_token bus_token) ++{ ++ const struct msi_parent_ops *ops = domain->msi_parent_ops; ++ u32 busmask = BIT(bus_token); ++ ++ if (fwspec->fwnode != domain->fwnode || fwspec->param_count != 0) ++ return 0; ++ ++ /* Handle pure domain searches */ ++ if (bus_token == ops->bus_select_token) ++ return 1; ++ ++ return !!(ops->bus_select_mask & busmask); ++} ++ ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++static void imsic_irq_debug_show(struct seq_file *m, struct irq_domain *d, ++ struct irq_data *irqd, int ind) ++{ ++ if (!irqd) { ++ imsic_vector_debug_show_summary(m, ind); ++ return; ++ } ++ ++ imsic_vector_debug_show(m, irq_data_get_irq_chip_data(irqd), ind); ++} ++#endif ++ ++static const struct irq_domain_ops imsic_base_domain_ops = { ++ .alloc = imsic_irq_domain_alloc, ++ .free = imsic_irq_domain_free, ++ .select = imsic_irq_domain_select, ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++ .debug_show = imsic_irq_debug_show, ++#endif ++}; ++ ++#ifdef CONFIG_RISCV_IMSIC_PCI ++ ++static void imsic_pci_mask_irq(struct irq_data *d) ++{ ++ pci_msi_mask_irq(d); ++ irq_chip_mask_parent(d); ++} ++ ++static void imsic_pci_unmask_irq(struct irq_data *d) ++{ ++ irq_chip_unmask_parent(d); ++ pci_msi_unmask_irq(d); ++} ++ ++#define MATCH_PCI_MSI BIT(DOMAIN_BUS_PCI_MSI) ++ ++#else ++ ++#define MATCH_PCI_MSI 0 ++ ++#endif ++ ++static bool imsic_init_dev_msi_info(struct device *dev, ++ struct irq_domain *domain, ++ struct irq_domain *real_parent, ++ struct msi_domain_info *info) ++{ ++ const struct msi_parent_ops *pops = real_parent->msi_parent_ops; ++ ++ /* MSI parent domain specific settings */ ++ switch (real_parent->bus_token) { ++ case DOMAIN_BUS_NEXUS: ++ if (WARN_ON_ONCE(domain != real_parent)) ++ return false; ++#ifdef CONFIG_SMP ++ info->chip->irq_set_affinity = imsic_irq_set_affinity; ++#endif ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ return false; ++ } ++ ++ /* Is the target supported? */ ++ switch (info->bus_token) { ++#ifdef CONFIG_RISCV_IMSIC_PCI ++ case DOMAIN_BUS_PCI_DEVICE_MSI: ++ case DOMAIN_BUS_PCI_DEVICE_MSIX: ++ info->chip->irq_mask = imsic_pci_mask_irq; ++ info->chip->irq_unmask = imsic_pci_unmask_irq; ++ break; ++#endif ++ case DOMAIN_BUS_DEVICE_MSI: ++ /* ++ * Per-device MSI should never have any MSI feature bits ++ * set. It's sole purpose is to create a dumb interrupt ++ * chip which has a device specific irq_write_msi_msg() ++ * callback. ++ */ ++ if (WARN_ON_ONCE(info->flags)) ++ return false; ++ ++ /* Core managed MSI descriptors */ ++ info->flags |= MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | ++ MSI_FLAG_FREE_MSI_DESCS; ++ break; ++ case DOMAIN_BUS_WIRED_TO_MSI: ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ return false; ++ } ++ ++ /* Use hierarchial chip operations re-trigger */ ++ info->chip->irq_retrigger = irq_chip_retrigger_hierarchy; ++ ++ /* ++ * Mask out the domain specific MSI feature flags which are not ++ * supported by the real parent. ++ */ ++ info->flags &= pops->supported_flags; ++ ++ /* Enforce the required flags */ ++ info->flags |= pops->required_flags; ++ ++ return true; ++} ++ ++#define MATCH_PLATFORM_MSI BIT(DOMAIN_BUS_PLATFORM_MSI) ++ ++static const struct msi_parent_ops imsic_msi_parent_ops = { ++ .supported_flags = MSI_GENERIC_FLAGS_MASK | ++ MSI_FLAG_PCI_MSIX, ++ .required_flags = MSI_FLAG_USE_DEF_DOM_OPS | ++ MSI_FLAG_USE_DEF_CHIP_OPS, ++ .bus_select_token = DOMAIN_BUS_NEXUS, ++ .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, ++ .init_dev_msi_info = imsic_init_dev_msi_info, ++}; ++ ++int imsic_irqdomain_init(void) ++{ ++ struct imsic_global_config *global; ++ ++ if (!imsic || !imsic->fwnode) { ++ pr_err("early driver not probed\n"); ++ return -ENODEV; ++ } ++ ++ if (imsic->base_domain) { ++ pr_err("%pfwP: irq domain already created\n", imsic->fwnode); ++ return -ENODEV; ++ } ++ ++ /* Create Base IRQ domain */ ++ imsic->base_domain = irq_domain_create_tree(imsic->fwnode, ++ &imsic_base_domain_ops, imsic); ++ if (!imsic->base_domain) { ++ pr_err("%pfwP: failed to create IMSIC base domain\n", imsic->fwnode); ++ return -ENOMEM; ++ } ++ imsic->base_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; ++ imsic->base_domain->msi_parent_ops = &imsic_msi_parent_ops; ++ ++ irq_domain_update_bus_token(imsic->base_domain, DOMAIN_BUS_NEXUS); ++ ++ global = &imsic->global; ++ pr_info("%pfwP: hart-index-bits: %d, guest-index-bits: %d\n", ++ imsic->fwnode, global->hart_index_bits, global->guest_index_bits); ++ pr_info("%pfwP: group-index-bits: %d, group-index-shift: %d\n", ++ imsic->fwnode, global->group_index_bits, global->group_index_shift); ++ pr_info("%pfwP: per-CPU IDs %d at base address %pa\n", ++ imsic->fwnode, global->nr_ids, &global->base_addr); ++ pr_info("%pfwP: total %d interrupts available\n", ++ imsic->fwnode, num_possible_cpus() * (global->nr_ids - 1)); ++ ++ return 0; ++} ++ ++static int imsic_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ ++ if (imsic && imsic->fwnode != dev->fwnode) { ++ dev_err(dev, "fwnode mismatch\n"); ++ return -ENODEV; ++ } ++ ++ return imsic_irqdomain_init(); ++} ++ ++static const struct of_device_id imsic_platform_match[] = { ++ { .compatible = "riscv,imsics" }, ++ {} ++}; ++ ++static struct platform_driver imsic_platform_driver = { ++ .driver = { ++ .name = "riscv-imsic", ++ .of_match_table = imsic_platform_match, ++ }, ++ .probe = imsic_platform_probe, ++}; ++builtin_platform_driver(imsic_platform_driver); +diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c +new file mode 100644 +index 000000000000..5479f872e62b +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-imsic-state.c +@@ -0,0 +1,865 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#define pr_fmt(fmt) "riscv-imsic: " fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "irq-riscv-imsic-state.h" ++ ++#define IMSIC_DISABLE_EIDELIVERY 0 ++#define IMSIC_ENABLE_EIDELIVERY 1 ++#define IMSIC_DISABLE_EITHRESHOLD 1 ++#define IMSIC_ENABLE_EITHRESHOLD 0 ++ ++static inline void imsic_csr_write(unsigned long reg, unsigned long val) ++{ ++ csr_write(CSR_ISELECT, reg); ++ csr_write(CSR_IREG, val); ++} ++ ++static inline unsigned long imsic_csr_read(unsigned long reg) ++{ ++ csr_write(CSR_ISELECT, reg); ++ return csr_read(CSR_IREG); ++} ++ ++static inline unsigned long imsic_csr_read_clear(unsigned long reg, unsigned long val) ++{ ++ csr_write(CSR_ISELECT, reg); ++ return csr_read_clear(CSR_IREG, val); ++} ++ ++static inline void imsic_csr_set(unsigned long reg, unsigned long val) ++{ ++ csr_write(CSR_ISELECT, reg); ++ csr_set(CSR_IREG, val); ++} ++ ++static inline void imsic_csr_clear(unsigned long reg, unsigned long val) ++{ ++ csr_write(CSR_ISELECT, reg); ++ csr_clear(CSR_IREG, val); ++} ++ ++struct imsic_priv *imsic; ++ ++const struct imsic_global_config *imsic_get_global_config(void) ++{ ++ return imsic ? &imsic->global : NULL; ++} ++EXPORT_SYMBOL_GPL(imsic_get_global_config); ++ ++static bool __imsic_eix_read_clear(unsigned long id, bool pend) ++{ ++ unsigned long isel, imask; ++ ++ isel = id / BITS_PER_LONG; ++ isel *= BITS_PER_LONG / IMSIC_EIPx_BITS; ++ isel += pend ? IMSIC_EIP0 : IMSIC_EIE0; ++ imask = BIT(id & (__riscv_xlen - 1)); ++ ++ return !!(imsic_csr_read_clear(isel, imask) & imask); ++} ++ ++static inline bool __imsic_id_read_clear_enabled(unsigned long id) ++{ ++ return __imsic_eix_read_clear(id, false); ++} ++ ++static inline bool __imsic_id_read_clear_pending(unsigned long id) ++{ ++ return __imsic_eix_read_clear(id, true); ++} ++ ++void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend, bool val) ++{ ++ unsigned long id = base_id, last_id = base_id + num_id; ++ unsigned long i, isel, ireg; ++ ++ while (id < last_id) { ++ isel = id / BITS_PER_LONG; ++ isel *= BITS_PER_LONG / IMSIC_EIPx_BITS; ++ isel += pend ? IMSIC_EIP0 : IMSIC_EIE0; ++ ++ /* ++ * Prepare the ID mask to be programmed in the ++ * IMSIC EIEx and EIPx registers. These registers ++ * are XLEN-wide and we must not touch IDs which ++ * are < base_id and >= (base_id + num_id). ++ */ ++ ireg = 0; ++ for (i = id & (__riscv_xlen - 1); id < last_id && i < __riscv_xlen; i++) { ++ ireg |= BIT(i); ++ id++; ++ } ++ ++ /* ++ * The IMSIC EIEx and EIPx registers are indirectly ++ * accessed via using ISELECT and IREG CSRs so we ++ * need to access these CSRs without getting preempted. ++ * ++ * All existing users of this function call this ++ * function with local IRQs disabled so we don't ++ * need to do anything special here. ++ */ ++ if (val) ++ imsic_csr_set(isel, ireg); ++ else ++ imsic_csr_clear(isel, ireg); ++ } ++} ++ ++static void __imsic_local_sync(struct imsic_local_priv *lpriv) ++{ ++ struct imsic_local_config *mlocal; ++ struct imsic_vector *vec, *mvec; ++ int i; ++ ++ lockdep_assert_held(&lpriv->lock); ++ ++ for_each_set_bit(i, lpriv->dirty_bitmap, imsic->global.nr_ids + 1) { ++ if (!i || i == IMSIC_IPI_ID) ++ goto skip; ++ vec = &lpriv->vectors[i]; ++ ++ if (READ_ONCE(vec->enable)) ++ __imsic_id_set_enable(i); ++ else ++ __imsic_id_clear_enable(i); ++ ++ /* ++ * If the ID was being moved to a new ID on some other CPU ++ * then we can get a MSI during the movement so check the ++ * ID pending bit and re-trigger the new ID on other CPU ++ * using MMIO write. ++ */ ++ mvec = READ_ONCE(vec->move); ++ WRITE_ONCE(vec->move, NULL); ++ if (mvec && mvec != vec) { ++ if (__imsic_id_read_clear_pending(i)) { ++ mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu); ++ writel_relaxed(mvec->local_id, mlocal->msi_va); ++ } ++ ++ imsic_vector_free(&lpriv->vectors[i]); ++ } ++ ++skip: ++ bitmap_clear(lpriv->dirty_bitmap, i, 1); ++ } ++} ++ ++void imsic_local_sync_all(void) ++{ ++ struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv); ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&lpriv->lock, flags); ++ bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1); ++ __imsic_local_sync(lpriv); ++ raw_spin_unlock_irqrestore(&lpriv->lock, flags); ++} ++ ++void imsic_local_delivery(bool enable) ++{ ++ if (enable) { ++ imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_ENABLE_EITHRESHOLD); ++ imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY); ++ return; ++ } ++ ++ imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_DISABLE_EIDELIVERY); ++ imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_DISABLE_EITHRESHOLD); ++} ++ ++#ifdef CONFIG_SMP ++static void imsic_local_timer_callback(struct timer_list *timer) ++{ ++ struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv); ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&lpriv->lock, flags); ++ __imsic_local_sync(lpriv); ++ raw_spin_unlock_irqrestore(&lpriv->lock, flags); ++} ++ ++static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu) ++{ ++ lockdep_assert_held(&lpriv->lock); ++ ++ /* ++ * The spinlock acquire/release semantics ensure that changes ++ * to vector enable, vector move and dirty bitmap are visible ++ * to the target CPU. ++ */ ++ ++ /* ++ * We schedule a timer on the target CPU if the target CPU is not ++ * same as the current CPU. An offline CPU will unconditionally ++ * synchronize IDs through imsic_starting_cpu() when the ++ * CPU is brought up. ++ */ ++ if (cpu_online(cpu)) { ++ if (cpu == smp_processor_id()) { ++ __imsic_local_sync(lpriv); ++ return; ++ } ++ ++ if (!timer_pending(&lpriv->timer)) { ++ lpriv->timer.expires = jiffies + 1; ++ add_timer_on(&lpriv->timer, cpu); ++ } ++ } ++} ++#else ++static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu) ++{ ++ lockdep_assert_held(&lpriv->lock); ++ __imsic_local_sync(lpriv); ++} ++#endif ++ ++void imsic_vector_mask(struct imsic_vector *vec) ++{ ++ struct imsic_local_priv *lpriv; ++ ++ lpriv = per_cpu_ptr(imsic->lpriv, vec->cpu); ++ if (WARN_ON_ONCE(&lpriv->vectors[vec->local_id] != vec)) ++ return; ++ ++ /* ++ * This function is called through Linux irq subsystem with ++ * irqs disabled so no need to save/restore irq flags. ++ */ ++ ++ raw_spin_lock(&lpriv->lock); ++ ++ WRITE_ONCE(vec->enable, false); ++ bitmap_set(lpriv->dirty_bitmap, vec->local_id, 1); ++ __imsic_remote_sync(lpriv, vec->cpu); ++ ++ raw_spin_unlock(&lpriv->lock); ++} ++ ++void imsic_vector_unmask(struct imsic_vector *vec) ++{ ++ struct imsic_local_priv *lpriv; ++ ++ lpriv = per_cpu_ptr(imsic->lpriv, vec->cpu); ++ if (WARN_ON_ONCE(&lpriv->vectors[vec->local_id] != vec)) ++ return; ++ ++ /* ++ * This function is called through Linux irq subsystem with ++ * irqs disabled so no need to save/restore irq flags. ++ */ ++ ++ raw_spin_lock(&lpriv->lock); ++ ++ WRITE_ONCE(vec->enable, true); ++ bitmap_set(lpriv->dirty_bitmap, vec->local_id, 1); ++ __imsic_remote_sync(lpriv, vec->cpu); ++ ++ raw_spin_unlock(&lpriv->lock); ++} ++ ++static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, struct imsic_vector *vec, ++ bool new_enable, struct imsic_vector *new_move) ++{ ++ unsigned long flags; ++ bool enabled; ++ ++ raw_spin_lock_irqsave(&lpriv->lock, flags); ++ ++ /* Update enable and move details */ ++ enabled = READ_ONCE(vec->enable); ++ WRITE_ONCE(vec->enable, new_enable); ++ WRITE_ONCE(vec->move, new_move); ++ ++ /* Mark the vector as dirty and synchronize */ ++ bitmap_set(lpriv->dirty_bitmap, vec->local_id, 1); ++ __imsic_remote_sync(lpriv, vec->cpu); ++ ++ raw_spin_unlock_irqrestore(&lpriv->lock, flags); ++ ++ return enabled; ++} ++ ++void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_vec) ++{ ++ struct imsic_local_priv *old_lpriv, *new_lpriv; ++ bool enabled; ++ ++ if (WARN_ON_ONCE(old_vec->cpu == new_vec->cpu)) ++ return; ++ ++ old_lpriv = per_cpu_ptr(imsic->lpriv, old_vec->cpu); ++ if (WARN_ON_ONCE(&old_lpriv->vectors[old_vec->local_id] != old_vec)) ++ return; ++ ++ new_lpriv = per_cpu_ptr(imsic->lpriv, new_vec->cpu); ++ if (WARN_ON_ONCE(&new_lpriv->vectors[new_vec->local_id] != new_vec)) ++ return; ++ ++ /* ++ * Move and re-trigger the new vector based on the pending ++ * state of the old vector because we might get a device ++ * interrupt on the old vector while device was being moved ++ * to the new vector. ++ */ ++ enabled = imsic_vector_move_update(old_lpriv, old_vec, false, new_vec); ++ imsic_vector_move_update(new_lpriv, new_vec, enabled, new_vec); ++} ++ ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++void imsic_vector_debug_show(struct seq_file *m, struct imsic_vector *vec, int ind) ++{ ++ struct imsic_local_priv *lpriv; ++ struct imsic_vector *mvec; ++ bool is_enabled; ++ ++ lpriv = per_cpu_ptr(imsic->lpriv, vec->cpu); ++ if (WARN_ON_ONCE(&lpriv->vectors[vec->local_id] != vec)) ++ return; ++ ++ is_enabled = imsic_vector_isenabled(vec); ++ mvec = imsic_vector_get_move(vec); ++ ++ seq_printf(m, "%*starget_cpu : %5u\n", ind, "", vec->cpu); ++ seq_printf(m, "%*starget_local_id : %5u\n", ind, "", vec->local_id); ++ seq_printf(m, "%*sis_reserved : %5u\n", ind, "", ++ (vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); ++ seq_printf(m, "%*sis_enabled : %5u\n", ind, "", is_enabled ? 1 : 0); ++ seq_printf(m, "%*sis_move_pending : %5u\n", ind, "", mvec ? 1 : 0); ++ if (mvec) { ++ seq_printf(m, "%*smove_cpu : %5u\n", ind, "", mvec->cpu); ++ seq_printf(m, "%*smove_local_id : %5u\n", ind, "", mvec->local_id); ++ } ++} ++ ++void imsic_vector_debug_show_summary(struct seq_file *m, int ind) ++{ ++ irq_matrix_debug_show(m, imsic->matrix, ind); ++} ++#endif ++ ++struct imsic_vector *imsic_vector_from_local_id(unsigned int cpu, unsigned int local_id) ++{ ++ struct imsic_local_priv *lpriv = per_cpu_ptr(imsic->lpriv, cpu); ++ ++ if (!lpriv || imsic->global.nr_ids < local_id) ++ return NULL; ++ ++ return &lpriv->vectors[local_id]; ++} ++ ++struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask *mask) ++{ ++ struct imsic_vector *vec = NULL; ++ struct imsic_local_priv *lpriv; ++ unsigned long flags; ++ unsigned int cpu; ++ int local_id; ++ ++ raw_spin_lock_irqsave(&imsic->matrix_lock, flags); ++ local_id = irq_matrix_alloc(imsic->matrix, mask, false, &cpu); ++ raw_spin_unlock_irqrestore(&imsic->matrix_lock, flags); ++ if (local_id < 0) ++ return NULL; ++ ++ lpriv = per_cpu_ptr(imsic->lpriv, cpu); ++ vec = &lpriv->vectors[local_id]; ++ vec->hwirq = hwirq; ++ vec->enable = false; ++ vec->move = NULL; ++ ++ return vec; ++} ++ ++void imsic_vector_free(struct imsic_vector *vec) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&imsic->matrix_lock, flags); ++ vec->hwirq = UINT_MAX; ++ irq_matrix_free(imsic->matrix, vec->cpu, vec->local_id, false); ++ raw_spin_unlock_irqrestore(&imsic->matrix_lock, flags); ++} ++ ++static void __init imsic_local_cleanup(void) ++{ ++ struct imsic_local_priv *lpriv; ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ lpriv = per_cpu_ptr(imsic->lpriv, cpu); ++ ++ bitmap_free(lpriv->dirty_bitmap); ++ kfree(lpriv->vectors); ++ } ++ ++ free_percpu(imsic->lpriv); ++} ++ ++static int __init imsic_local_init(void) ++{ ++ struct imsic_global_config *global = &imsic->global; ++ struct imsic_local_priv *lpriv; ++ struct imsic_vector *vec; ++ int cpu, i; ++ ++ /* Allocate per-CPU private state */ ++ imsic->lpriv = alloc_percpu(typeof(*imsic->lpriv)); ++ if (!imsic->lpriv) ++ return -ENOMEM; ++ ++ /* Setup per-CPU private state */ ++ for_each_possible_cpu(cpu) { ++ lpriv = per_cpu_ptr(imsic->lpriv, cpu); ++ ++ raw_spin_lock_init(&lpriv->lock); ++ ++ /* Allocate dirty bitmap */ ++ lpriv->dirty_bitmap = bitmap_zalloc(global->nr_ids + 1, GFP_KERNEL); ++ if (!lpriv->dirty_bitmap) ++ goto fail_local_cleanup; ++ ++#ifdef CONFIG_SMP ++ /* Setup lazy timer for synchronization */ ++ timer_setup(&lpriv->timer, imsic_local_timer_callback, TIMER_PINNED); ++#endif ++ ++ /* Allocate vector array */ ++ lpriv->vectors = kcalloc(global->nr_ids + 1, sizeof(*lpriv->vectors), ++ GFP_KERNEL); ++ if (!lpriv->vectors) ++ goto fail_local_cleanup; ++ ++ /* Setup vector array */ ++ for (i = 0; i <= global->nr_ids; i++) { ++ vec = &lpriv->vectors[i]; ++ vec->cpu = cpu; ++ vec->local_id = i; ++ vec->hwirq = UINT_MAX; ++ } ++ } ++ ++ return 0; ++ ++fail_local_cleanup: ++ imsic_local_cleanup(); ++ return -ENOMEM; ++} ++ ++void imsic_state_online(void) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&imsic->matrix_lock, flags); ++ irq_matrix_online(imsic->matrix); ++ raw_spin_unlock_irqrestore(&imsic->matrix_lock, flags); ++} ++ ++void imsic_state_offline(void) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&imsic->matrix_lock, flags); ++ irq_matrix_offline(imsic->matrix); ++ raw_spin_unlock_irqrestore(&imsic->matrix_lock, flags); ++ ++#ifdef CONFIG_SMP ++ struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv); ++ ++ raw_spin_lock_irqsave(&lpriv->lock, flags); ++ WARN_ON_ONCE(try_to_del_timer_sync(&lpriv->timer) < 0); ++ raw_spin_unlock_irqrestore(&lpriv->lock, flags); ++#endif ++} ++ ++static int __init imsic_matrix_init(void) ++{ ++ struct imsic_global_config *global = &imsic->global; ++ ++ raw_spin_lock_init(&imsic->matrix_lock); ++ imsic->matrix = irq_alloc_matrix(global->nr_ids + 1, ++ 0, global->nr_ids + 1); ++ if (!imsic->matrix) ++ return -ENOMEM; ++ ++ /* Reserve ID#0 because it is special and never implemented */ ++ irq_matrix_assign_system(imsic->matrix, 0, false); ++ ++ /* Reserve IPI ID because it is special and used internally */ ++ irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); ++ ++ return 0; ++} ++ ++static int __init imsic_get_parent_hartid(struct fwnode_handle *fwnode, ++ u32 index, unsigned long *hartid) ++{ ++ struct of_phandle_args parent; ++ int rc; ++ ++ /* ++ * Currently, only OF fwnode is supported so extend this ++ * function for ACPI support. ++ */ ++ if (!is_of_node(fwnode)) ++ return -EINVAL; ++ ++ rc = of_irq_parse_one(to_of_node(fwnode), index, &parent); ++ if (rc) ++ return rc; ++ ++ /* ++ * Skip interrupts other than external interrupts for ++ * current privilege level. ++ */ ++ if (parent.args[0] != RV_IRQ_EXT) ++ return -EINVAL; ++ ++ return riscv_of_parent_hartid(parent.np, hartid); ++} ++ ++static int __init imsic_get_mmio_resource(struct fwnode_handle *fwnode, ++ u32 index, struct resource *res) ++{ ++ /* ++ * Currently, only OF fwnode is supported so extend this ++ * function for ACPI support. ++ */ ++ if (!is_of_node(fwnode)) ++ return -EINVAL; ++ ++ return of_address_to_resource(to_of_node(fwnode), index, res); ++} ++ ++static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode, ++ struct imsic_global_config *global, ++ u32 *nr_parent_irqs, ++ u32 *nr_mmios) ++{ ++ unsigned long hartid; ++ struct resource res; ++ int rc; ++ u32 i; ++ ++ /* ++ * Currently, only OF fwnode is supported so extend this ++ * function for ACPI support. ++ */ ++ if (!is_of_node(fwnode)) ++ return -EINVAL; ++ ++ *nr_parent_irqs = 0; ++ *nr_mmios = 0; ++ ++ /* Find number of parent interrupts */ ++ while (!imsic_get_parent_hartid(fwnode, *nr_parent_irqs, &hartid)) ++ (*nr_parent_irqs)++; ++ if (!*nr_parent_irqs) { ++ pr_err("%pfwP: no parent irqs available\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Find number of guest index bits in MSI address */ ++ rc = of_property_read_u32(to_of_node(fwnode), "riscv,guest-index-bits", ++ &global->guest_index_bits); ++ if (rc) ++ global->guest_index_bits = 0; ++ ++ /* Find number of HART index bits */ ++ rc = of_property_read_u32(to_of_node(fwnode), "riscv,hart-index-bits", ++ &global->hart_index_bits); ++ if (rc) { ++ /* Assume default value */ ++ global->hart_index_bits = __fls(*nr_parent_irqs); ++ if (BIT(global->hart_index_bits) < *nr_parent_irqs) ++ global->hart_index_bits++; ++ } ++ ++ /* Find number of group index bits */ ++ rc = of_property_read_u32(to_of_node(fwnode), "riscv,group-index-bits", ++ &global->group_index_bits); ++ if (rc) ++ global->group_index_bits = 0; ++ ++ /* ++ * Find first bit position of group index. ++ * If not specified assumed the default APLIC-IMSIC configuration. ++ */ ++ rc = of_property_read_u32(to_of_node(fwnode), "riscv,group-index-shift", ++ &global->group_index_shift); ++ if (rc) ++ global->group_index_shift = IMSIC_MMIO_PAGE_SHIFT * 2; ++ ++ /* Find number of interrupt identities */ ++ rc = of_property_read_u32(to_of_node(fwnode), "riscv,num-ids", ++ &global->nr_ids); ++ if (rc) { ++ pr_err("%pfwP: number of interrupt identities not found\n", fwnode); ++ return rc; ++ } ++ ++ /* Find number of guest interrupt identities */ ++ rc = of_property_read_u32(to_of_node(fwnode), "riscv,num-guest-ids", ++ &global->nr_guest_ids); ++ if (rc) ++ global->nr_guest_ids = global->nr_ids; ++ ++ /* Sanity check guest index bits */ ++ i = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT; ++ if (i < global->guest_index_bits) { ++ pr_err("%pfwP: guest index bits too big\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Sanity check HART index bits */ ++ i = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT - global->guest_index_bits; ++ if (i < global->hart_index_bits) { ++ pr_err("%pfwP: HART index bits too big\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Sanity check group index bits */ ++ i = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT - ++ global->guest_index_bits - global->hart_index_bits; ++ if (i < global->group_index_bits) { ++ pr_err("%pfwP: group index bits too big\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Sanity check group index shift */ ++ i = global->group_index_bits + global->group_index_shift - 1; ++ if (i >= BITS_PER_LONG) { ++ pr_err("%pfwP: group index shift too big\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Sanity check number of interrupt identities */ ++ if (global->nr_ids < IMSIC_MIN_ID || ++ global->nr_ids >= IMSIC_MAX_ID || ++ (global->nr_ids & IMSIC_MIN_ID) != IMSIC_MIN_ID) { ++ pr_err("%pfwP: invalid number of interrupt identities\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Sanity check number of guest interrupt identities */ ++ if (global->nr_guest_ids < IMSIC_MIN_ID || ++ global->nr_guest_ids >= IMSIC_MAX_ID || ++ (global->nr_guest_ids & IMSIC_MIN_ID) != IMSIC_MIN_ID) { ++ pr_err("%pfwP: invalid number of guest interrupt identities\n", fwnode); ++ return -EINVAL; ++ } ++ ++ /* Compute base address */ ++ rc = imsic_get_mmio_resource(fwnode, 0, &res); ++ if (rc) { ++ pr_err("%pfwP: first MMIO resource not found\n", fwnode); ++ return -EINVAL; ++ } ++ global->base_addr = res.start; ++ global->base_addr &= ~(BIT(global->guest_index_bits + ++ global->hart_index_bits + ++ IMSIC_MMIO_PAGE_SHIFT) - 1); ++ global->base_addr &= ~((BIT(global->group_index_bits) - 1) << ++ global->group_index_shift); ++ ++ /* Find number of MMIO register sets */ ++ while (!imsic_get_mmio_resource(fwnode, *nr_mmios, &res)) ++ (*nr_mmios)++; ++ ++ return 0; ++} ++ ++int __init imsic_setup_state(struct fwnode_handle *fwnode) ++{ ++ u32 i, j, index, nr_parent_irqs, nr_mmios, nr_handlers = 0; ++ struct imsic_global_config *global; ++ struct imsic_local_config *local; ++ void __iomem **mmios_va = NULL; ++ struct resource *mmios = NULL; ++ unsigned long reloff, hartid; ++ phys_addr_t base_addr; ++ int rc, cpu; ++ ++ /* ++ * Only one IMSIC instance allowed in a platform for clean ++ * implementation of SMP IRQ affinity and per-CPU IPIs. ++ * ++ * This means on a multi-socket (or multi-die) platform we ++ * will have multiple MMIO regions for one IMSIC instance. ++ */ ++ if (imsic) { ++ pr_err("%pfwP: already initialized hence ignoring\n", fwnode); ++ return -EALREADY; ++ } ++ ++ if (!riscv_isa_extension_available(NULL, SxAIA)) { ++ pr_err("%pfwP: AIA support not available\n", fwnode); ++ return -ENODEV; ++ } ++ ++ imsic = kzalloc(sizeof(*imsic), GFP_KERNEL); ++ if (!imsic) ++ return -ENOMEM; ++ imsic->fwnode = fwnode; ++ global = &imsic->global; ++ ++ global->local = alloc_percpu(typeof(*global->local)); ++ if (!global->local) { ++ rc = -ENOMEM; ++ goto out_free_priv; ++ } ++ ++ /* Parse IMSIC fwnode */ ++ rc = imsic_parse_fwnode(fwnode, global, &nr_parent_irqs, &nr_mmios); ++ if (rc) ++ goto out_free_local; ++ ++ /* Allocate MMIO resource array */ ++ mmios = kcalloc(nr_mmios, sizeof(*mmios), GFP_KERNEL); ++ if (!mmios) { ++ rc = -ENOMEM; ++ goto out_free_local; ++ } ++ ++ /* Allocate MMIO virtual address array */ ++ mmios_va = kcalloc(nr_mmios, sizeof(*mmios_va), GFP_KERNEL); ++ if (!mmios_va) { ++ rc = -ENOMEM; ++ goto out_iounmap; ++ } ++ ++ /* Parse and map MMIO register sets */ ++ for (i = 0; i < nr_mmios; i++) { ++ rc = imsic_get_mmio_resource(fwnode, i, &mmios[i]); ++ if (rc) { ++ pr_err("%pfwP: unable to parse MMIO regset %d\n", fwnode, i); ++ goto out_iounmap; ++ } ++ ++ base_addr = mmios[i].start; ++ base_addr &= ~(BIT(global->guest_index_bits + ++ global->hart_index_bits + ++ IMSIC_MMIO_PAGE_SHIFT) - 1); ++ base_addr &= ~((BIT(global->group_index_bits) - 1) << ++ global->group_index_shift); ++ if (base_addr != global->base_addr) { ++ rc = -EINVAL; ++ pr_err("%pfwP: address mismatch for regset %d\n", fwnode, i); ++ goto out_iounmap; ++ } ++ ++ mmios_va[i] = ioremap(mmios[i].start, resource_size(&mmios[i])); ++ if (!mmios_va[i]) { ++ rc = -EIO; ++ pr_err("%pfwP: unable to map MMIO regset %d\n", fwnode, i); ++ goto out_iounmap; ++ } ++ } ++ ++ /* Initialize local (or per-CPU )state */ ++ rc = imsic_local_init(); ++ if (rc) { ++ pr_err("%pfwP: failed to initialize local state\n", ++ fwnode); ++ goto out_iounmap; ++ } ++ ++ /* Configure handlers for target CPUs */ ++ for (i = 0; i < nr_parent_irqs; i++) { ++ rc = imsic_get_parent_hartid(fwnode, i, &hartid); ++ if (rc) { ++ pr_warn("%pfwP: hart ID for parent irq%d not found\n", fwnode, i); ++ continue; ++ } ++ ++ cpu = riscv_hartid_to_cpuid(hartid); ++ if (cpu < 0) { ++ pr_warn("%pfwP: invalid cpuid for parent irq%d\n", fwnode, i); ++ continue; ++ } ++ ++ /* Find MMIO location of MSI page */ ++ index = nr_mmios; ++ reloff = i * BIT(global->guest_index_bits) * ++ IMSIC_MMIO_PAGE_SZ; ++ for (j = 0; nr_mmios; j++) { ++ if (reloff < resource_size(&mmios[j])) { ++ index = j; ++ break; ++ } ++ ++ /* ++ * MMIO region size may not be aligned to ++ * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ ++ * if holes are present. ++ */ ++ reloff -= ALIGN(resource_size(&mmios[j]), ++ BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ); ++ } ++ if (index >= nr_mmios) { ++ pr_warn("%pfwP: MMIO not found for parent irq%d\n", fwnode, i); ++ continue; ++ } ++ ++ local = per_cpu_ptr(global->local, cpu); ++ local->msi_pa = mmios[index].start + reloff; ++ local->msi_va = mmios_va[index] + reloff; ++ ++ nr_handlers++; ++ } ++ ++ /* If no CPU handlers found then can't take interrupts */ ++ if (!nr_handlers) { ++ pr_err("%pfwP: No CPU handlers found\n", fwnode); ++ rc = -ENODEV; ++ goto out_local_cleanup; ++ } ++ ++ /* Initialize matrix allocator */ ++ rc = imsic_matrix_init(); ++ if (rc) { ++ pr_err("%pfwP: failed to create matrix allocator\n", fwnode); ++ goto out_local_cleanup; ++ } ++ ++ /* We don't need MMIO arrays anymore so let's free-up */ ++ kfree(mmios_va); ++ kfree(mmios); ++ ++ return 0; ++ ++out_local_cleanup: ++ imsic_local_cleanup(); ++out_iounmap: ++ for (i = 0; i < nr_mmios; i++) { ++ if (mmios_va[i]) ++ iounmap(mmios_va[i]); ++ } ++ kfree(mmios_va); ++ kfree(mmios); ++out_free_local: ++ free_percpu(imsic->global.local); ++out_free_priv: ++ kfree(imsic); ++ imsic = NULL; ++ return rc; ++} +diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h +new file mode 100644 +index 000000000000..5ae2f69b035b +--- /dev/null ++++ b/drivers/irqchip/irq-riscv-imsic-state.h +@@ -0,0 +1,108 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++ ++#ifndef _IRQ_RISCV_IMSIC_STATE_H ++#define _IRQ_RISCV_IMSIC_STATE_H ++ ++#include ++#include ++#include ++#include ++ ++#define IMSIC_IPI_ID 1 ++#define IMSIC_NR_IPI 8 ++ ++struct imsic_vector { ++ /* Fixed details of the vector */ ++ unsigned int cpu; ++ unsigned int local_id; ++ /* Details saved by driver in the vector */ ++ unsigned int hwirq; ++ /* Details accessed using local lock held */ ++ bool enable; ++ struct imsic_vector *move; ++}; ++ ++struct imsic_local_priv { ++ /* Local lock to protect vector enable/move variables and dirty bitmap */ ++ raw_spinlock_t lock; ++ ++ /* Local dirty bitmap for synchronization */ ++ unsigned long *dirty_bitmap; ++ ++#ifdef CONFIG_SMP ++ /* Local timer for synchronization */ ++ struct timer_list timer; ++#endif ++ ++ /* Local vector table */ ++ struct imsic_vector *vectors; ++}; ++ ++struct imsic_priv { ++ /* Device details */ ++ struct fwnode_handle *fwnode; ++ ++ /* Global configuration common for all HARTs */ ++ struct imsic_global_config global; ++ ++ /* Per-CPU state */ ++ struct imsic_local_priv __percpu *lpriv; ++ ++ /* State of IRQ matrix allocator */ ++ raw_spinlock_t matrix_lock; ++ struct irq_matrix *matrix; ++ ++ /* IRQ domains (created by platform driver) */ ++ struct irq_domain *base_domain; ++}; ++ ++extern struct imsic_priv *imsic; ++ ++void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend, bool val); ++ ++static inline void __imsic_id_set_enable(unsigned long id) ++{ ++ __imsic_eix_update(id, 1, false, true); ++} ++ ++static inline void __imsic_id_clear_enable(unsigned long id) ++{ ++ __imsic_eix_update(id, 1, false, false); ++} ++ ++void imsic_local_sync_all(void); ++void imsic_local_delivery(bool enable); ++ ++void imsic_vector_mask(struct imsic_vector *vec); ++void imsic_vector_unmask(struct imsic_vector *vec); ++ ++static inline bool imsic_vector_isenabled(struct imsic_vector *vec) ++{ ++ return READ_ONCE(vec->enable); ++} ++ ++static inline struct imsic_vector *imsic_vector_get_move(struct imsic_vector *vec) ++{ ++ return READ_ONCE(vec->move); ++} ++ ++void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_vec); ++ ++struct imsic_vector *imsic_vector_from_local_id(unsigned int cpu, unsigned int local_id); ++ ++struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask *mask); ++void imsic_vector_free(struct imsic_vector *vector); ++ ++void imsic_vector_debug_show(struct seq_file *m, struct imsic_vector *vec, int ind); ++void imsic_vector_debug_show_summary(struct seq_file *m, int ind); ++ ++void imsic_state_online(void); ++void imsic_state_offline(void); ++int imsic_setup_state(struct fwnode_handle *fwnode); ++int imsic_irqdomain_init(void); ++ ++#endif +diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c +index 627beae9649a..4f3a12383a1e 100644 +--- a/drivers/irqchip/irq-riscv-intc.c ++++ b/drivers/irqchip/irq-riscv-intc.c +@@ -19,6 +19,8 @@ + #include + #include + ++#include ++ + static struct irq_domain *intc_domain; + static unsigned int riscv_intc_nr_irqs __ro_after_init = BITS_PER_LONG; + static unsigned int riscv_intc_custom_base __ro_after_init = BITS_PER_LONG; +@@ -32,6 +34,14 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs) + pr_warn_ratelimited("Failed to handle interrupt (cause: %ld)\n", cause); + } + ++static asmlinkage void riscv_intc_aia_irq(struct pt_regs *regs) ++{ ++ unsigned long topi; ++ ++ while ((topi = csr_read(CSR_TOPI))) ++ generic_handle_domain_irq(intc_domain, topi >> TOPI_IID_SHIFT); ++} ++ + /* + * On RISC-V systems local interrupts are masked or unmasked by writing + * the SIE (Supervisor Interrupt Enable) CSR. As CSRs can only be written +@@ -41,12 +51,18 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs) + + static void riscv_intc_irq_mask(struct irq_data *d) + { +- csr_clear(CSR_IE, BIT(d->hwirq)); ++ if (IS_ENABLED(CONFIG_32BIT) && d->hwirq >= BITS_PER_LONG) ++ csr_clear(CSR_IEH, BIT(d->hwirq - BITS_PER_LONG)); ++ else ++ csr_clear(CSR_IE, BIT(d->hwirq)); + } + + static void riscv_intc_irq_unmask(struct irq_data *d) + { +- csr_set(CSR_IE, BIT(d->hwirq)); ++ if (IS_ENABLED(CONFIG_32BIT) && d->hwirq >= BITS_PER_LONG) ++ csr_set(CSR_IEH, BIT(d->hwirq - BITS_PER_LONG)); ++ else ++ csr_set(CSR_IE, BIT(d->hwirq)); + } + + static void andes_intc_irq_mask(struct irq_data *d) +@@ -133,8 +149,9 @@ static int riscv_intc_domain_alloc(struct irq_domain *domain, + * Only allow hwirq for which we have corresponding standard or + * custom interrupt enable register. + */ +- if ((hwirq >= riscv_intc_nr_irqs && hwirq < riscv_intc_custom_base) || +- (hwirq >= riscv_intc_custom_base + riscv_intc_custom_nr_irqs)) ++ if (hwirq >= riscv_intc_nr_irqs && ++ (hwirq < riscv_intc_custom_base || ++ hwirq >= riscv_intc_custom_base + riscv_intc_custom_nr_irqs)) + return -EINVAL; + + for (i = 0; i < nr_irqs; i++) { +@@ -157,8 +174,7 @@ static struct fwnode_handle *riscv_intc_hwnode(void) + return intc_domain->fwnode; + } + +-static int __init riscv_intc_init_common(struct fwnode_handle *fn, +- struct irq_chip *chip) ++static int __init riscv_intc_init_common(struct fwnode_handle *fn, struct irq_chip *chip) + { + int rc; + +@@ -168,7 +184,12 @@ static int __init riscv_intc_init_common(struct fwnode_handle *fn, + return -ENXIO; + } + +- rc = set_handle_irq(&riscv_intc_irq); ++ if (riscv_isa_extension_available(NULL, SxAIA)) { ++ riscv_intc_nr_irqs = 64; ++ rc = set_handle_irq(&riscv_intc_aia_irq); ++ } else { ++ rc = set_handle_irq(&riscv_intc_irq); ++ } + if (rc) { + pr_err("failed to set irq handler\n"); + return rc; +@@ -176,11 +197,11 @@ static int __init riscv_intc_init_common(struct fwnode_handle *fn, + + riscv_set_intc_hwnode_fn(riscv_intc_hwnode); + +- pr_info("%d local interrupts mapped\n", riscv_intc_nr_irqs); +- if (riscv_intc_custom_nr_irqs) { +- pr_info("%d custom local interrupts mapped\n", +- riscv_intc_custom_nr_irqs); +- } ++ pr_info("%d local interrupts mapped%s\n", ++ riscv_intc_nr_irqs, ++ riscv_isa_extension_available(NULL, SxAIA) ? " using AIA" : ""); ++ if (riscv_intc_custom_nr_irqs) ++ pr_info("%d custom local interrupts mapped\n", riscv_intc_custom_nr_irqs); + + return 0; + } diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index bc2e265cb02d..a0186d27086f 100644 --- a/drivers/mailbox/Kconfig @@ -347880,6 +353325,39 @@ index fc9376117111..f1a807c76731 100644 obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o + +obj-$(CONFIG_TH1520_MBOX) += th1520-mailbox.o +diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c +index a2b8839d4e7c..7094d44869a8 100644 +--- a/drivers/mailbox/bcm-flexrm-mailbox.c ++++ b/drivers/mailbox/bcm-flexrm-mailbox.c +@@ -1587,8 +1587,8 @@ static int flexrm_mbox_probe(struct platform_device *pdev) + } + + /* Allocate platform MSIs for each ring */ +- ret = platform_msi_domain_alloc_irqs(dev, mbox->num_rings, +- flexrm_mbox_msi_write); ++ ret = platform_device_msi_init_and_alloc_irqs(dev, mbox->num_rings, ++ flexrm_mbox_msi_write); + if (ret) + goto fail_destroy_cmpl_pool; + +@@ -1641,7 +1641,7 @@ static int flexrm_mbox_probe(struct platform_device *pdev) + + fail_free_debugfs_root: + debugfs_remove_recursive(mbox->root); +- platform_msi_domain_free_irqs(dev); ++ platform_device_msi_free_irqs_all(dev); + fail_destroy_cmpl_pool: + dma_pool_destroy(mbox->cmpl_pool); + fail_destroy_bd_pool: +@@ -1657,7 +1657,7 @@ static int flexrm_mbox_remove(struct platform_device *pdev) + + debugfs_remove_recursive(mbox->root); + +- platform_msi_domain_free_irqs(dev); ++ platform_device_msi_free_irqs_all(dev); + + dma_pool_destroy(mbox->cmpl_pool); + dma_pool_destroy(mbox->bd_pool); diff --git a/drivers/mailbox/th1520-mailbox.c b/drivers/mailbox/th1520-mailbox.c new file mode 100644 index 000000000000..71c983bd631c @@ -438953,6 +444431,28 @@ index 46fad0d813b2..560b3a236d84 100644 /* * If the user specified "pcie_ports=native", use the PCIe services regardless +diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c +index 6303b82566f9..9e5d7fa647b6 100644 +--- a/drivers/perf/arm_smmuv3_pmu.c ++++ b/drivers/perf/arm_smmuv3_pmu.c +@@ -716,7 +716,7 @@ static void smmu_pmu_free_msis(void *data) + { + struct device *dev = data; + +- platform_msi_domain_free_irqs(dev); ++ platform_device_msi_free_irqs_all(dev); + } + + static void smmu_pmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) +@@ -746,7 +746,7 @@ static void smmu_pmu_setup_msi(struct smmu_pmu *pmu) + if (!(readl(pmu->reg_base + SMMU_PMCG_CFGR) & SMMU_PMCG_CFGR_MSI)) + return; + +- ret = platform_msi_domain_alloc_irqs(dev, 1, smmu_pmu_write_msi_msg); ++ ret = platform_device_msi_init_and_alloc_irqs(dev, 1, smmu_pmu_write_msi_msg); + if (ret) { + dev_warn(dev, "failed to allocate MSIs\n"); + return; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e4502958fd62..50f729360df1 100644 --- a/drivers/phy/Kconfig @@ -554071,6 +559571,39 @@ index a17803da83f8..dde4293f3109 100644 } /* +diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c +index 60079771df25..9ed4236f7b4f 100644 +--- a/drivers/ufs/host/ufs-qcom.c ++++ b/drivers/ufs/host/ufs-qcom.c +@@ -1816,8 +1816,8 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) + * 2. Poll queues do not need ESI. + */ + nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]; +- ret = platform_msi_domain_alloc_irqs(hba->dev, nr_irqs, +- ufs_qcom_write_msi_msg); ++ ret = platform_device_msi_init_and_alloc_irqs(hba->dev, nr_irqs, ++ ufs_qcom_write_msi_msg); + if (ret) { + dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret); + goto out; +@@ -1846,7 +1846,7 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) + devm_free_irq(hba->dev, desc->irq, hba); + } + msi_unlock_descs(hba->dev); +- platform_msi_domain_free_irqs(hba->dev); ++ platform_device_msi_free_irqs_all(hba->dev); + } else { + if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 && + host->hw_ver.step == 0) { +@@ -1928,7 +1928,7 @@ static int ufs_qcom_remove(struct platform_device *pdev) + pm_runtime_get_sync(&(pdev)->dev); + ufshcd_remove(hba); + if (host->esi_enabled) +- platform_msi_domain_free_irqs(hba->dev); ++ platform_device_msi_free_irqs_all(hba->dev); + return 0; + } + diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 98efcbb76c88..54e2a412d643 100644 --- a/drivers/usb/dwc3/Kconfig @@ -554933,6 +560466,32 @@ index 000000000000..80cb0b1e3d64 +MODULE_AUTHOR("Wei.Liu "); +MODULE_DESCRIPTION("PMIC Watchdog Driver for TH1520"); +MODULE_LICENSE("GPL"); +diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h +index c75d4a753849..879e5f8aa5e9 100644 +--- a/include/asm-generic/pgalloc.h ++++ b/include/asm-generic/pgalloc.h +@@ -169,6 +169,8 @@ static inline pud_t *__pud_alloc_one(struct mm_struct *mm, unsigned long addr) + ptdesc = pagetable_alloc(gfp, 0); + if (!ptdesc) + return NULL; ++ ++ pagetable_pud_ctor(ptdesc); + return ptdesc_address(ptdesc); + } + +@@ -190,8 +192,11 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) + + static inline void __pud_free(struct mm_struct *mm, pud_t *pud) + { ++ struct ptdesc *ptdesc = virt_to_ptdesc(pud); ++ + BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); +- pagetable_free(virt_to_ptdesc(pud)); ++ pagetable_pud_dtor(ptdesc); ++ pagetable_free(ptdesc); + } + + #ifndef __HAVE_ARCH_PUD_FREE diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 6a46baa0737c..30de0e07c2eb 100644 --- a/include/drm/bridge/dw_hdmi.h @@ -556165,17 +561724,91 @@ index 000000000000..c0370797443f + +#endif /* __DT_XUANTIE_TH1520_IOPMP_H__ */ diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h -index 8f3b474f3a70..c69ac0619c6a 100644 +index 8f3b474f3a70..61c981c1ec9d 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h -@@ -158,6 +158,7 @@ enum cpuhp_state { +@@ -158,6 +158,8 @@ enum cpuhp_state { CPUHP_AP_IRQ_AVECINTC_STARTING, #endif CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, + CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING, ++ CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, CPUHP_AP_ARM_MVEBU_COHERENCY, CPUHP_AP_MICROCODE_LOADER, CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING, +diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h +index 4c26ede3b87d..b2da3c2837dd 100644 +--- a/include/linux/cpumask.h ++++ b/include/linux/cpumask.h +@@ -189,6 +189,23 @@ unsigned int cpumask_first_and(const struct cpumask *srcp1, const struct cpumask + return find_first_and_bit(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits); + } + ++/** ++ * cpumask_first_and_and - return the first cpu from *srcp1 & *srcp2 & *srcp3 ++ * @srcp1: the first input ++ * @srcp2: the second input ++ * @srcp3: the third input ++ * ++ * Return: >= nr_cpu_ids if no cpus set in all. ++ */ ++static inline ++unsigned int cpumask_first_and_and(const struct cpumask *srcp1, ++ const struct cpumask *srcp2, ++ const struct cpumask *srcp3) ++{ ++ return find_first_and_and_bit(cpumask_bits(srcp1), cpumask_bits(srcp2), ++ cpumask_bits(srcp3), small_cpumask_bits); ++} ++ + /** + * cpumask_last - get the last CPU in a cpumask + * @srcp: - the cpumask pointer +diff --git a/include/linux/find.h b/include/linux/find.h +index 5e4f39ef2e72..a3a908a27df7 100644 +--- a/include/linux/find.h ++++ b/include/linux/find.h +@@ -29,6 +29,8 @@ unsigned long __find_nth_and_andnot_bit(const unsigned long *addr1, const unsign + unsigned long n); + extern unsigned long _find_first_and_bit(const unsigned long *addr1, + const unsigned long *addr2, unsigned long size); ++unsigned long _find_first_and_and_bit(const unsigned long *addr1, const unsigned long *addr2, ++ const unsigned long *addr3, unsigned long size); + extern unsigned long _find_first_zero_bit(const unsigned long *addr, unsigned long size); + extern unsigned long _find_last_bit(const unsigned long *addr, unsigned long size); + +@@ -345,6 +347,31 @@ unsigned long find_first_and_bit(const unsigned long *addr1, + } + #endif + ++/** ++ * find_first_and_and_bit - find the first set bit in 3 memory regions ++ * @addr1: The first address to base the search on ++ * @addr2: The second address to base the search on ++ * @addr3: The third address to base the search on ++ * @size: The bitmap size in bits ++ * ++ * Returns the bit number for the first set bit ++ * If no bits are set, returns @size. ++ */ ++static inline ++unsigned long find_first_and_and_bit(const unsigned long *addr1, ++ const unsigned long *addr2, ++ const unsigned long *addr3, ++ unsigned long size) ++{ ++ if (small_const_nbits(size)) { ++ unsigned long val = *addr1 & *addr2 & *addr3 & GENMASK(size - 1, 0); ++ ++ return val ? __ffs(val) : size; ++ } ++ ++ return _find_first_and_and_bit(addr1, addr2, addr3, size); ++} ++ + #ifndef find_first_zero_bit + /** + * find_first_zero_bit - find the first cleared bit in a memory region diff --git a/include/linux/firmware/xuantie/ipc.h b/include/linux/firmware/xuantie/ipc.h new file mode 100644 index 000000000000..bc1a1eb34a8c @@ -556390,6 +562023,291 @@ index 000000000000..b88ae8727c29 +#endif + +#endif +diff --git a/include/linux/irqchip/riscv-aplic.h b/include/linux/irqchip/riscv-aplic.h +new file mode 100644 +index 000000000000..ec8f7df50583 +--- /dev/null ++++ b/include/linux/irqchip/riscv-aplic.h +@@ -0,0 +1,145 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++#ifndef __LINUX_IRQCHIP_RISCV_APLIC_H ++#define __LINUX_IRQCHIP_RISCV_APLIC_H ++ ++#include ++ ++#define APLIC_MAX_IDC BIT(14) ++#define APLIC_MAX_SOURCE 1024 ++ ++#define APLIC_DOMAINCFG 0x0000 ++#define APLIC_DOMAINCFG_RDONLY 0x80000000 ++#define APLIC_DOMAINCFG_IE BIT(8) ++#define APLIC_DOMAINCFG_DM BIT(2) ++#define APLIC_DOMAINCFG_BE BIT(0) ++ ++#define APLIC_SOURCECFG_BASE 0x0004 ++#define APLIC_SOURCECFG_D BIT(10) ++#define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff ++#define APLIC_SOURCECFG_SM_MASK 0x00000007 ++#define APLIC_SOURCECFG_SM_INACTIVE 0x0 ++#define APLIC_SOURCECFG_SM_DETACH 0x1 ++#define APLIC_SOURCECFG_SM_EDGE_RISE 0x4 ++#define APLIC_SOURCECFG_SM_EDGE_FALL 0x5 ++#define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6 ++#define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7 ++ ++#define APLIC_MMSICFGADDR 0x1bc0 ++#define APLIC_MMSICFGADDRH 0x1bc4 ++#define APLIC_SMSICFGADDR 0x1bc8 ++#define APLIC_SMSICFGADDRH 0x1bcc ++ ++#ifdef CONFIG_RISCV_M_MODE ++#define APLIC_xMSICFGADDR APLIC_MMSICFGADDR ++#define APLIC_xMSICFGADDRH APLIC_MMSICFGADDRH ++#else ++#define APLIC_xMSICFGADDR APLIC_SMSICFGADDR ++#define APLIC_xMSICFGADDRH APLIC_SMSICFGADDRH ++#endif ++ ++#define APLIC_xMSICFGADDRH_L BIT(31) ++#define APLIC_xMSICFGADDRH_HHXS_MASK 0x1f ++#define APLIC_xMSICFGADDRH_HHXS_SHIFT 24 ++#define APLIC_xMSICFGADDRH_HHXS (APLIC_xMSICFGADDRH_HHXS_MASK << \ ++ APLIC_xMSICFGADDRH_HHXS_SHIFT) ++#define APLIC_xMSICFGADDRH_LHXS_MASK 0x7 ++#define APLIC_xMSICFGADDRH_LHXS_SHIFT 20 ++#define APLIC_xMSICFGADDRH_LHXS (APLIC_xMSICFGADDRH_LHXS_MASK << \ ++ APLIC_xMSICFGADDRH_LHXS_SHIFT) ++#define APLIC_xMSICFGADDRH_HHXW_MASK 0x7 ++#define APLIC_xMSICFGADDRH_HHXW_SHIFT 16 ++#define APLIC_xMSICFGADDRH_HHXW (APLIC_xMSICFGADDRH_HHXW_MASK << \ ++ APLIC_xMSICFGADDRH_HHXW_SHIFT) ++#define APLIC_xMSICFGADDRH_LHXW_MASK 0xf ++#define APLIC_xMSICFGADDRH_LHXW_SHIFT 12 ++#define APLIC_xMSICFGADDRH_LHXW (APLIC_xMSICFGADDRH_LHXW_MASK << \ ++ APLIC_xMSICFGADDRH_LHXW_SHIFT) ++#define APLIC_xMSICFGADDRH_BAPPN_MASK 0xfff ++#define APLIC_xMSICFGADDRH_BAPPN_SHIFT 0 ++#define APLIC_xMSICFGADDRH_BAPPN (APLIC_xMSICFGADDRH_BAPPN_MASK << \ ++ APLIC_xMSICFGADDRH_BAPPN_SHIFT) ++ ++#define APLIC_xMSICFGADDR_PPN_SHIFT 12 ++ ++#define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \ ++ (BIT(__lhxs) - 1) ++ ++#define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \ ++ (BIT(__lhxw) - 1) ++#define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \ ++ ((__lhxs)) ++#define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \ ++ (APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \ ++ APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs)) ++ ++#define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \ ++ (BIT(__hhxw) - 1) ++#define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \ ++ ((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT) ++#define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \ ++ (APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \ ++ APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs)) ++ ++#define APLIC_IRQBITS_PER_REG 32 ++ ++#define APLIC_SETIP_BASE 0x1c00 ++#define APLIC_SETIPNUM 0x1cdc ++ ++#define APLIC_CLRIP_BASE 0x1d00 ++#define APLIC_CLRIPNUM 0x1ddc ++ ++#define APLIC_SETIE_BASE 0x1e00 ++#define APLIC_SETIENUM 0x1edc ++ ++#define APLIC_CLRIE_BASE 0x1f00 ++#define APLIC_CLRIENUM 0x1fdc ++ ++#define APLIC_SETIPNUM_LE 0x2000 ++#define APLIC_SETIPNUM_BE 0x2004 ++ ++#define APLIC_GENMSI 0x3000 ++ ++#define APLIC_TARGET_BASE 0x3004 ++#define APLIC_TARGET_HART_IDX_SHIFT 18 ++#define APLIC_TARGET_HART_IDX_MASK 0x3fff ++#define APLIC_TARGET_HART_IDX (APLIC_TARGET_HART_IDX_MASK << \ ++ APLIC_TARGET_HART_IDX_SHIFT) ++#define APLIC_TARGET_GUEST_IDX_SHIFT 12 ++#define APLIC_TARGET_GUEST_IDX_MASK 0x3f ++#define APLIC_TARGET_GUEST_IDX (APLIC_TARGET_GUEST_IDX_MASK << \ ++ APLIC_TARGET_GUEST_IDX_SHIFT) ++#define APLIC_TARGET_IPRIO_SHIFT 0 ++#define APLIC_TARGET_IPRIO_MASK 0xff ++#define APLIC_TARGET_IPRIO (APLIC_TARGET_IPRIO_MASK << \ ++ APLIC_TARGET_IPRIO_SHIFT) ++#define APLIC_TARGET_EIID_SHIFT 0 ++#define APLIC_TARGET_EIID_MASK 0x7ff ++#define APLIC_TARGET_EIID (APLIC_TARGET_EIID_MASK << \ ++ APLIC_TARGET_EIID_SHIFT) ++ ++#define APLIC_IDC_BASE 0x4000 ++#define APLIC_IDC_SIZE 32 ++ ++#define APLIC_IDC_IDELIVERY 0x00 ++ ++#define APLIC_IDC_IFORCE 0x04 ++ ++#define APLIC_IDC_ITHRESHOLD 0x08 ++ ++#define APLIC_IDC_TOPI 0x18 ++#define APLIC_IDC_TOPI_ID_SHIFT 16 ++#define APLIC_IDC_TOPI_ID_MASK 0x3ff ++#define APLIC_IDC_TOPI_ID (APLIC_IDC_TOPI_ID_MASK << \ ++ APLIC_IDC_TOPI_ID_SHIFT) ++#define APLIC_IDC_TOPI_PRIO_SHIFT 0 ++#define APLIC_IDC_TOPI_PRIO_MASK 0xff ++#define APLIC_IDC_TOPI_PRIO (APLIC_IDC_TOPI_PRIO_MASK << \ ++ APLIC_IDC_TOPI_PRIO_SHIFT) ++ ++#define APLIC_IDC_CLAIMI 0x1c ++ ++#endif +diff --git a/include/linux/irqchip/riscv-imsic.h b/include/linux/irqchip/riscv-imsic.h +new file mode 100644 +index 000000000000..faf0b800b1b0 +--- /dev/null ++++ b/include/linux/irqchip/riscv-imsic.h +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2021 Western Digital Corporation or its affiliates. ++ * Copyright (C) 2022 Ventana Micro Systems Inc. ++ */ ++#ifndef __LINUX_IRQCHIP_RISCV_IMSIC_H ++#define __LINUX_IRQCHIP_RISCV_IMSIC_H ++ ++#include ++#include ++#include ++ ++#define IMSIC_MMIO_PAGE_SHIFT 12 ++#define IMSIC_MMIO_PAGE_SZ BIT(IMSIC_MMIO_PAGE_SHIFT) ++#define IMSIC_MMIO_PAGE_LE 0x00 ++#define IMSIC_MMIO_PAGE_BE 0x04 ++ ++#define IMSIC_MIN_ID 63 ++#define IMSIC_MAX_ID 2048 ++ ++#define IMSIC_EIDELIVERY 0x70 ++ ++#define IMSIC_EITHRESHOLD 0x72 ++ ++#define IMSIC_EIP0 0x80 ++#define IMSIC_EIP63 0xbf ++#define IMSIC_EIPx_BITS 32 ++ ++#define IMSIC_EIE0 0xc0 ++#define IMSIC_EIE63 0xff ++#define IMSIC_EIEx_BITS 32 ++ ++#define IMSIC_FIRST IMSIC_EIDELIVERY ++#define IMSIC_LAST IMSIC_EIE63 ++ ++#define IMSIC_MMIO_SETIPNUM_LE 0x00 ++#define IMSIC_MMIO_SETIPNUM_BE 0x04 ++ ++struct imsic_local_config { ++ phys_addr_t msi_pa; ++ void __iomem *msi_va; ++}; ++ ++struct imsic_global_config { ++ /* ++ * MSI Target Address Scheme ++ * ++ * XLEN-1 12 0 ++ * | | | ++ * ------------------------------------------------------------- ++ * |xxxxxx|Group Index|xxxxxxxxxxx|HART Index|Guest Index| 0 | ++ * ------------------------------------------------------------- ++ */ ++ ++ /* Bits representing Guest index, HART index, and Group index */ ++ u32 guest_index_bits; ++ u32 hart_index_bits; ++ u32 group_index_bits; ++ u32 group_index_shift; ++ ++ /* Global base address matching all target MSI addresses */ ++ phys_addr_t base_addr; ++ ++ /* Number of interrupt identities */ ++ u32 nr_ids; ++ ++ /* Number of guest interrupt identities */ ++ u32 nr_guest_ids; ++ ++ /* Per-CPU IMSIC addresses */ ++ struct imsic_local_config __percpu *local; ++}; ++ ++#ifdef CONFIG_RISCV_IMSIC ++ ++const struct imsic_global_config *imsic_get_global_config(void); ++ ++#else ++ ++static inline const struct imsic_global_config *imsic_get_global_config(void) ++{ ++ return NULL; ++} ++ ++#endif ++ ++#endif +diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h +index 8594cd9b642e..2992c1851b63 100644 +--- a/include/linux/irqdomain.h ++++ b/include/linux/irqdomain.h +@@ -622,6 +622,23 @@ static inline bool irq_domain_is_msi_device(struct irq_domain *domain) + + #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + ++#ifdef CONFIG_GENERIC_MSI_IRQ ++int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq, ++ unsigned int type); ++void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq); ++#else ++static inline int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq, ++ unsigned int type) ++{ ++ WARN_ON_ONCE(1); ++ return -EINVAL; ++} ++static inline void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq) ++{ ++ WARN_ON_ONCE(1); ++} ++#endif ++ + #else /* CONFIG_IRQ_DOMAIN */ + static inline void irq_dispose_mapping(unsigned int virq) { } + static inline struct irq_domain *irq_find_matching_fwnode( +diff --git a/include/linux/irqdomain_defs.h b/include/linux/irqdomain_defs.h +index c29921fd8cd1..5c1fe6f1fcde 100644 +--- a/include/linux/irqdomain_defs.h ++++ b/include/linux/irqdomain_defs.h +@@ -26,6 +26,8 @@ enum irq_domain_bus_token { + DOMAIN_BUS_DMAR, + DOMAIN_BUS_AMDVI, + DOMAIN_BUS_PCI_DEVICE_IMS, ++ DOMAIN_BUS_DEVICE_MSI, ++ DOMAIN_BUS_WIRED_TO_MSI, + }; + + #endif /* _LINUX_IRQDOMAIN_DEFS_H */ diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 27f42f713c89..7617930d3157 100644 --- a/include/linux/mlx4/device.h @@ -556403,6 +562321,121 @@ index 27f42f713c89..7617930d3157 100644 #define MIN_MSIX_P_PORT 5 #define MLX4_IS_LEGACY_EQ_MODE(dev_cap) ((dev_cap).num_comp_vectors < \ (dev_cap).num_ports * MIN_MSIX_P_PORT) +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 2e6ef9532fc3..4454fcf3a953 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -3181,6 +3181,22 @@ static inline spinlock_t *pud_lock(struct mm_struct *mm, pud_t *pud) + return ptl; + } + ++static inline void pagetable_pud_ctor(struct ptdesc *ptdesc) ++{ ++ struct folio *folio = ptdesc_folio(ptdesc); ++ ++ __folio_set_pgtable(folio); ++ lruvec_stat_add_folio(folio, NR_PAGETABLE); ++} ++ ++static inline void pagetable_pud_dtor(struct ptdesc *ptdesc) ++{ ++ struct folio *folio = ptdesc_folio(ptdesc); ++ ++ __folio_clear_pgtable(folio); ++ lruvec_stat_sub_folio(folio, NR_PAGETABLE); ++} ++ + extern void __init pagecache_init(void); + extern void free_initmem(void); + +diff --git a/include/linux/msi.h b/include/linux/msi.h +index 5fd8a6caae98..b0ac7a49b529 100644 +--- a/include/linux/msi.h ++++ b/include/linux/msi.h +@@ -420,6 +420,7 @@ bool arch_restore_msi_irqs(struct pci_dev *dev); + struct irq_domain; + struct irq_domain_ops; + struct irq_chip; ++struct irq_fwspec; + struct device_node; + struct fwnode_handle; + struct msi_domain_info; +@@ -439,6 +440,8 @@ struct msi_domain_info; + * function. + * @msi_post_free: Optional function which is invoked after freeing + * all interrupts. ++ * @msi_translate: Optional translate callback to support the odd wire to ++ * MSI bridges, e.g. MBIGEN + * + * @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying + * irqdomain. +@@ -476,6 +479,8 @@ struct msi_domain_ops { + struct device *dev); + void (*msi_post_free)(struct irq_domain *domain, + struct device *dev); ++ int (*msi_translate)(struct irq_domain *domain, struct irq_fwspec *fwspec, ++ irq_hw_number_t *hwirq, unsigned int *type); + }; + + /** +@@ -555,6 +560,10 @@ enum { + MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 5), + /* Free MSI descriptors */ + MSI_FLAG_FREE_MSI_DESCS = (1 << 6), ++ /* Use dev->fwnode for MSI device domain creation */ ++ MSI_FLAG_USE_DEV_FWNODE = (1 << 7), ++ /* Set parent->dev into domain->pm_dev on device domain creation */ ++ MSI_FLAG_PARENT_PM_DEV = (1 << 8), + + /* Mask for the generic functionality */ + MSI_GENERIC_FLAGS_MASK = GENMASK(15, 0), +@@ -580,6 +589,11 @@ enum { + * struct msi_parent_ops - MSI parent domain callbacks and configuration info + * + * @supported_flags: Required: The supported MSI flags of the parent domain ++ * @required_flags: Optional: The required MSI flags of the parent MSI domain ++ * @bus_select_token: Optional: The bus token of the real parent domain for ++ * irq_domain::select() ++ * @bus_select_mask: Optional: A mask of supported BUS_DOMAINs for ++ * irq_domain::select() + * @prefix: Optional: Prefix for the domain and chip name + * @init_dev_msi_info: Required: Callback for MSI parent domains to setup parent + * domain specific domain flags, domain ops and interrupt chip +@@ -587,6 +601,9 @@ enum { + */ + struct msi_parent_ops { + u32 supported_flags; ++ u32 required_flags; ++ u32 bus_select_token; ++ u32 bus_select_mask; + const char *prefix; + bool (*init_dev_msi_info)(struct device *dev, struct irq_domain *domain, + struct irq_domain *msi_parent_domain, +@@ -635,13 +652,6 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain); + struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode, + struct msi_domain_info *info, + struct irq_domain *parent); +-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, +- irq_write_msi_msg_t write_msi_msg); +-#ifdef CONFIG_HISI_VIRTCCA_CODA +-int platform_msi_domain_alloc_range_irqs(struct device *dev, unsigned int start, +- unsigned int end, irq_write_msi_msg_t write_msi_msg); +-#endif +-void platform_msi_domain_free_irqs(struct device *dev); + + /* When an MSI domain is used as an intermediate domain */ + int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, +@@ -668,6 +678,10 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir + void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int virq, + unsigned int nvec); + void *platform_msi_get_host_data(struct irq_domain *domain); ++/* Per device platform MSI */ ++int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec, ++ irq_write_msi_msg_t write_msi_msg); ++void platform_device_msi_free_irqs_all(struct device *dev); + + bool msi_device_has_isolated_msi(struct device *dev); + #else /* CONFIG_GENERIC_MSI_IRQ */ diff --git a/include/linux/sync_core.h b/include/linux/sync_core.h index 013da4b8b327..67bb9794b875 100644 --- a/include/linux/sync_core.h @@ -556838,10 +562871,10 @@ index 000000000000..cfb1f017480c + +#endif /* __VS_DRM_H__ */ diff --git a/init/Kconfig b/init/Kconfig -index 1840935e919c..6ba464555bf7 100644 +index 5af21834fbff..6a7263bee7de 100644 --- a/init/Kconfig +++ b/init/Kconfig -@@ -2163,6 +2163,9 @@ source "kernel/Kconfig.locks" +@@ -2149,6 +2149,9 @@ source "kernel/Kconfig.locks" config ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE bool @@ -556851,6 +562884,430 @@ index 1840935e919c..6ba464555bf7 100644 config ARCH_HAS_SYNC_CORE_BEFORE_USERMODE bool +diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c +index f5cfc5069746..9cd4bb204a96 100644 +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -29,6 +29,7 @@ static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base, + unsigned int nr_irqs, int node, void *arg, + bool realloc, const struct irq_affinity_desc *affinity); + static void irq_domain_check_hierarchy(struct irq_domain *domain); ++static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq); + + struct irqchip_fwid { + struct fwnode_handle fwnode; +@@ -445,7 +446,7 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, + */ + mutex_lock(&irq_domain_mutex); + list_for_each_entry(h, &irq_domain_list, link) { +- if (h->ops->select && fwspec->param_count) ++ if (h->ops->select && bus_token != DOMAIN_BUS_ANY) + rc = h->ops->select(h, fwspec, bus_token); + else if (h->ops->match) + rc = h->ops->match(h, to_of_node(fwnode), bus_token); +@@ -855,8 +856,13 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) + } + + if (irq_domain_is_hierarchy(domain)) { +- virq = irq_domain_alloc_irqs_locked(domain, -1, 1, NUMA_NO_NODE, +- fwspec, false, NULL); ++ if (irq_domain_is_msi_device(domain)) { ++ mutex_unlock(&domain->root->mutex); ++ virq = msi_device_domain_alloc_wired(domain, hwirq, type); ++ mutex_lock(&domain->root->mutex); ++ } else ++ virq = irq_domain_alloc_irqs_locked(domain, -1, 1, NUMA_NO_NODE, ++ fwspec, false, NULL); + if (virq <= 0) { + virq = 0; + goto out; +@@ -911,7 +917,7 @@ void irq_dispose_mapping(unsigned int virq) + return; + + if (irq_domain_is_hierarchy(domain)) { +- irq_domain_free_irqs(virq, 1); ++ irq_domain_free_one_irq(domain, virq); + } else { + irq_domain_disassociate(domain, virq); + irq_free_desc(virq); +@@ -1763,6 +1769,14 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) + irq_free_descs(virq, nr_irqs); + } + ++static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq) ++{ ++ if (irq_domain_is_msi_device(domain)) ++ msi_device_domain_free_wired(domain, virq); ++ else ++ irq_domain_free_irqs(virq, 1); ++} ++ + /** + * irq_domain_alloc_irqs_parent - Allocate interrupts from parent domain + * @domain: Domain below which interrupts must be allocated +@@ -1915,9 +1929,9 @@ static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base, + return -EINVAL; + } + +-static void irq_domain_check_hierarchy(struct irq_domain *domain) +-{ +-} ++static void irq_domain_check_hierarchy(struct irq_domain *domain) { } ++static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq) { } ++ + #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + + #ifdef CONFIG_GENERIC_IRQ_DEBUGFS +diff --git a/kernel/irq/matrix.c b/kernel/irq/matrix.c +index 75d0ae490e29..8f222d1cccec 100644 +--- a/kernel/irq/matrix.c ++++ b/kernel/irq/matrix.c +@@ -8,8 +8,6 @@ + #include + #include + +-#define IRQ_MATRIX_SIZE (BITS_TO_LONGS(IRQ_MATRIX_BITS)) +- + struct cpumap { + unsigned int available; + unsigned int allocated; +@@ -17,8 +15,8 @@ struct cpumap { + unsigned int managed_allocated; + bool initialized; + bool online; +- unsigned long alloc_map[IRQ_MATRIX_SIZE]; +- unsigned long managed_map[IRQ_MATRIX_SIZE]; ++ unsigned long *managed_map; ++ unsigned long alloc_map[]; + }; + + struct irq_matrix { +@@ -32,8 +30,8 @@ struct irq_matrix { + unsigned int total_allocated; + unsigned int online_maps; + struct cpumap __percpu *maps; +- unsigned long scratch_map[IRQ_MATRIX_SIZE]; +- unsigned long system_map[IRQ_MATRIX_SIZE]; ++ unsigned long *system_map; ++ unsigned long scratch_map[]; + }; + + #define CREATE_TRACE_POINTS +@@ -50,24 +48,32 @@ __init struct irq_matrix *irq_alloc_matrix(unsigned int matrix_bits, + unsigned int alloc_start, + unsigned int alloc_end) + { ++ unsigned int cpu, matrix_size = BITS_TO_LONGS(matrix_bits); + struct irq_matrix *m; + +- if (matrix_bits > IRQ_MATRIX_BITS) +- return NULL; +- +- m = kzalloc(sizeof(*m), GFP_KERNEL); ++ m = kzalloc(struct_size(m, scratch_map, matrix_size * 2), GFP_KERNEL); + if (!m) + return NULL; + ++ m->system_map = &m->scratch_map[matrix_size]; ++ + m->matrix_bits = matrix_bits; + m->alloc_start = alloc_start; + m->alloc_end = alloc_end; + m->alloc_size = alloc_end - alloc_start; +- m->maps = alloc_percpu(*m->maps); ++ m->maps = __alloc_percpu(struct_size(m->maps, alloc_map, matrix_size * 2), ++ __alignof__(*m->maps)); + if (!m->maps) { + kfree(m); + return NULL; + } ++ ++ for_each_possible_cpu(cpu) { ++ struct cpumap *cm = per_cpu_ptr(m->maps, cpu); ++ ++ cm->managed_map = &cm->alloc_map[matrix_size]; ++ } ++ + return m; + } + +diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c +index 79b4a58ba9c3..f90952ebc494 100644 +--- a/kernel/irq/msi.c ++++ b/kernel/irq/msi.c +@@ -726,11 +726,26 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq, + irq_domain_free_irqs_top(domain, virq, nr_irqs); + } + ++static int msi_domain_translate(struct irq_domain *domain, struct irq_fwspec *fwspec, ++ irq_hw_number_t *hwirq, unsigned int *type) ++{ ++ struct msi_domain_info *info = domain->host_data; ++ ++ /* ++ * This will catch allocations through the regular irqdomain path except ++ * for MSI domains which really support this, e.g. MBIGEN. ++ */ ++ if (!info->ops->msi_translate) ++ return -ENOTSUPP; ++ return info->ops->msi_translate(domain, fwspec, hwirq, type); ++} ++ + static const struct irq_domain_ops msi_domain_ops = { + .alloc = msi_domain_alloc, + .free = msi_domain_free, + .activate = msi_domain_activate, + .deactivate = msi_domain_deactivate, ++ .translate = msi_domain_translate, + }; + + static irq_hw_number_t msi_domain_ops_get_hwirq(struct msi_domain_info *info, +@@ -830,8 +845,11 @@ static struct irq_domain *__msi_create_irq_domain(struct fwnode_handle *fwnode, + domain = irq_domain_create_hierarchy(parent, flags | IRQ_DOMAIN_FLAG_MSI, 0, + fwnode, &msi_domain_ops, info); + +- if (domain) ++ if (domain) { + irq_domain_update_bus_token(domain, info->bus_token); ++ if (info->flags & MSI_FLAG_PARENT_PM_DEV) ++ domain->pm_dev = parent->pm_dev; ++ } + + return domain; + } +@@ -945,9 +963,9 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, + void *chip_data) + { + struct irq_domain *domain, *parent = dev->msi.domain; +- const struct msi_parent_ops *pops; ++ struct fwnode_handle *fwnode, *fwnalloced = NULL; + struct msi_domain_template *bundle; +- struct fwnode_handle *fwnode; ++ const struct msi_parent_ops *pops; + + if (!irq_domain_is_msi_parent(parent)) + return false; +@@ -970,7 +988,19 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, + pops->prefix ? : "", bundle->chip.name, dev_name(dev)); + bundle->chip.name = bundle->name; + +- fwnode = irq_domain_alloc_named_fwnode(bundle->name); ++ /* ++ * Using the device firmware node is required for wire to MSI ++ * device domains so that the existing firmware results in a domain ++ * match. ++ * All other device domains like PCI/MSI use the named firmware ++ * node as they are not guaranteed to have a fwnode. They are never ++ * looked up and always handled in the context of the device. ++ */ ++ if (bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE) ++ fwnode = dev->fwnode; ++ else ++ fwnode = fwnalloced = irq_domain_alloc_named_fwnode(bundle->name); ++ + if (!fwnode) + goto free_bundle; + +@@ -997,7 +1027,7 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, + fail: + msi_unlock_descs(dev); + free_fwnode: +- irq_domain_free_fwnode(fwnode); ++ irq_domain_free_fwnode(fwnalloced); + free_bundle: + kfree(bundle); + return false; +@@ -1431,34 +1461,10 @@ int msi_domain_alloc_irqs_all_locked(struct device *dev, unsigned int domid, int + return msi_domain_alloc_locked(dev, &ctrl); + } + +-/** +- * msi_domain_alloc_irq_at - Allocate an interrupt from a MSI interrupt domain at +- * a given index - or at the next free index +- * +- * @dev: Pointer to device struct of the device for which the interrupts +- * are allocated +- * @domid: Id of the interrupt domain to operate on +- * @index: Index for allocation. If @index == %MSI_ANY_INDEX the allocation +- * uses the next free index. +- * @affdesc: Optional pointer to an interrupt affinity descriptor structure +- * @icookie: Optional pointer to a domain specific per instance cookie. If +- * non-NULL the content of the cookie is stored in msi_desc::data. +- * Must be NULL for MSI-X allocations +- * +- * This requires a MSI interrupt domain which lets the core code manage the +- * MSI descriptors. +- * +- * Return: struct msi_map +- * +- * On success msi_map::index contains the allocated index number and +- * msi_map::virq the corresponding Linux interrupt number +- * +- * On failure msi_map::index contains the error code and msi_map::virq +- * is %0. +- */ +-struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, unsigned int index, +- const struct irq_affinity_desc *affdesc, +- union msi_instance_cookie *icookie) ++static struct msi_map __msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, ++ unsigned int index, ++ const struct irq_affinity_desc *affdesc, ++ union msi_instance_cookie *icookie) + { + struct msi_ctrl ctrl = { .domid = domid, .nirqs = 1, }; + struct irq_domain *domain; +@@ -1466,17 +1472,16 @@ struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, u + struct msi_desc *desc; + int ret; + +- msi_lock_descs(dev); + domain = msi_get_device_domain(dev, domid); + if (!domain) { + map.index = -ENODEV; +- goto unlock; ++ return map; + } + + desc = msi_alloc_desc(dev, 1, affdesc); + if (!desc) { + map.index = -ENOMEM; +- goto unlock; ++ return map; + } + + if (icookie) +@@ -1485,7 +1490,7 @@ struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, u + ret = msi_insert_desc(dev, desc, domid, index); + if (ret) { + map.index = ret; +- goto unlock; ++ return map; + } + + ctrl.first = ctrl.last = desc->msi_index; +@@ -1498,11 +1503,90 @@ struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, u + map.index = desc->msi_index; + map.virq = desc->irq; + } +-unlock: ++ return map; ++} ++ ++/** ++ * msi_domain_alloc_irq_at - Allocate an interrupt from a MSI interrupt domain at ++ * a given index - or at the next free index ++ * ++ * @dev: Pointer to device struct of the device for which the interrupts ++ * are allocated ++ * @domid: Id of the interrupt domain to operate on ++ * @index: Index for allocation. If @index == %MSI_ANY_INDEX the allocation ++ * uses the next free index. ++ * @affdesc: Optional pointer to an interrupt affinity descriptor structure ++ * @icookie: Optional pointer to a domain specific per instance cookie. If ++ * non-NULL the content of the cookie is stored in msi_desc::data. ++ * Must be NULL for MSI-X allocations ++ * ++ * This requires a MSI interrupt domain which lets the core code manage the ++ * MSI descriptors. ++ * ++ * Return: struct msi_map ++ * ++ * On success msi_map::index contains the allocated index number and ++ * msi_map::virq the corresponding Linux interrupt number ++ * ++ * On failure msi_map::index contains the error code and msi_map::virq ++ * is %0. ++ */ ++struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, unsigned int index, ++ const struct irq_affinity_desc *affdesc, ++ union msi_instance_cookie *icookie) ++{ ++ struct msi_map map; ++ ++ msi_lock_descs(dev); ++ map = __msi_domain_alloc_irq_at(dev, domid, index, affdesc, icookie); + msi_unlock_descs(dev); + return map; + } + ++/** ++ * msi_device_domain_alloc_wired - Allocate a "wired" interrupt on @domain ++ * @domain: The domain to allocate on ++ * @hwirq: The hardware interrupt number to allocate for ++ * @type: The interrupt type ++ * ++ * This weirdness supports wire to MSI controllers like MBIGEN. ++ * ++ * @hwirq is the hardware interrupt number which is handed in from ++ * irq_create_fwspec_mapping(). As the wire to MSI domain is sparse, but ++ * sized in firmware, the hardware interrupt number cannot be used as MSI ++ * index. For the underlying irq chip the MSI index is irrelevant and ++ * all it needs is the hardware interrupt number. ++ * ++ * To handle this the MSI index is allocated with MSI_ANY_INDEX and the ++ * hardware interrupt number is stored along with the type information in ++ * msi_desc::cookie so the underlying interrupt chip and domain code can ++ * retrieve it. ++ * ++ * Return: The Linux interrupt number (> 0) or an error code ++ */ ++int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq, ++ unsigned int type) ++{ ++ unsigned int domid = MSI_DEFAULT_DOMAIN; ++ union msi_instance_cookie icookie = { }; ++ struct device *dev = domain->dev; ++ struct msi_map map = { }; ++ ++ if (WARN_ON_ONCE(!dev || domain->bus_token != DOMAIN_BUS_WIRED_TO_MSI)) ++ return -EINVAL; ++ ++ icookie.value = ((u64)type << 32) | hwirq; ++ ++ msi_lock_descs(dev); ++ if (WARN_ON_ONCE(msi_get_device_domain(dev, domid) != domain)) ++ map.index = -EINVAL; ++ else ++ map = __msi_domain_alloc_irq_at(dev, domid, MSI_ANY_INDEX, NULL, &icookie); ++ msi_unlock_descs(dev); ++ ++ return map.index >= 0 ? map.virq : map.index; ++} ++ + static void __msi_domain_free_irqs(struct device *dev, struct irq_domain *domain, + struct msi_ctrl *ctrl) + { +@@ -1628,6 +1712,30 @@ void msi_domain_free_irqs_all(struct device *dev, unsigned int domid) + msi_unlock_descs(dev); + } + ++/** ++ * msi_device_domain_free_wired - Free a wired interrupt in @domain ++ * @domain: The domain to free the interrupt on ++ * @virq: The Linux interrupt number to free ++ * ++ * This is the counterpart of msi_device_domain_alloc_wired() for the ++ * weird wired to MSI converting domains. ++ */ ++void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq) ++{ ++ struct msi_desc *desc = irq_get_msi_desc(virq); ++ struct device *dev = domain->dev; ++ ++ if (WARN_ON_ONCE(!dev || !desc || domain->bus_token != DOMAIN_BUS_WIRED_TO_MSI)) ++ return; ++ ++ msi_lock_descs(dev); ++ if (!WARN_ON_ONCE(msi_get_device_domain(dev, MSI_DEFAULT_DOMAIN) != domain)) { ++ msi_domain_free_irqs_range_locked(dev, MSI_DEFAULT_DOMAIN, desc->msi_index, ++ desc->msi_index); ++ } ++ msi_unlock_descs(dev); ++} ++ + /** + * msi_get_domain_info - Get the MSI interrupt domain info for @domain + * @domain: The interrupt domain to retrieve data from diff --git a/kernel/panic.c b/kernel/panic.c index ef9f9a4e928d..824220b20ad7 100644 --- a/kernel/panic.c @@ -556907,7 +563364,7 @@ index 462571b26f88..c456af8136c4 100644 ++*switch_count; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c -index fadc59328e3b..87e1f37996a6 100644 +index be1d35549144..64aea75c0de3 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -10590,6 +10590,9 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) @@ -556986,6 +563443,29 @@ index 5e2c2c26b3cc..368c8fc21b1f 100644 if (!dev) { pr_cont(" no tick device\n"); } else { +diff --git a/lib/find_bit.c b/lib/find_bit.c +index 32f99e9a670e..dacadd904250 100644 +--- a/lib/find_bit.c ++++ b/lib/find_bit.c +@@ -116,6 +116,18 @@ unsigned long _find_first_and_bit(const unsigned long *addr1, + EXPORT_SYMBOL(_find_first_and_bit); + #endif + ++/* ++ * Find the first set bit in three memory regions. ++ */ ++unsigned long _find_first_and_and_bit(const unsigned long *addr1, ++ const unsigned long *addr2, ++ const unsigned long *addr3, ++ unsigned long size) ++{ ++ return FIND_FIRST_BIT(addr1[idx] & addr2[idx] & addr3[idx], /* nop */, size); ++} ++EXPORT_SYMBOL(_find_first_and_and_bit); ++ + #ifndef find_first_zero_bit + /* + * Find the first cleared bit in a memory region. diff --git a/mm/memblock.c b/mm/memblock.c index b46bcb931a2e..7ebe8620bb6f 100644 --- a/mm/memblock.c diff --git a/kernel.spec b/kernel.spec index 9682bca..b26417c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -42,7 +42,7 @@ rm -f test_openEuler_sign.ko test_openEuler_sign.ko.sig %global upstream_sublevel 0 %global devel_release 73 %global maintenance_release .0.0 -%global pkg_release .65 +%global pkg_release .66 %global openeuler_lts 1 %global openeuler_major 2403 @@ -1124,6 +1124,12 @@ fi %endif %changelog +* Thu Jan 16 2025 Mingzheng Xing - 6.6.0-73.0.0.66 +- riscv kernel upgrade to 6.6.0-73.0.0 +- Backport RISC-V AIA driver from mainline linux +- Fix kernel-mode FPU support on riscv +- Add cache info for SG2042 dts + * Mon Jan 06 2025 ZhangPeng - 6.6.0-73.0.0.65 - !14618 drm: zynqmp_kms: Unplug DRM device before removal - drm: zynqmp_kms: Unplug DRM device before removal