mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-12-25 23:55:17 +00:00
LoongArch KVM changes for v6.13
1. Add iocsr and mmio bus simulation in kernel. 2. Add in-kernel interrupt controller emulation. 3. Add virt extension support for eiointc irqchip. -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEzOlt8mkP+tbeiYy5AoYrw/LiJnoFAmc0otUWHGNoZW5odWFj YWlAa2VybmVsLm9yZwAKCRAChivD8uImega1D/0Q91hUlKVp55QXDZrnpW7Z71v+ I9u8avjRiISDMLkjku/HE9eoD7lVYndzkDDSH32W+UVpBharJvuR+MIoH4jtLf3k IImybEaBwXru0+8YxbMqIzqcUEbQda0U5u31Ju1U6xcp+y1PGJJJDVPk4vBXOQB3 +wnLE6Q7orddw3s6G0QYtTv8jPDPOOL0Jv2ClqBaM8mTr2dIEpMjbZg2yGPMQVlE mVEgoked9OS5blkoxz2rEfUMQX5CVs20lyhfr05Qk2mTbeKITceqVlx183CyLMUO /9uJl7sD1ctxmQtU7ezeM7n7ItP9ehdAPECkt8WWSHM6mGbwHVTAtJoQGZjgoc6O pL1aSzhfGH3mdbwUCjhGsov6cZ4hliDQ76H3dlxrSr0JJX3zOPY5qDegmfDlxlyT uoKOAsx5D2N+WgshDPApZonkh38agaeTWposamseJbVNZXHmQV8Q8ipiNhgcgtVe mAReWfoYHL2mFIQNrfKS2i9J8mRj9SrjcQyNxgeU3L1s5Mr1p11yYXrkfVrZiHVk 0KzPfNJZvHO7zvgAIbyqyXEAY2Cq6F2r7UIELUOzY2zayoZwbn2jIZrsUVVbUsWp G4FbTRQDK1UR1cCVqe9jLmf5BzlSZ+jXOgcg+CxGIAelZ0qRcK/IgkX6/KygSlgY 49W45xpHtVUycsWDNA== =Jov3 -----END PGP SIGNATURE----- Merge tag 'loongarch-kvm-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson into HEAD LoongArch KVM changes for v6.13 1. Add iocsr and mmio bus simulation in kernel. 2. Add in-kernel interrupt controller emulation. 3. Add virt extension support for eiointc irqchip.
This commit is contained in:
commit
0586ade9e7
1
.mailmap
1
.mailmap
@ -665,6 +665,7 @@ Tomeu Vizoso <tomeu@tomeuvizoso.net> <tomeu.vizoso@collabora.com>
|
||||
Thomas Graf <tgraf@suug.ch>
|
||||
Thomas Körper <socketcan@esd.eu> <thomas.koerper@esd.eu>
|
||||
Thomas Pedersen <twp@codeaurora.org>
|
||||
Thorsten Blum <thorsten.blum@linux.dev> <thorsten.blum@toblux.com>
|
||||
Tiezhu Yang <yangtiezhu@loongson.cn> <kernelpatch@126.com>
|
||||
Tingwei Zhang <quic_tingwei@quicinc.com> <tingwei@codeaurora.org>
|
||||
Tirupathi Reddy <quic_tirupath@quicinc.com> <tirupath@codeaurora.org>
|
||||
|
||||
4
CREDITS
4
CREDITS
@ -1204,6 +1204,10 @@ S: Dreisbachstrasse 24
|
||||
S: D-57250 Netphen
|
||||
S: Germany
|
||||
|
||||
N: Florian Fainelli
|
||||
E: f.fainelli@gmail.com
|
||||
D: DSA
|
||||
|
||||
N: Rik Faith
|
||||
E: faith@acm.org
|
||||
D: Future Domain TMC-16x0 SCSI driver (author)
|
||||
|
||||
@ -6688,7 +6688,7 @@
|
||||
0: no polling (default)
|
||||
|
||||
thp_anon= [KNL]
|
||||
Format: <size>,<size>[KMG]:<state>;<size>-<size>[KMG]:<state>
|
||||
Format: <size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state>
|
||||
state is one of "always", "madvise", "never" or "inherit".
|
||||
Control the default behavior of the system with respect
|
||||
to anonymous transparent hugepages.
|
||||
|
||||
@ -303,7 +303,7 @@ control by passing the parameter ``transparent_hugepage=always`` or
|
||||
kernel command line.
|
||||
|
||||
Alternatively, each supported anonymous THP size can be controlled by
|
||||
passing ``thp_anon=<size>,<size>[KMG]:<state>;<size>-<size>[KMG]:<state>``,
|
||||
passing ``thp_anon=<size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state>``,
|
||||
where ``<size>`` is the THP size (must be a power of 2 of PAGE_SIZE and
|
||||
supported anonymous THP) and ``<state>`` is one of ``always``, ``madvise``,
|
||||
``never`` or ``inherit``.
|
||||
|
||||
@ -85,6 +85,70 @@ to CPUINTC directly::
|
||||
| Devices |
|
||||
+---------+
|
||||
|
||||
Virtual Extended IRQ model
|
||||
==========================
|
||||
|
||||
In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt
|
||||
go to CPUINTC directly, CPU UARTS interrupts go to PCH-PIC, while all other
|
||||
devices interrupts go to PCH-PIC/PCH-MSI and gathered by V-EIOINTC (Virtual
|
||||
Extended I/O Interrupt Controller), and then go to CPUINTC directly::
|
||||
|
||||
+-----+ +-------------------+ +-------+
|
||||
| IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer |
|
||||
+-----+ +-------------------+ +-------+
|
||||
^
|
||||
|
|
||||
+-----------+
|
||||
| V-EIOINTC |
|
||||
+-----------+
|
||||
^ ^
|
||||
| |
|
||||
+---------+ +---------+
|
||||
| PCH-PIC | | PCH-MSI |
|
||||
+---------+ +---------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
+--------+ +---------+ +---------+
|
||||
| UARTs | | Devices | | Devices |
|
||||
+--------+ +---------+ +---------+
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
V-EIOINTC (Virtual Extended I/O Interrupt Controller) is an extension of
|
||||
EIOINTC, it only works in VM mode which runs in KVM hypervisor. Interrupts can
|
||||
be routed to up to four vCPUs via standard EIOINTC, however with V-EIOINTC
|
||||
interrupts can be routed to up to 256 virtual cpus.
|
||||
|
||||
With standard EIOINTC, interrupt routing setting includes two parts: eight
|
||||
bits for CPU selection and four bits for CPU IP (Interrupt Pin) selection.
|
||||
For CPU selection there is four bits for EIOINTC node selection, four bits
|
||||
for EIOINTC CPU selection. Bitmap method is used for CPU selection and
|
||||
CPU IP selection, so interrupt can only route to CPU0 - CPU3 and IP0-IP3 in
|
||||
one EIOINTC node.
|
||||
|
||||
With V-EIOINTC it supports to route more CPUs and CPU IP (Interrupt Pin),
|
||||
there are two newly added registers with V-EIOINTC.
|
||||
|
||||
EXTIOI_VIRT_FEATURES
|
||||
--------------------
|
||||
This register is read-only register, which indicates supported features with
|
||||
V-EIOINTC. Feature EXTIOI_HAS_INT_ENCODE and EXTIOI_HAS_CPU_ENCODE is added.
|
||||
|
||||
Feature EXTIOI_HAS_INT_ENCODE is part of standard EIOINTC. If it is 1, it
|
||||
indicates that CPU Interrupt Pin selection can be normal method rather than
|
||||
bitmap method, so interrupt can be routed to IP0 - IP15.
|
||||
|
||||
Feature EXTIOI_HAS_CPU_ENCODE is entension of V-EIOINTC. If it is 1, it
|
||||
indicates that CPU selection can be normal method rather than bitmap method,
|
||||
so interrupt can be routed to CPU0 - CPU255.
|
||||
|
||||
EXTIOI_VIRT_CONFIG
|
||||
------------------
|
||||
This register is read-write register, for compatibility intterupt routed uses
|
||||
the default method which is the same with standard EIOINTC. If the bit is set
|
||||
with 1, it indicated HW to use normal method rather than bitmap method.
|
||||
|
||||
Advanced Extended IRQ model
|
||||
===========================
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ properties:
|
||||
atomic mode of operation, even if requested.
|
||||
default: 0
|
||||
|
||||
max-rx-timeout-ms:
|
||||
arm,max-rx-timeout-ms:
|
||||
description:
|
||||
An optional time value, expressed in milliseconds, representing the
|
||||
transport maximum timeout value for the receive channel. The value should
|
||||
|
||||
@ -61,7 +61,7 @@ properties:
|
||||
- gmii
|
||||
- rgmii
|
||||
- sgmii
|
||||
- 1000BaseX
|
||||
- 1000base-x
|
||||
|
||||
xlnx,phy-type:
|
||||
description:
|
||||
|
||||
@ -293,7 +293,6 @@ operations:
|
||||
doc: Get endpoint information
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &get-addr-attrs
|
||||
request:
|
||||
attributes:
|
||||
|
||||
@ -121,7 +121,7 @@ format, the Group Extension is set in the PS-field.
|
||||
|
||||
On the other hand, when using PDU1 format, the PS-field contains a so-called
|
||||
Destination Address, which is _not_ part of the PGN. When communicating a PGN
|
||||
from user space to kernel (or vice versa) and PDU2 format is used, the PS-field
|
||||
from user space to kernel (or vice versa) and PDU1 format is used, the PS-field
|
||||
of the PGN shall be set to zero. The Destination Address shall be set
|
||||
elsewhere.
|
||||
|
||||
|
||||
@ -87,6 +87,61 @@ PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC::
|
||||
| Devices |
|
||||
+---------+
|
||||
|
||||
虚拟扩展IRQ模型
|
||||
===============
|
||||
|
||||
在这种模型里面, IPI(Inter-Processor Interrupt) 和CPU本地时钟中断直接发送到CPUINTC,
|
||||
CPU串口 (UARTs) 中断发送到PCH-PIC, 而其他所有设备的中断则分别发送到所连接的PCH_PIC/
|
||||
PCH-MSI, 然后V-EIOINTC统一收集,再直接到达CPUINTC::
|
||||
|
||||
+-----+ +-------------------+ +-------+
|
||||
| IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer |
|
||||
+-----+ +-------------------+ +-------+
|
||||
^
|
||||
|
|
||||
+-----------+
|
||||
| V-EIOINTC |
|
||||
+-----------+
|
||||
^ ^
|
||||
| |
|
||||
+---------+ +---------+
|
||||
| PCH-PIC | | PCH-MSI |
|
||||
+---------+ +---------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
+--------+ +---------+ +---------+
|
||||
| UARTs | | Devices | | Devices |
|
||||
+--------+ +---------+ +---------+
|
||||
|
||||
V-EIOINTC 是EIOINTC的扩展, 仅工作在虚拟机模式下, 中断经EIOINTC最多可个路由到
|
||||
4个虚拟CPU. 但中断经V-EIOINTC最多可个路由到256个虚拟CPU.
|
||||
|
||||
传统的EIOINTC中断控制器,中断路由分为两个部分:8比特用于控制路由到哪个CPU,
|
||||
4比特用于控制路由到特定CPU的哪个中断管脚。控制CPU路由的8比特前4比特用于控制
|
||||
路由到哪个EIOINTC节点,后4比特用于控制此节点哪个CPU。中断路由在选择CPU路由
|
||||
和CPU中断管脚路由时,使用bitmap编码方式而不是正常编码方式,所以对于一个
|
||||
EIOINTC中断控制器节点,中断只能路由到CPU0 - CPU3,中断管脚IP0-IP3。
|
||||
|
||||
V-EIOINTC新增了两个寄存器,支持中断路由到更多CPU个和中断管脚。
|
||||
|
||||
V-EIOINTC功能寄存器
|
||||
-------------------
|
||||
功能寄存器是只读寄存器,用于显示V-EIOINTC支持的特性,目前两个支持两个特性
|
||||
EXTIOI_HAS_INT_ENCODE 和 EXTIOI_HAS_CPU_ENCODE。
|
||||
|
||||
特性EXTIOI_HAS_INT_ENCODE是传统EIOINTC中断控制器的一个特性,如果此比特为1,
|
||||
显示CPU中断管脚路由方式支持正常编码,而不是bitmap编码,所以中断可以路由到
|
||||
管脚IP0 - IP15。
|
||||
|
||||
特性EXTIOI_HAS_CPU_ENCODE是V-EIOINTC新增特性,如果此比特为1,表示CPU路由
|
||||
方式支持正常编码,而不是bitmap编码,所以中断可以路由到CPU0 - CPU255。
|
||||
|
||||
V-EIOINTC配置寄存器
|
||||
-------------------
|
||||
配置寄存器是可读写寄存器,为了兼容性考虑,如果不写此寄存器,中断路由采用
|
||||
和传统EIOINTC相同的路由设置。如果对应比特设置为1,表示采用正常路由方式而
|
||||
不是bitmap编码的路由方式。
|
||||
|
||||
高级扩展IRQ模型
|
||||
===============
|
||||
|
||||
|
||||
28
MAINTAINERS
28
MAINTAINERS
@ -1174,8 +1174,9 @@ F: Documentation/hid/amd-sfh*
|
||||
F: drivers/hid/amd-sfh-hid/
|
||||
|
||||
AMD SPI DRIVER
|
||||
M: Sanjay R Mehta <sanju.mehta@amd.com>
|
||||
S: Maintained
|
||||
M: Raju Rangoju <Raju.Rangoju@amd.com>
|
||||
L: linux-spi@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/spi/spi-amd.c
|
||||
|
||||
AMD XGBE DRIVER
|
||||
@ -2852,7 +2853,7 @@ F: Documentation/devicetree/bindings/arm/qcom.yaml
|
||||
F: Documentation/devicetree/bindings/bus/qcom*
|
||||
F: Documentation/devicetree/bindings/cache/qcom,llcc.yaml
|
||||
F: Documentation/devicetree/bindings/firmware/qcom,scm.yaml
|
||||
F: Documentation/devicetree/bindings/reserved-memory/qcom
|
||||
F: Documentation/devicetree/bindings/reserved-memory/qcom*
|
||||
F: Documentation/devicetree/bindings/soc/qcom/
|
||||
F: arch/arm/boot/dts/qcom/
|
||||
F: arch/arm/configs/qcom_defconfig
|
||||
@ -3745,6 +3746,7 @@ F: drivers/spi/spi-axi-spi-engine.c
|
||||
AXI PWM GENERATOR
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
R: Trevor Gamblin <tgamblin@baylibre.com>
|
||||
L: linux-pwm@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
@ -16082,7 +16084,6 @@ F: drivers/net/wireless/
|
||||
|
||||
NETWORKING [DSA]
|
||||
M: Andrew Lunn <andrew@lunn.ch>
|
||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||
M: Vladimir Oltean <olteanv@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/dsa/
|
||||
@ -19846,12 +19847,10 @@ L: linux-riscv@lists.infradead.org
|
||||
S: Maintained
|
||||
Q: https://patchwork.kernel.org/project/linux-riscv/list/
|
||||
T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
|
||||
F: Documentation/devicetree/bindings/riscv/
|
||||
F: arch/riscv/boot/dts/
|
||||
X: arch/riscv/boot/dts/allwinner/
|
||||
X: arch/riscv/boot/dts/renesas/
|
||||
X: arch/riscv/boot/dts/sophgo/
|
||||
X: arch/riscv/boot/dts/thead/
|
||||
F: arch/riscv/boot/dts/canaan/
|
||||
F: arch/riscv/boot/dts/microchip/
|
||||
F: arch/riscv/boot/dts/sifive/
|
||||
F: arch/riscv/boot/dts/starfive/
|
||||
|
||||
RISC-V PMU DRIVERS
|
||||
M: Atish Patra <atishp@atishpatra.org>
|
||||
@ -21618,6 +21617,15 @@ S: Supported
|
||||
W: https://github.com/thesofproject/linux/
|
||||
F: sound/soc/sof/
|
||||
|
||||
SOUND - GENERIC SOUND CARD (Simple-Audio-Card, Audio-Graph-Card)
|
||||
M: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
S: Supported
|
||||
L: linux-sound@vger.kernel.org
|
||||
F: sound/soc/generic/
|
||||
F: include/sound/simple_card*
|
||||
F: Documentation/devicetree/bindings/sound/simple-card.yaml
|
||||
F: Documentation/devicetree/bindings/sound/audio-graph*.yaml
|
||||
|
||||
SOUNDWIRE SUBSYSTEM
|
||||
M: Vinod Koul <vkoul@kernel.org>
|
||||
M: Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
|
||||
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 12
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@ -325,8 +325,8 @@
|
||||
&i2c2 {
|
||||
status = "okay";
|
||||
|
||||
rt5616: rt5616@1b {
|
||||
compatible = "rt5616";
|
||||
rt5616: audio-codec@1b {
|
||||
compatible = "realtek,rt5616";
|
||||
reg = <0x1b>;
|
||||
clocks = <&cru SCLK_I2S_OUT>;
|
||||
clock-names = "mclk";
|
||||
|
||||
@ -384,12 +384,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
acodec: acodec-ana@20030000 {
|
||||
compatible = "rk3036-codec";
|
||||
acodec: audio-codec@20030000 {
|
||||
compatible = "rockchip,rk3036-codec";
|
||||
reg = <0x20030000 0x4000>;
|
||||
rockchip,grf = <&grf>;
|
||||
clock-names = "acodec_pclk";
|
||||
clocks = <&cru PCLK_ACODEC>;
|
||||
rockchip,grf = <&grf>;
|
||||
#sound-dai-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -399,7 +400,6 @@
|
||||
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru PCLK_HDMI>;
|
||||
clock-names = "pclk";
|
||||
rockchip,grf = <&grf>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&hdmi_ctl>;
|
||||
#sound-dai-cells = <0>;
|
||||
@ -553,11 +553,11 @@
|
||||
};
|
||||
|
||||
spi: spi@20074000 {
|
||||
compatible = "rockchip,rockchip-spi";
|
||||
compatible = "rockchip,rk3036-spi";
|
||||
reg = <0x20074000 0x1000>;
|
||||
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru PCLK_SPI>, <&cru SCLK_SPI>;
|
||||
clock-names = "apb-pclk","spi_pclk";
|
||||
clocks = <&cru SCLK_SPI>, <&cru PCLK_SPI>;
|
||||
clock-names = "spiclk", "apb_pclk";
|
||||
dmas = <&pdma 8>, <&pdma 9>;
|
||||
dma-names = "tx", "rx";
|
||||
pinctrl-names = "default";
|
||||
|
||||
@ -2214,6 +2214,7 @@ config ARM64_SME
|
||||
bool "ARM Scalable Matrix Extension support"
|
||||
default y
|
||||
depends on ARM64_SVE
|
||||
depends on BROKEN
|
||||
help
|
||||
The Scalable Matrix Extension (SME) is an extension to the AArch64
|
||||
execution state which utilises a substantial subset of the SVE
|
||||
|
||||
@ -14,7 +14,7 @@ lvds0_subsys: bus@56240000 {
|
||||
compatible = "fsl,imx8qxp-lpcg";
|
||||
reg = <0x56243000 0x4>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "mipi1_lis_lpcg_ipg_clk";
|
||||
clock-output-names = "lvds0_lis_lpcg_ipg_clk";
|
||||
power-domains = <&pd IMX_SC_R_MIPI_1>;
|
||||
};
|
||||
|
||||
@ -22,9 +22,9 @@ lvds0_subsys: bus@56240000 {
|
||||
compatible = "fsl,imx8qxp-lpcg";
|
||||
reg = <0x5624300c 0x4>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "mipi1_pwm_lpcg_clk",
|
||||
"mipi1_pwm_lpcg_ipg_clk",
|
||||
"mipi1_pwm_lpcg_32k_clk";
|
||||
clock-output-names = "lvds0_pwm_lpcg_clk",
|
||||
"lvds0_pwm_lpcg_ipg_clk",
|
||||
"lvds0_pwm_lpcg_32k_clk";
|
||||
power-domains = <&pd IMX_SC_R_MIPI_1_PWM_0>;
|
||||
};
|
||||
|
||||
@ -32,8 +32,8 @@ lvds0_subsys: bus@56240000 {
|
||||
compatible = "fsl,imx8qxp-lpcg";
|
||||
reg = <0x56243010 0x4>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "mipi1_i2c0_lpcg_clk",
|
||||
"mipi1_i2c0_lpcg_ipg_clk";
|
||||
clock-output-names = "lvds0_i2c0_lpcg_clk",
|
||||
"lvds0_i2c0_lpcg_ipg_clk";
|
||||
power-domains = <&pd IMX_SC_R_MIPI_1_I2C_0>;
|
||||
};
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ vpu: vpu@2c000000 {
|
||||
mu_m0: mailbox@2d000000 {
|
||||
compatible = "fsl,imx6sx-mu";
|
||||
reg = <0x2d000000 0x20000>;
|
||||
interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#mbox-cells = <2>;
|
||||
power-domains = <&pd IMX_SC_R_VPU_MU_0>;
|
||||
status = "disabled";
|
||||
@ -24,7 +24,7 @@ vpu: vpu@2c000000 {
|
||||
mu1_m0: mailbox@2d020000 {
|
||||
compatible = "fsl,imx6sx-mu";
|
||||
reg = <0x2d020000 0x20000>;
|
||||
interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#mbox-cells = <2>;
|
||||
power-domains = <&pd IMX_SC_R_VPU_MU_1>;
|
||||
status = "disabled";
|
||||
|
||||
@ -218,6 +218,18 @@
|
||||
};
|
||||
};
|
||||
|
||||
&media_blk_ctrl {
|
||||
/*
|
||||
* The LVDS panel on this device uses 72.4 MHz pixel clock,
|
||||
* set IMX8MP_VIDEO_PLL1 to 72.4 * 7 = 506.8 MHz so the LDB
|
||||
* serializer and LCDIFv3 scanout engine can reach accurate
|
||||
* pixel clock of exactly 72.4 MHz.
|
||||
*/
|
||||
assigned-clock-rates = <500000000>, <200000000>,
|
||||
<0>, <0>, <500000000>,
|
||||
<506800000>;
|
||||
};
|
||||
|
||||
&snvs_pwrkey {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -71,6 +71,7 @@
|
||||
assigned-clock-rates = <500000000>, <200000000>, <0>,
|
||||
/* IMX8MP_CLK_MEDIA_DISP2_PIX = pixelclk of lvds panel */
|
||||
<68900000>,
|
||||
<500000000>,
|
||||
/* IMX8MP_VIDEO_PLL1 = IMX8MP_CLK_MEDIA_LDB * 2 */
|
||||
<964600000>;
|
||||
};
|
||||
|
||||
@ -1261,7 +1261,7 @@
|
||||
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
|
||||
reg = <0x30b40000 0x10000>;
|
||||
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX8MP_CLK_DUMMY>,
|
||||
clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
|
||||
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
|
||||
<&clk IMX8MP_CLK_USDHC1_ROOT>;
|
||||
clock-names = "ipg", "ahb", "per";
|
||||
@ -1275,7 +1275,7 @@
|
||||
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
|
||||
reg = <0x30b50000 0x10000>;
|
||||
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX8MP_CLK_DUMMY>,
|
||||
clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
|
||||
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
|
||||
<&clk IMX8MP_CLK_USDHC2_ROOT>;
|
||||
clock-names = "ipg", "ahb", "per";
|
||||
@ -1289,7 +1289,7 @@
|
||||
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
|
||||
reg = <0x30b60000 0x10000>;
|
||||
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX8MP_CLK_DUMMY>,
|
||||
clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
|
||||
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
|
||||
<&clk IMX8MP_CLK_USDHC3_ROOT>;
|
||||
clock-names = "ipg", "ahb", "per";
|
||||
|
||||
@ -5,6 +5,14 @@
|
||||
* Author: Alexander Stein
|
||||
*/
|
||||
|
||||
&mu_m0 {
|
||||
interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
&mu1_m0 {
|
||||
interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
&vpu_core0 {
|
||||
reg = <0x2d040000 0x10000>;
|
||||
};
|
||||
|
||||
@ -384,7 +384,7 @@
|
||||
};
|
||||
|
||||
flexspi2: spi@29810000 {
|
||||
compatible = "nxp,imx8mm-fspi";
|
||||
compatible = "nxp,imx8ulp-fspi";
|
||||
reg = <0x29810000 0x10000>, <0x60000000 0x10000000>;
|
||||
reg-names = "fspi_base", "fspi_mmap";
|
||||
#address-cells = <1>;
|
||||
|
||||
@ -248,7 +248,7 @@
|
||||
|
||||
smd-edge {
|
||||
interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
|
||||
mboxes = <&apcs1_mbox 0>;
|
||||
qcom,ipc = <&apcs1_mbox 8 0>;
|
||||
qcom,smd-edge = <15>;
|
||||
|
||||
rpm_requests: rpm-requests {
|
||||
|
||||
@ -1973,7 +1973,7 @@
|
||||
|
||||
clocks = <&gcc GCC_PCIE_1_PIPE_CLK>,
|
||||
<&gcc GCC_PCIE_1_PIPE_CLK_SRC>,
|
||||
<&pcie1_phy>,
|
||||
<&pcie1_phy QMP_PCIE_PIPE_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_PCIE_1_AUX_CLK>,
|
||||
<&gcc GCC_PCIE_1_CFG_AHB_CLK>,
|
||||
|
||||
@ -139,6 +139,8 @@
|
||||
|
||||
pinctrl-0 = <&nvme_reg_en>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
vph_pwr: regulator-vph-pwr {
|
||||
|
||||
@ -134,6 +134,8 @@
|
||||
|
||||
pinctrl-0 = <&nvme_reg_en>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -177,9 +177,9 @@
|
||||
compatible = "qcom,x1e80100-sndcard";
|
||||
model = "X1E80100-CRD";
|
||||
audio-routing = "WooferLeft IN", "WSA WSA_SPK1 OUT",
|
||||
"TwitterLeft IN", "WSA WSA_SPK2 OUT",
|
||||
"TweeterLeft IN", "WSA WSA_SPK2 OUT",
|
||||
"WooferRight IN", "WSA2 WSA_SPK2 OUT",
|
||||
"TwitterRight IN", "WSA2 WSA_SPK2 OUT",
|
||||
"TweeterRight IN", "WSA2 WSA_SPK2 OUT",
|
||||
"IN1_HPHL", "HPHL_OUT",
|
||||
"IN2_HPHR", "HPHR_OUT",
|
||||
"AMIC2", "MIC BIAS2",
|
||||
@ -300,6 +300,8 @@
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&nvme_reg_en>;
|
||||
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
vreg_wwan: regulator-wwan {
|
||||
@ -933,7 +935,7 @@
|
||||
reg = <0 1>;
|
||||
reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "TwitterLeft";
|
||||
sound-name-prefix = "TweeterLeft";
|
||||
vdd-1p8-supply = <&vreg_l15b_1p8>;
|
||||
vdd-io-supply = <&vreg_l12b_1p2>;
|
||||
qcom,port-mapping = <4 5 6 7 11 13>;
|
||||
@ -986,7 +988,7 @@
|
||||
reg = <0 1>;
|
||||
reset-gpios = <&lpass_tlmm 13 GPIO_ACTIVE_LOW>;
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "TwitterRight";
|
||||
sound-name-prefix = "TweeterRight";
|
||||
vdd-1p8-supply = <&vreg_l15b_1p8>;
|
||||
vdd-io-supply = <&vreg_l12b_1p2>;
|
||||
qcom,port-mapping = <4 5 6 7 11 13>;
|
||||
|
||||
@ -205,6 +205,8 @@
|
||||
|
||||
pinctrl-0 = <&nvme_reg_en>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -164,6 +164,8 @@
|
||||
|
||||
pinctrl-0 = <&nvme_reg_en>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -253,6 +253,8 @@
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&nvme_reg_en>;
|
||||
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -2924,14 +2924,14 @@
|
||||
"mhi";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges = <0x01000000 0 0x00000000 0 0x70200000 0 0x100000>,
|
||||
<0x02000000 0 0x70300000 0 0x70300000 0 0x3d00000>;
|
||||
bus-range = <0 0xff>;
|
||||
ranges = <0x01000000 0x0 0x00000000 0x0 0x70200000 0x0 0x100000>,
|
||||
<0x02000000 0x0 0x70300000 0x0 0x70300000 0x0 0x1d00000>;
|
||||
bus-range = <0x00 0xff>;
|
||||
|
||||
dma-coherent;
|
||||
|
||||
linux,pci-domain = <6>;
|
||||
num-lanes = <2>;
|
||||
num-lanes = <4>;
|
||||
|
||||
interrupts = <GIC_SPI 773 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 774 IRQ_TYPE_LEVEL_HIGH>,
|
||||
@ -2997,19 +2997,22 @@
|
||||
};
|
||||
|
||||
pcie6a_phy: phy@1bfc000 {
|
||||
compatible = "qcom,x1e80100-qmp-gen4x2-pcie-phy";
|
||||
reg = <0 0x01bfc000 0 0x2000>;
|
||||
compatible = "qcom,x1e80100-qmp-gen4x4-pcie-phy";
|
||||
reg = <0 0x01bfc000 0 0x2000>,
|
||||
<0 0x01bfe000 0 0x2000>;
|
||||
|
||||
clocks = <&gcc GCC_PCIE_6A_PHY_AUX_CLK>,
|
||||
<&gcc GCC_PCIE_6A_CFG_AHB_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&tcsr TCSR_PCIE_4L_CLKREF_EN>,
|
||||
<&gcc GCC_PCIE_6A_PHY_RCHNG_CLK>,
|
||||
<&gcc GCC_PCIE_6A_PIPE_CLK>;
|
||||
<&gcc GCC_PCIE_6A_PIPE_CLK>,
|
||||
<&gcc GCC_PCIE_6A_PIPEDIV2_CLK>;
|
||||
clock-names = "aux",
|
||||
"cfg_ahb",
|
||||
"ref",
|
||||
"rchng",
|
||||
"pipe";
|
||||
"pipe",
|
||||
"pipediv2";
|
||||
|
||||
resets = <&gcc GCC_PCIE_6A_PHY_BCR>,
|
||||
<&gcc GCC_PCIE_6A_NOCSR_COM_PHY_BCR>;
|
||||
@ -3021,6 +3024,8 @@
|
||||
|
||||
power-domains = <&gcc GCC_PCIE_6_PHY_GDSC>;
|
||||
|
||||
qcom,4ln-config-sel = <&tcsr 0x1a000 0>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "pcie6a_pipe_clk";
|
||||
|
||||
@ -3097,7 +3102,7 @@
|
||||
assigned-clocks = <&gcc GCC_PCIE_5_AUX_CLK>;
|
||||
assigned-clock-rates = <19200000>;
|
||||
|
||||
interconnects = <&pcie_south_anoc MASTER_PCIE_5 QCOM_ICC_TAG_ALWAYS
|
||||
interconnects = <&pcie_north_anoc MASTER_PCIE_5 QCOM_ICC_TAG_ALWAYS
|
||||
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
|
||||
<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
|
||||
&cnoc_main SLAVE_PCIE_5 QCOM_ICC_TAG_ALWAYS>;
|
||||
@ -3124,14 +3129,16 @@
|
||||
|
||||
clocks = <&gcc GCC_PCIE_5_AUX_CLK>,
|
||||
<&gcc GCC_PCIE_5_CFG_AHB_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&tcsr TCSR_PCIE_2L_5_CLKREF_EN>,
|
||||
<&gcc GCC_PCIE_5_PHY_RCHNG_CLK>,
|
||||
<&gcc GCC_PCIE_5_PIPE_CLK>;
|
||||
<&gcc GCC_PCIE_5_PIPE_CLK>,
|
||||
<&gcc GCC_PCIE_5_PIPEDIV2_CLK>;
|
||||
clock-names = "aux",
|
||||
"cfg_ahb",
|
||||
"ref",
|
||||
"rchng",
|
||||
"pipe";
|
||||
"pipe",
|
||||
"pipediv2";
|
||||
|
||||
resets = <&gcc GCC_PCIE_5_PHY_BCR>;
|
||||
reset-names = "phy";
|
||||
@ -3166,8 +3173,8 @@
|
||||
"mhi";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges = <0x01000000 0 0x00000000 0 0x7c200000 0 0x100000>,
|
||||
<0x02000000 0 0x7c300000 0 0x7c300000 0 0x3d00000>;
|
||||
ranges = <0x01000000 0x0 0x00000000 0x0 0x7c200000 0x0 0x100000>,
|
||||
<0x02000000 0x0 0x7c300000 0x0 0x7c300000 0x0 0x1d00000>;
|
||||
bus-range = <0x00 0xff>;
|
||||
|
||||
dma-coherent;
|
||||
@ -3217,7 +3224,7 @@
|
||||
assigned-clocks = <&gcc GCC_PCIE_4_AUX_CLK>;
|
||||
assigned-clock-rates = <19200000>;
|
||||
|
||||
interconnects = <&pcie_south_anoc MASTER_PCIE_4 QCOM_ICC_TAG_ALWAYS
|
||||
interconnects = <&pcie_north_anoc MASTER_PCIE_4 QCOM_ICC_TAG_ALWAYS
|
||||
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
|
||||
<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
|
||||
&cnoc_main SLAVE_PCIE_4 QCOM_ICC_TAG_ALWAYS>;
|
||||
@ -3254,14 +3261,16 @@
|
||||
|
||||
clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
|
||||
<&gcc GCC_PCIE_4_CFG_AHB_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&tcsr TCSR_PCIE_2L_4_CLKREF_EN>,
|
||||
<&gcc GCC_PCIE_4_PHY_RCHNG_CLK>,
|
||||
<&gcc GCC_PCIE_4_PIPE_CLK>;
|
||||
<&gcc GCC_PCIE_4_PIPE_CLK>,
|
||||
<&gcc GCC_PCIE_4_PIPEDIV2_CLK>;
|
||||
clock-names = "aux",
|
||||
"cfg_ahb",
|
||||
"ref",
|
||||
"rchng",
|
||||
"pipe";
|
||||
"pipe",
|
||||
"pipediv2";
|
||||
|
||||
resets = <&gcc GCC_PCIE_4_PHY_BCR>;
|
||||
reset-names = "phy";
|
||||
@ -6084,7 +6093,8 @@
|
||||
<0 0x25a00000 0 0x200000>,
|
||||
<0 0x25c00000 0 0x200000>,
|
||||
<0 0x25e00000 0 0x200000>,
|
||||
<0 0x26000000 0 0x200000>;
|
||||
<0 0x26000000 0 0x200000>,
|
||||
<0 0x26200000 0 0x200000>;
|
||||
reg-names = "llcc0_base",
|
||||
"llcc1_base",
|
||||
"llcc2_base",
|
||||
@ -6093,7 +6103,8 @@
|
||||
"llcc5_base",
|
||||
"llcc6_base",
|
||||
"llcc7_base",
|
||||
"llcc_broadcast_base";
|
||||
"llcc_broadcast_base",
|
||||
"llcc_broadcast_and_base";
|
||||
interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
|
||||
@ -66,7 +66,6 @@
|
||||
bus-width = <8>;
|
||||
cap-mmc-highspeed;
|
||||
mmc-hs200-1_8v;
|
||||
supports-emmc;
|
||||
mmc-pwrseq = <&emmc_pwrseq>;
|
||||
non-removable;
|
||||
vmmc-supply = <&vcc_3v3>;
|
||||
|
||||
@ -36,14 +36,14 @@
|
||||
|
||||
power_led: led-0 {
|
||||
label = "firefly:red:power";
|
||||
linux,default-trigger = "ir-power-click";
|
||||
linux,default-trigger = "default-on";
|
||||
default-state = "on";
|
||||
gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
user_led: led-1 {
|
||||
label = "firefly:blue:user";
|
||||
linux,default-trigger = "ir-user-click";
|
||||
linux,default-trigger = "rc-feedback";
|
||||
default-state = "off";
|
||||
gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
@ -24,9 +24,7 @@
|
||||
disable-wp;
|
||||
mmc-hs200-1_8v;
|
||||
non-removable;
|
||||
num-slots = <1>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
|
||||
supports-emmc;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -754,8 +754,7 @@
|
||||
compatible = "rockchip,rk3328-dw-hdmi";
|
||||
reg = <0x0 0xff3c0000 0x0 0x20000>;
|
||||
reg-io-width = <4>;
|
||||
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru PCLK_HDMI>,
|
||||
<&cru SCLK_HDMI_SFC>,
|
||||
<&cru SCLK_RTC32K>;
|
||||
|
||||
@ -61,7 +61,6 @@
|
||||
fan: fan@18 {
|
||||
compatible = "ti,amc6821";
|
||||
reg = <0x18>;
|
||||
#cooling-cells = <2>;
|
||||
};
|
||||
|
||||
rtc_twi: rtc@6f {
|
||||
|
||||
@ -541,7 +541,7 @@
|
||||
status = "okay";
|
||||
|
||||
rt5651: audio-codec@1a {
|
||||
compatible = "rockchip,rt5651";
|
||||
compatible = "realtek,rt5651";
|
||||
reg = <0x1a>;
|
||||
clocks = <&cru SCLK_I2S_8CH_OUT>;
|
||||
clock-names = "mclk";
|
||||
|
||||
@ -166,7 +166,6 @@
|
||||
regulator-max-microvolt = <1800000>;
|
||||
vin-supply = <&vcc3v3_sys>;
|
||||
gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
/* MIPI DSI panel 2.8v supply */
|
||||
@ -178,7 +177,6 @@
|
||||
regulator-max-microvolt = <2800000>;
|
||||
vin-supply = <&vcc3v3_sys>;
|
||||
gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
vibrator {
|
||||
|
||||
@ -114,7 +114,6 @@
|
||||
es8388: es8388@11 {
|
||||
compatible = "everest,es8388";
|
||||
reg = <0x11>;
|
||||
clock-names = "mclk";
|
||||
clocks = <&cru SCLK_I2S_8CH_OUT>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
|
||||
@ -576,7 +576,7 @@
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
clocks = <&rk808 1>;
|
||||
clock-names = "ext_clock";
|
||||
clock-names = "txco";
|
||||
device-wakeup-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
|
||||
host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
|
||||
shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
@ -163,7 +163,7 @@
|
||||
status = "okay";
|
||||
|
||||
rt5651: rt5651@1a {
|
||||
compatible = "rockchip,rt5651";
|
||||
compatible = "realtek,rt5651";
|
||||
reg = <0x1a>;
|
||||
clocks = <&cru SCLK_I2S_8CH_OUT>;
|
||||
clock-names = "mclk";
|
||||
|
||||
@ -92,7 +92,7 @@
|
||||
};
|
||||
|
||||
&i2c2 {
|
||||
pintctrl-names = "default";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c2m1_xfer>;
|
||||
status = "okay";
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@
|
||||
};
|
||||
|
||||
&i2c2 {
|
||||
pintctrl-names = "default";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c2m1_xfer>;
|
||||
status = "okay";
|
||||
|
||||
|
||||
@ -449,9 +449,9 @@
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
clocks = <&pmucru CLK_RTC_32K>;
|
||||
clock-names = "ext_clock";
|
||||
device-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
|
||||
host-wake-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
|
||||
clock-names = "txco";
|
||||
device-wakeup-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
|
||||
host-wakeup-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
|
||||
shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
|
||||
|
||||
@ -507,7 +507,6 @@
|
||||
non-removable;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
|
||||
supports-emmc;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@ -684,11 +684,11 @@
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
clocks = <&rk817 1>;
|
||||
clock-names = "lpo";
|
||||
device-wake-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
|
||||
host-wake-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_LOW>;
|
||||
device-wakeup-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
|
||||
host-wakeup-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-0 = <&bt_enable_h>, <&bt_host_wake_l>, <&bt_wake_h>;
|
||||
pinctrl-names = "default";
|
||||
shutdown-gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>;
|
||||
vbat-supply = <&vcc_wl>;
|
||||
vddio-supply = <&vcca_1v8_pmu>;
|
||||
};
|
||||
|
||||
@ -402,9 +402,9 @@
|
||||
clock-names = "lpo";
|
||||
device-wakeup-gpios = <&gpio2 RK_PB2 GPIO_ACTIVE_HIGH>;
|
||||
host-wakeup-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&bt_host_wake_h &bt_reg_on_h &bt_wake_host_h>;
|
||||
shutdown-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
|
||||
vbat-supply = <&vcc_3v3>;
|
||||
vddio-supply = <&vcc_1v8>;
|
||||
};
|
||||
|
||||
@ -589,7 +589,6 @@
|
||||
non-removable;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
|
||||
supports-emmc;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@ -272,7 +272,6 @@
|
||||
regulator-name = "vdd_logic";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-init-microvolt = <900000>;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
@ -285,7 +284,6 @@
|
||||
|
||||
vdd_gpu: DCDC_REG2 {
|
||||
regulator-name = "vdd_gpu";
|
||||
regulator-init-microvolt = <900000>;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
@ -309,7 +307,6 @@
|
||||
|
||||
vdd_npu: DCDC_REG4 {
|
||||
regulator-name = "vdd_npu";
|
||||
regulator-init-microvolt = <900000>;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
|
||||
@ -337,15 +337,19 @@
|
||||
cache-unified;
|
||||
next-level-cache = <&l3_cache>;
|
||||
};
|
||||
};
|
||||
|
||||
l3_cache: l3-cache {
|
||||
compatible = "cache";
|
||||
cache-size = <3145728>;
|
||||
cache-line-size = <64>;
|
||||
cache-sets = <4096>;
|
||||
cache-level = <3>;
|
||||
cache-unified;
|
||||
};
|
||||
/*
|
||||
* The L3 cache belongs to the DynamIQ Shared Unit (DSU),
|
||||
* so it's represented here, outside the "cpus" node
|
||||
*/
|
||||
l3_cache: l3-cache {
|
||||
compatible = "cache";
|
||||
cache-size = <3145728>;
|
||||
cache-line-size = <64>;
|
||||
cache-sets = <4096>;
|
||||
cache-level = <3>;
|
||||
cache-unified;
|
||||
};
|
||||
|
||||
display_subsystem: display-subsystem {
|
||||
|
||||
@ -328,7 +328,6 @@
|
||||
compatible = "everest,es8388";
|
||||
reg = <0x11>;
|
||||
clocks = <&cru I2S0_8CH_MCLKOUT>;
|
||||
clock-names = "mclk";
|
||||
AVDD-supply = <&vcc_1v8_s0>;
|
||||
DVDD-supply = <&vcc_1v8_s0>;
|
||||
HPVDD-supply = <&vcc_3v3_s0>;
|
||||
|
||||
@ -316,7 +316,6 @@
|
||||
assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
|
||||
assigned-clock-rates = <12288000>;
|
||||
clocks = <&cru I2S0_8CH_MCLKOUT>;
|
||||
clock-names = "mclk";
|
||||
AVDD-supply = <&avcc_1v8_codec_s0>;
|
||||
DVDD-supply = <&avcc_1v8_codec_s0>;
|
||||
HPVDD-supply = <&vcc_3v3_s0>;
|
||||
|
||||
@ -304,12 +304,12 @@
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map1 {
|
||||
map0 {
|
||||
trip = <&package_fan0>;
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT 1>;
|
||||
};
|
||||
|
||||
map2 {
|
||||
map1 {
|
||||
trip = <&package_fan1>;
|
||||
cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
|
||||
};
|
||||
|
||||
@ -428,7 +428,6 @@
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <950000>;
|
||||
regulator-init-microvolt = <750000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
|
||||
@ -296,6 +296,7 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
|
||||
<&rk806_dvs2_null>, <&rk806_dvs3_null>;
|
||||
system-power-controller;
|
||||
|
||||
vcc1-supply = <&vcc5v0_sys>;
|
||||
vcc2-supply = <&vcc5v0_sys>;
|
||||
|
||||
@ -377,7 +377,6 @@
|
||||
assigned-clock-rates = <12288000>;
|
||||
assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
|
||||
AVDD-supply = <&vcc_3v3_s3>;
|
||||
clock-names = "mclk";
|
||||
clocks = <&cru I2S0_8CH_MCLKOUT>;
|
||||
DVDD-supply = <&vcc_1v8_s3>;
|
||||
HPVDD-supply = <&vcc_3v3_s3>;
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
|
||||
#ifndef BUILD_VDSO
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
|
||||
@ -31,19 +33,21 @@ static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
|
||||
}
|
||||
#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
|
||||
|
||||
static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
|
||||
static inline unsigned long arch_calc_vm_flag_bits(struct file *file,
|
||||
unsigned long flags)
|
||||
{
|
||||
/*
|
||||
* Only allow MTE on anonymous mappings as these are guaranteed to be
|
||||
* backed by tags-capable memory. The vm_flags may be overridden by a
|
||||
* filesystem supporting MTE (RAM-based).
|
||||
*/
|
||||
if (system_supports_mte() && (flags & MAP_ANONYMOUS))
|
||||
if (system_supports_mte() &&
|
||||
((flags & MAP_ANONYMOUS) || shmem_file(file)))
|
||||
return VM_MTE_ALLOWED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags)
|
||||
#define arch_calc_vm_flag_bits(file, flags) arch_calc_vm_flag_bits(file, flags)
|
||||
|
||||
static inline bool arch_validate_prot(unsigned long prot,
|
||||
unsigned long addr __always_unused)
|
||||
|
||||
@ -26,10 +26,6 @@ void update_freq_counters_refs(void);
|
||||
#define arch_scale_freq_invariant topology_scale_freq_invariant
|
||||
#define arch_scale_freq_ref topology_get_freq_ref
|
||||
|
||||
#ifdef CONFIG_ACPI_CPPC_LIB
|
||||
#define arch_init_invariance_cppc topology_init_cpu_capacity_cppc
|
||||
#endif
|
||||
|
||||
/* Replace task scheduler's default cpu-invariant accounting */
|
||||
#define arch_scale_cpu_capacity topology_get_cpu_scale
|
||||
|
||||
|
||||
@ -1367,6 +1367,7 @@ static void sve_init_regs(void)
|
||||
} else {
|
||||
fpsimd_to_sve(current);
|
||||
current->thread.fp_type = FP_STATE_SVE;
|
||||
fpsimd_flush_task_state(current);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,48 +7,19 @@
|
||||
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
/*
|
||||
* If we have SMCCC v1.3 and (as is likely) no SVE state in
|
||||
* the registers then set the SMCCC hint bit to say there's no
|
||||
* need to preserve it. Do this by directly adjusting the SMCCC
|
||||
* function value which is already stored in x0 ready to be called.
|
||||
*/
|
||||
SYM_FUNC_START(__arm_smccc_sve_check)
|
||||
|
||||
ldr_l x16, smccc_has_sve_hint
|
||||
cbz x16, 2f
|
||||
|
||||
get_current_task x16
|
||||
ldr x16, [x16, #TSK_TI_FLAGS]
|
||||
tbnz x16, #TIF_FOREIGN_FPSTATE, 1f // Any live FP state?
|
||||
tbnz x16, #TIF_SVE, 2f // Does that state include SVE?
|
||||
|
||||
1: orr x0, x0, ARM_SMCCC_1_3_SVE_HINT
|
||||
|
||||
2: ret
|
||||
SYM_FUNC_END(__arm_smccc_sve_check)
|
||||
EXPORT_SYMBOL(__arm_smccc_sve_check)
|
||||
|
||||
.macro SMCCC instr
|
||||
stp x29, x30, [sp, #-16]!
|
||||
mov x29, sp
|
||||
alternative_if ARM64_SVE
|
||||
bl __arm_smccc_sve_check
|
||||
alternative_else_nop_endif
|
||||
\instr #0
|
||||
ldr x4, [sp, #16]
|
||||
ldr x4, [sp]
|
||||
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
|
||||
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
|
||||
ldr x4, [sp, #24]
|
||||
ldr x4, [sp, #8]
|
||||
cbz x4, 1f /* no quirk structure */
|
||||
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
|
||||
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
|
||||
b.ne 1f
|
||||
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
|
||||
1: ldp x29, x30, [sp], #16
|
||||
ret
|
||||
1: ret
|
||||
.endm
|
||||
|
||||
/*
|
||||
|
||||
@ -65,6 +65,7 @@ extern struct acpi_vector_group pch_group[MAX_IO_PICS];
|
||||
extern struct acpi_vector_group msi_group[MAX_IO_PICS];
|
||||
|
||||
#define CORES_PER_EIO_NODE 4
|
||||
#define CORES_PER_VEIO_NODE 256
|
||||
|
||||
#define LOONGSON_CPU_UART0_VEC 10 /* CPU UART0 */
|
||||
#define LOONGSON_CPU_THSENS_VEC 14 /* CPU Thsens */
|
||||
|
||||
123
arch/loongarch/include/asm/kvm_eiointc.h
Normal file
123
arch/loongarch/include/asm/kvm_eiointc.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef __ASM_KVM_EIOINTC_H
|
||||
#define __ASM_KVM_EIOINTC_H
|
||||
|
||||
#include <kvm/iodev.h>
|
||||
|
||||
#define EIOINTC_IRQS 256
|
||||
#define EIOINTC_ROUTE_MAX_VCPUS 256
|
||||
#define EIOINTC_IRQS_U8_NUMS (EIOINTC_IRQS / 8)
|
||||
#define EIOINTC_IRQS_U16_NUMS (EIOINTC_IRQS_U8_NUMS / 2)
|
||||
#define EIOINTC_IRQS_U32_NUMS (EIOINTC_IRQS_U8_NUMS / 4)
|
||||
#define EIOINTC_IRQS_U64_NUMS (EIOINTC_IRQS_U8_NUMS / 8)
|
||||
/* map to ipnum per 32 irqs */
|
||||
#define EIOINTC_IRQS_NODETYPE_COUNT 16
|
||||
|
||||
#define EIOINTC_BASE 0x1400
|
||||
#define EIOINTC_SIZE 0x900
|
||||
|
||||
#define EIOINTC_NODETYPE_START 0xa0
|
||||
#define EIOINTC_NODETYPE_END 0xbf
|
||||
#define EIOINTC_IPMAP_START 0xc0
|
||||
#define EIOINTC_IPMAP_END 0xc7
|
||||
#define EIOINTC_ENABLE_START 0x200
|
||||
#define EIOINTC_ENABLE_END 0x21f
|
||||
#define EIOINTC_BOUNCE_START 0x280
|
||||
#define EIOINTC_BOUNCE_END 0x29f
|
||||
#define EIOINTC_ISR_START 0x300
|
||||
#define EIOINTC_ISR_END 0x31f
|
||||
#define EIOINTC_COREISR_START 0x400
|
||||
#define EIOINTC_COREISR_END 0x41f
|
||||
#define EIOINTC_COREMAP_START 0x800
|
||||
#define EIOINTC_COREMAP_END 0x8ff
|
||||
|
||||
#define EIOINTC_VIRT_BASE (0x40000000)
|
||||
#define EIOINTC_VIRT_SIZE (0x1000)
|
||||
|
||||
#define EIOINTC_VIRT_FEATURES (0x0)
|
||||
#define EIOINTC_HAS_VIRT_EXTENSION (0)
|
||||
#define EIOINTC_HAS_ENABLE_OPTION (1)
|
||||
#define EIOINTC_HAS_INT_ENCODE (2)
|
||||
#define EIOINTC_HAS_CPU_ENCODE (3)
|
||||
#define EIOINTC_VIRT_HAS_FEATURES ((1U << EIOINTC_HAS_VIRT_EXTENSION) \
|
||||
| (1U << EIOINTC_HAS_ENABLE_OPTION) \
|
||||
| (1U << EIOINTC_HAS_INT_ENCODE) \
|
||||
| (1U << EIOINTC_HAS_CPU_ENCODE))
|
||||
#define EIOINTC_VIRT_CONFIG (0x4)
|
||||
#define EIOINTC_ENABLE (1)
|
||||
#define EIOINTC_ENABLE_INT_ENCODE (2)
|
||||
#define EIOINTC_ENABLE_CPU_ENCODE (3)
|
||||
|
||||
#define LOONGSON_IP_NUM 8
|
||||
|
||||
struct loongarch_eiointc {
|
||||
spinlock_t lock;
|
||||
struct kvm *kvm;
|
||||
struct kvm_io_device device;
|
||||
struct kvm_io_device device_vext;
|
||||
uint32_t num_cpu;
|
||||
uint32_t features;
|
||||
uint32_t status;
|
||||
|
||||
/* hardware state */
|
||||
union nodetype {
|
||||
u64 reg_u64[EIOINTC_IRQS_NODETYPE_COUNT / 4];
|
||||
u32 reg_u32[EIOINTC_IRQS_NODETYPE_COUNT / 2];
|
||||
u16 reg_u16[EIOINTC_IRQS_NODETYPE_COUNT];
|
||||
u8 reg_u8[EIOINTC_IRQS_NODETYPE_COUNT * 2];
|
||||
} nodetype;
|
||||
|
||||
/* one bit shows the state of one irq */
|
||||
union bounce {
|
||||
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
|
||||
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
|
||||
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
|
||||
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
|
||||
} bounce;
|
||||
|
||||
union isr {
|
||||
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
|
||||
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
|
||||
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
|
||||
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
|
||||
} isr;
|
||||
union coreisr {
|
||||
u64 reg_u64[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U64_NUMS];
|
||||
u32 reg_u32[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U32_NUMS];
|
||||
u16 reg_u16[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U16_NUMS];
|
||||
u8 reg_u8[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U8_NUMS];
|
||||
} coreisr;
|
||||
union enable {
|
||||
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
|
||||
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
|
||||
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
|
||||
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
|
||||
} enable;
|
||||
|
||||
/* use one byte to config ipmap for 32 irqs at once */
|
||||
union ipmap {
|
||||
u64 reg_u64;
|
||||
u32 reg_u32[EIOINTC_IRQS_U32_NUMS / 4];
|
||||
u16 reg_u16[EIOINTC_IRQS_U16_NUMS / 4];
|
||||
u8 reg_u8[EIOINTC_IRQS_U8_NUMS / 4];
|
||||
} ipmap;
|
||||
/* use one byte to config coremap for one irq */
|
||||
union coremap {
|
||||
u64 reg_u64[EIOINTC_IRQS / 8];
|
||||
u32 reg_u32[EIOINTC_IRQS / 4];
|
||||
u16 reg_u16[EIOINTC_IRQS / 2];
|
||||
u8 reg_u8[EIOINTC_IRQS];
|
||||
} coremap;
|
||||
|
||||
DECLARE_BITMAP(sw_coreisr[EIOINTC_ROUTE_MAX_VCPUS][LOONGSON_IP_NUM], EIOINTC_IRQS);
|
||||
uint8_t sw_coremap[EIOINTC_IRQS];
|
||||
};
|
||||
|
||||
int kvm_loongarch_register_eiointc_device(void);
|
||||
void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level);
|
||||
|
||||
#endif /* __ASM_KVM_EIOINTC_H */
|
||||
@ -18,8 +18,13 @@
|
||||
|
||||
#include <asm/inst.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_ipi.h>
|
||||
#include <asm/kvm_eiointc.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
#include <asm/loongarch.h>
|
||||
|
||||
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||
|
||||
/* Loongarch KVM register ids */
|
||||
#define KVM_GET_IOC_CSR_IDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
|
||||
#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
|
||||
@ -44,6 +49,12 @@ struct kvm_vm_stat {
|
||||
struct kvm_vm_stat_generic generic;
|
||||
u64 pages;
|
||||
u64 hugepages;
|
||||
u64 ipi_read_exits;
|
||||
u64 ipi_write_exits;
|
||||
u64 eiointc_read_exits;
|
||||
u64 eiointc_write_exits;
|
||||
u64 pch_pic_read_exits;
|
||||
u64 pch_pic_write_exits;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_stat {
|
||||
@ -84,7 +95,7 @@ struct kvm_world_switch {
|
||||
*
|
||||
* For LOONGARCH_CSR_CPUID register, max CPUID size if 512
|
||||
* For IPI hardware, max destination CPUID size 1024
|
||||
* For extioi interrupt controller, max destination CPUID size is 256
|
||||
* For eiointc interrupt controller, max destination CPUID size is 256
|
||||
* For msgint interrupt controller, max supported CPUID size is 65536
|
||||
*
|
||||
* Currently max CPUID is defined as 256 for KVM hypervisor, in future
|
||||
@ -117,6 +128,9 @@ struct kvm_arch {
|
||||
|
||||
s64 time_offset;
|
||||
struct kvm_context __percpu *vmcs;
|
||||
struct loongarch_ipi *ipi;
|
||||
struct loongarch_eiointc *eiointc;
|
||||
struct loongarch_pch_pic *pch_pic;
|
||||
};
|
||||
|
||||
#define CSR_MAX_NUMS 0x800
|
||||
@ -221,6 +235,8 @@ struct kvm_vcpu_arch {
|
||||
int last_sched_cpu;
|
||||
/* mp state */
|
||||
struct kvm_mp_state mp_state;
|
||||
/* ipi state */
|
||||
struct ipi_state ipi_state;
|
||||
/* cpucfg */
|
||||
u32 cpucfg[KVM_MAX_CPUCFG_REGS];
|
||||
|
||||
|
||||
45
arch/loongarch/include/asm/kvm_ipi.h
Normal file
45
arch/loongarch/include/asm/kvm_ipi.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef __ASM_KVM_IPI_H
|
||||
#define __ASM_KVM_IPI_H
|
||||
|
||||
#include <kvm/iodev.h>
|
||||
|
||||
#define LARCH_INT_IPI 12
|
||||
|
||||
struct loongarch_ipi {
|
||||
spinlock_t lock;
|
||||
struct kvm *kvm;
|
||||
struct kvm_io_device device;
|
||||
};
|
||||
|
||||
struct ipi_state {
|
||||
spinlock_t lock;
|
||||
uint32_t status;
|
||||
uint32_t en;
|
||||
uint32_t set;
|
||||
uint32_t clear;
|
||||
uint64_t buf[4];
|
||||
};
|
||||
|
||||
#define IOCSR_IPI_BASE 0x1000
|
||||
#define IOCSR_IPI_SIZE 0x160
|
||||
|
||||
#define IOCSR_IPI_STATUS 0x000
|
||||
#define IOCSR_IPI_EN 0x004
|
||||
#define IOCSR_IPI_SET 0x008
|
||||
#define IOCSR_IPI_CLEAR 0x00c
|
||||
#define IOCSR_IPI_BUF_20 0x020
|
||||
#define IOCSR_IPI_BUF_28 0x028
|
||||
#define IOCSR_IPI_BUF_30 0x030
|
||||
#define IOCSR_IPI_BUF_38 0x038
|
||||
#define IOCSR_IPI_SEND 0x040
|
||||
#define IOCSR_MAIL_SEND 0x048
|
||||
#define IOCSR_ANY_SEND 0x158
|
||||
|
||||
int kvm_loongarch_register_ipi_device(void);
|
||||
|
||||
#endif
|
||||
62
arch/loongarch/include/asm/kvm_pch_pic.h
Normal file
62
arch/loongarch/include/asm/kvm_pch_pic.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef __ASM_KVM_PCH_PIC_H
|
||||
#define __ASM_KVM_PCH_PIC_H
|
||||
|
||||
#include <kvm/iodev.h>
|
||||
|
||||
#define PCH_PIC_SIZE 0x3e8
|
||||
|
||||
#define PCH_PIC_INT_ID_START 0x0
|
||||
#define PCH_PIC_INT_ID_END 0x7
|
||||
#define PCH_PIC_MASK_START 0x20
|
||||
#define PCH_PIC_MASK_END 0x27
|
||||
#define PCH_PIC_HTMSI_EN_START 0x40
|
||||
#define PCH_PIC_HTMSI_EN_END 0x47
|
||||
#define PCH_PIC_EDGE_START 0x60
|
||||
#define PCH_PIC_EDGE_END 0x67
|
||||
#define PCH_PIC_CLEAR_START 0x80
|
||||
#define PCH_PIC_CLEAR_END 0x87
|
||||
#define PCH_PIC_AUTO_CTRL0_START 0xc0
|
||||
#define PCH_PIC_AUTO_CTRL0_END 0xc7
|
||||
#define PCH_PIC_AUTO_CTRL1_START 0xe0
|
||||
#define PCH_PIC_AUTO_CTRL1_END 0xe7
|
||||
#define PCH_PIC_ROUTE_ENTRY_START 0x100
|
||||
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
||||
#define PCH_PIC_HTMSI_VEC_START 0x200
|
||||
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
||||
#define PCH_PIC_INT_IRR_START 0x380
|
||||
#define PCH_PIC_INT_IRR_END 0x38f
|
||||
#define PCH_PIC_INT_ISR_START 0x3a0
|
||||
#define PCH_PIC_INT_ISR_END 0x3af
|
||||
#define PCH_PIC_POLARITY_START 0x3e0
|
||||
#define PCH_PIC_POLARITY_END 0x3e7
|
||||
#define PCH_PIC_INT_ID_VAL 0x7000000UL
|
||||
#define PCH_PIC_INT_ID_VER 0x1UL
|
||||
|
||||
struct loongarch_pch_pic {
|
||||
spinlock_t lock;
|
||||
struct kvm *kvm;
|
||||
struct kvm_io_device device;
|
||||
uint64_t mask; /* 1:disable irq, 0:enable irq */
|
||||
uint64_t htmsi_en; /* 1:msi */
|
||||
uint64_t edge; /* 1:edge triggered, 0:level triggered */
|
||||
uint64_t auto_ctrl0; /* only use default value 00b */
|
||||
uint64_t auto_ctrl1; /* only use default value 00b */
|
||||
uint64_t last_intirr; /* edge detection */
|
||||
uint64_t irr; /* interrupt request register */
|
||||
uint64_t isr; /* interrupt service register */
|
||||
uint64_t polarity; /* 0: high level trigger, 1: low level trigger */
|
||||
uint8_t route_entry[64]; /* default value 0, route to int0: eiointc */
|
||||
uint8_t htmsi_vector[64]; /* irq route table for routing to eiointc */
|
||||
uint64_t pch_pic_base;
|
||||
};
|
||||
|
||||
int kvm_loongarch_register_pch_pic_device(void);
|
||||
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level);
|
||||
void pch_msi_set_irq(struct kvm *kvm, int irq, int level);
|
||||
|
||||
#endif /* __ASM_KVM_PCH_PIC_H */
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define __KVM_HAVE_IRQ_LINE
|
||||
|
||||
/*
|
||||
* KVM LoongArch specific structures and definitions.
|
||||
*
|
||||
@ -132,4 +134,22 @@ struct kvm_iocsr_entry {
|
||||
#define KVM_IRQCHIP_NUM_PINS 64
|
||||
#define KVM_MAX_CORES 256
|
||||
|
||||
#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000001
|
||||
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000002
|
||||
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS 0x40000003
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU 0x0
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE 0x1
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE 0x2
|
||||
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL 0x40000004
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU 0x0
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE 0x1
|
||||
#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED 0x3
|
||||
|
||||
#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005
|
||||
#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000006
|
||||
#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0
|
||||
|
||||
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
|
||||
|
||||
@ -21,13 +21,16 @@ config KVM
|
||||
tristate "Kernel-based Virtual Machine (KVM) support"
|
||||
depends on AS_HAS_LVZ_EXTENSION
|
||||
select HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||
select HAVE_KVM_IRQ_ROUTING
|
||||
select HAVE_KVM_IRQCHIP
|
||||
select HAVE_KVM_MSI
|
||||
select HAVE_KVM_READONLY_MEM
|
||||
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||
select KVM_COMMON
|
||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||
select KVM_GENERIC_HARDWARE_ENABLING
|
||||
select KVM_GENERIC_MMU_NOTIFIER
|
||||
select KVM_MMIO
|
||||
select HAVE_KVM_READONLY_MEM
|
||||
select KVM_XFER_TO_GUEST_WORK
|
||||
select SCHED_INFO
|
||||
help
|
||||
|
||||
@ -18,5 +18,9 @@ kvm-y += timer.o
|
||||
kvm-y += tlb.o
|
||||
kvm-y += vcpu.o
|
||||
kvm-y += vm.o
|
||||
kvm-y += intc/ipi.o
|
||||
kvm-y += intc/eiointc.o
|
||||
kvm-y += intc/pch_pic.o
|
||||
kvm-y += irqfd.o
|
||||
|
||||
CFLAGS_exit.o += $(call cc-option,-Wno-override-init,)
|
||||
|
||||
@ -157,7 +157,7 @@ static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
|
||||
int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
unsigned long val;
|
||||
unsigned long *val;
|
||||
u32 addr, rd, rj, opcode;
|
||||
|
||||
/*
|
||||
@ -170,6 +170,7 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
ret = EMULATE_DO_IOCSR;
|
||||
run->iocsr_io.phys_addr = addr;
|
||||
run->iocsr_io.is_write = 0;
|
||||
val = &vcpu->arch.gprs[rd];
|
||||
|
||||
/* LoongArch is Little endian */
|
||||
switch (opcode) {
|
||||
@ -202,16 +203,25 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
run->iocsr_io.is_write = 1;
|
||||
break;
|
||||
default:
|
||||
ret = EMULATE_FAIL;
|
||||
break;
|
||||
return EMULATE_FAIL;
|
||||
}
|
||||
|
||||
if (ret == EMULATE_DO_IOCSR) {
|
||||
if (run->iocsr_io.is_write) {
|
||||
val = vcpu->arch.gprs[rd];
|
||||
memcpy(run->iocsr_io.data, &val, run->iocsr_io.len);
|
||||
}
|
||||
vcpu->arch.io_gpr = rd;
|
||||
if (run->iocsr_io.is_write) {
|
||||
if (!kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val))
|
||||
ret = EMULATE_DONE;
|
||||
else
|
||||
/* Save data and let user space to write it */
|
||||
memcpy(run->iocsr_io.data, val, run->iocsr_io.len);
|
||||
|
||||
trace_kvm_iocsr(KVM_TRACE_IOCSR_WRITE, run->iocsr_io.len, addr, val);
|
||||
} else {
|
||||
if (!kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val))
|
||||
ret = EMULATE_DONE;
|
||||
else
|
||||
/* Save register id for iocsr read completion */
|
||||
vcpu->arch.io_gpr = rd;
|
||||
|
||||
trace_kvm_iocsr(KVM_TRACE_IOCSR_READ, run->iocsr_io.len, addr, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -447,19 +457,33 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst)
|
||||
}
|
||||
|
||||
if (ret == EMULATE_DO_MMIO) {
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, run->mmio.len, run->mmio.phys_addr, NULL);
|
||||
|
||||
/*
|
||||
* If mmio device such as PCH-PIC is emulated in KVM,
|
||||
* it need not return to user space to handle the mmio
|
||||
* exception.
|
||||
*/
|
||||
ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, vcpu->arch.badv,
|
||||
run->mmio.len, &vcpu->arch.gprs[rd]);
|
||||
if (!ret) {
|
||||
update_pc(&vcpu->arch);
|
||||
vcpu->mmio_needed = 0;
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
|
||||
/* Set for kvm_complete_mmio_read() use */
|
||||
vcpu->arch.io_gpr = rd;
|
||||
run->mmio.is_write = 0;
|
||||
vcpu->mmio_is_write = 0;
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, run->mmio.len,
|
||||
run->mmio.phys_addr, NULL);
|
||||
} else {
|
||||
kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
|
||||
inst.word, vcpu->arch.pc, vcpu->arch.badv);
|
||||
kvm_arch_vcpu_dump_regs(vcpu);
|
||||
vcpu->mmio_needed = 0;
|
||||
return EMULATE_DO_MMIO;
|
||||
}
|
||||
|
||||
kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
|
||||
inst.word, vcpu->arch.pc, vcpu->arch.badv);
|
||||
kvm_arch_vcpu_dump_regs(vcpu);
|
||||
vcpu->mmio_needed = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -600,19 +624,29 @@ int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst)
|
||||
}
|
||||
|
||||
if (ret == EMULATE_DO_MMIO) {
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len, run->mmio.phys_addr, data);
|
||||
|
||||
/*
|
||||
* If mmio device such as PCH-PIC is emulated in KVM,
|
||||
* it need not return to user space to handle the mmio
|
||||
* exception.
|
||||
*/
|
||||
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, vcpu->arch.badv, run->mmio.len, data);
|
||||
if (!ret)
|
||||
return EMULATE_DONE;
|
||||
|
||||
run->mmio.is_write = 1;
|
||||
vcpu->mmio_needed = 1;
|
||||
vcpu->mmio_is_write = 1;
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len,
|
||||
run->mmio.phys_addr, data);
|
||||
} else {
|
||||
vcpu->arch.pc = curr_pc;
|
||||
kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
|
||||
inst.word, vcpu->arch.pc, vcpu->arch.badv);
|
||||
kvm_arch_vcpu_dump_regs(vcpu);
|
||||
/* Rollback PC if emulation was unsuccessful */
|
||||
return EMULATE_DO_MMIO;
|
||||
}
|
||||
|
||||
vcpu->arch.pc = curr_pc;
|
||||
kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
|
||||
inst.word, vcpu->arch.pc, vcpu->arch.badv);
|
||||
kvm_arch_vcpu_dump_regs(vcpu);
|
||||
/* Rollback PC if emulation was unsuccessful */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
1027
arch/loongarch/kvm/intc/eiointc.c
Normal file
1027
arch/loongarch/kvm/intc/eiointc.c
Normal file
File diff suppressed because it is too large
Load Diff
475
arch/loongarch/kvm/intc/ipi.c
Normal file
475
arch/loongarch/kvm/intc/ipi.c
Normal file
@ -0,0 +1,475 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_ipi.h>
|
||||
#include <asm/kvm_vcpu.h>
|
||||
|
||||
static void ipi_send(struct kvm *kvm, uint64_t data)
|
||||
{
|
||||
int cpu, action;
|
||||
uint32_t status;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_interrupt irq;
|
||||
|
||||
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
action = BIT(data & 0x1f);
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
status = vcpu->arch.ipi_state.status;
|
||||
vcpu->arch.ipi_state.status |= action;
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
if (status == 0) {
|
||||
irq.irq = LARCH_INT_IPI;
|
||||
kvm_vcpu_ioctl_interrupt(vcpu, &irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data)
|
||||
{
|
||||
uint32_t status;
|
||||
struct kvm_interrupt irq;
|
||||
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
vcpu->arch.ipi_state.status &= ~data;
|
||||
status = vcpu->arch.ipi_state.status;
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
if (status == 0) {
|
||||
irq.irq = -LARCH_INT_IPI;
|
||||
kvm_vcpu_ioctl_interrupt(vcpu, &irq);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
data = *(ulong *)((void *)vcpu->arch.ipi_state.buf + (offset - 0x20));
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return data & 0xffff;
|
||||
case 4:
|
||||
return data & 0xffffffff;
|
||||
case 8:
|
||||
return data;
|
||||
default:
|
||||
kvm_err("%s: unknown data len: %d\n", __func__, len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int len)
|
||||
{
|
||||
void *pbuf;
|
||||
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
pbuf = (void *)vcpu->arch.ipi_state.buf + (offset - 0x20);
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
*(unsigned char *)pbuf = (unsigned char)data;
|
||||
break;
|
||||
case 2:
|
||||
*(unsigned short *)pbuf = (unsigned short)data;
|
||||
break;
|
||||
case 4:
|
||||
*(unsigned int *)pbuf = (unsigned int)data;
|
||||
break;
|
||||
case 8:
|
||||
*(unsigned long *)pbuf = (unsigned long)data;
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown data len: %d\n", __func__, len);
|
||||
}
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
}
|
||||
|
||||
static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
||||
{
|
||||
int i, ret;
|
||||
uint32_t val = 0, mask = 0;
|
||||
|
||||
/*
|
||||
* Bit 27-30 is mask for byte writing.
|
||||
* If the mask is 0, we need not to do anything.
|
||||
*/
|
||||
if ((data >> 27) & 0xf) {
|
||||
/* Read the old val */
|
||||
ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
|
||||
if (unlikely(ret)) {
|
||||
kvm_err("%s: : read date from addr %llx failed\n", __func__, addr);
|
||||
return ret;
|
||||
}
|
||||
/* Construct the mask by scanning the bit 27-30 */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (data & (BIT(27 + i)))
|
||||
mask |= (0xff << (i * 8));
|
||||
}
|
||||
/* Save the old part of val */
|
||||
val &= mask;
|
||||
}
|
||||
val |= ((uint32_t)(data >> 32) & ~mask);
|
||||
ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
|
||||
if (unlikely(ret))
|
||||
kvm_err("%s: : write date to addr %llx failed\n", __func__, addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mail_send(struct kvm *kvm, uint64_t data)
|
||||
{
|
||||
int cpu, mailbox, offset;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return -EINVAL;
|
||||
}
|
||||
mailbox = ((data & 0xffffffff) >> 2) & 0x7;
|
||||
offset = IOCSR_IPI_BASE + IOCSR_IPI_BUF_20 + mailbox * 4;
|
||||
|
||||
return send_ipi_data(vcpu, offset, data);
|
||||
}
|
||||
|
||||
static int any_send(struct kvm *kvm, uint64_t data)
|
||||
{
|
||||
int cpu, offset;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return -EINVAL;
|
||||
}
|
||||
offset = data & 0xffff;
|
||||
|
||||
return send_ipi_data(vcpu, offset, data);
|
||||
}
|
||||
|
||||
static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t offset;
|
||||
uint64_t res = 0;
|
||||
|
||||
offset = (uint32_t)(addr & 0x1ff);
|
||||
WARN_ON_ONCE(offset & (len - 1));
|
||||
|
||||
switch (offset) {
|
||||
case IOCSR_IPI_STATUS:
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
res = vcpu->arch.ipi_state.status;
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
break;
|
||||
case IOCSR_IPI_EN:
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
res = vcpu->arch.ipi_state.en;
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
break;
|
||||
case IOCSR_IPI_SET:
|
||||
res = 0;
|
||||
break;
|
||||
case IOCSR_IPI_CLEAR:
|
||||
res = 0;
|
||||
break;
|
||||
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
|
||||
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
|
||||
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
|
||||
__func__, offset, len);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
res = read_mailbox(vcpu, offset, len);
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
*(uint64_t *)val = res;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t data;
|
||||
uint32_t offset;
|
||||
|
||||
data = *(uint64_t *)val;
|
||||
|
||||
offset = (uint32_t)(addr & 0x1ff);
|
||||
WARN_ON_ONCE(offset & (len - 1));
|
||||
|
||||
switch (offset) {
|
||||
case IOCSR_IPI_STATUS:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case IOCSR_IPI_EN:
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
vcpu->arch.ipi_state.en = data;
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
break;
|
||||
case IOCSR_IPI_SET:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case IOCSR_IPI_CLEAR:
|
||||
/* Just clear the status of the current vcpu */
|
||||
ipi_clear(vcpu, data);
|
||||
break;
|
||||
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
|
||||
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
|
||||
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
|
||||
__func__, offset, len);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
write_mailbox(vcpu, offset, data, len);
|
||||
break;
|
||||
case IOCSR_IPI_SEND:
|
||||
ipi_send(vcpu->kvm, data);
|
||||
break;
|
||||
case IOCSR_MAIL_SEND:
|
||||
ret = mail_send(vcpu->kvm, *(uint64_t *)val);
|
||||
break;
|
||||
case IOCSR_ANY_SEND:
|
||||
ret = any_send(vcpu->kvm, *(uint64_t *)val);
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_ipi_read(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret;
|
||||
struct loongarch_ipi *ipi;
|
||||
|
||||
ipi = vcpu->kvm->arch.ipi;
|
||||
if (!ipi) {
|
||||
kvm_err("%s: ipi irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ipi->kvm->stat.ipi_read_exits++;
|
||||
ret = loongarch_ipi_readl(vcpu, addr, len, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_ipi_write(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret;
|
||||
struct loongarch_ipi *ipi;
|
||||
|
||||
ipi = vcpu->kvm->arch.ipi;
|
||||
if (!ipi) {
|
||||
kvm_err("%s: ipi irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ipi->kvm->stat.ipi_write_exits++;
|
||||
ret = loongarch_ipi_writel(vcpu, addr, len, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct kvm_io_device_ops kvm_ipi_ops = {
|
||||
.read = kvm_ipi_read,
|
||||
.write = kvm_ipi_write,
|
||||
};
|
||||
|
||||
static int kvm_ipi_regs_access(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr,
|
||||
bool is_write)
|
||||
{
|
||||
int len = 4;
|
||||
int cpu, addr;
|
||||
uint64_t val;
|
||||
void *p = NULL;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
cpu = (attr->attr >> 16) & 0x3ff;
|
||||
addr = attr->attr & 0xff;
|
||||
|
||||
vcpu = kvm_get_vcpu(dev->kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case IOCSR_IPI_STATUS:
|
||||
p = &vcpu->arch.ipi_state.status;
|
||||
break;
|
||||
case IOCSR_IPI_EN:
|
||||
p = &vcpu->arch.ipi_state.en;
|
||||
break;
|
||||
case IOCSR_IPI_SET:
|
||||
p = &vcpu->arch.ipi_state.set;
|
||||
break;
|
||||
case IOCSR_IPI_CLEAR:
|
||||
p = &vcpu->arch.ipi_state.clear;
|
||||
break;
|
||||
case IOCSR_IPI_BUF_20:
|
||||
p = &vcpu->arch.ipi_state.buf[0];
|
||||
len = 8;
|
||||
break;
|
||||
case IOCSR_IPI_BUF_28:
|
||||
p = &vcpu->arch.ipi_state.buf[1];
|
||||
len = 8;
|
||||
break;
|
||||
case IOCSR_IPI_BUF_30:
|
||||
p = &vcpu->arch.ipi_state.buf[2];
|
||||
len = 8;
|
||||
break;
|
||||
case IOCSR_IPI_BUF_38:
|
||||
p = &vcpu->arch.ipi_state.buf[3];
|
||||
len = 8;
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown ipi register, addr = %d\n", __func__, addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_write) {
|
||||
if (len == 4) {
|
||||
if (get_user(val, (uint32_t __user *)attr->addr))
|
||||
return -EFAULT;
|
||||
*(uint32_t *)p = (uint32_t)val;
|
||||
} else if (len == 8) {
|
||||
if (get_user(val, (uint64_t __user *)attr->addr))
|
||||
return -EFAULT;
|
||||
*(uint64_t *)p = val;
|
||||
}
|
||||
} else {
|
||||
if (len == 4) {
|
||||
val = *(uint32_t *)p;
|
||||
return put_user(val, (uint32_t __user *)attr->addr);
|
||||
} else if (len == 8) {
|
||||
val = *(uint64_t *)p;
|
||||
return put_user(val, (uint64_t __user *)attr->addr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_ipi_get_attr(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
switch (attr->group) {
|
||||
case KVM_DEV_LOONGARCH_IPI_GRP_REGS:
|
||||
return kvm_ipi_regs_access(dev, attr, false);
|
||||
default:
|
||||
kvm_err("%s: unknown group (%d)\n", __func__, attr->group);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_ipi_set_attr(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
switch (attr->group) {
|
||||
case KVM_DEV_LOONGARCH_IPI_GRP_REGS:
|
||||
return kvm_ipi_regs_access(dev, attr, true);
|
||||
default:
|
||||
kvm_err("%s: unknown group (%d)\n", __func__, attr->group);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_ipi_create(struct kvm_device *dev, u32 type)
|
||||
{
|
||||
int ret;
|
||||
struct kvm *kvm;
|
||||
struct kvm_io_device *device;
|
||||
struct loongarch_ipi *s;
|
||||
|
||||
if (!dev) {
|
||||
kvm_err("%s: kvm_device ptr is invalid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kvm = dev->kvm;
|
||||
if (kvm->arch.ipi) {
|
||||
kvm_err("%s: LoongArch IPI has already been created!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = kzalloc(sizeof(struct loongarch_ipi), GFP_KERNEL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&s->lock);
|
||||
s->kvm = kvm;
|
||||
|
||||
/*
|
||||
* Initialize IOCSR device
|
||||
*/
|
||||
device = &s->device;
|
||||
kvm_iodevice_init(device, &kvm_ipi_ops);
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device);
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
if (ret < 0) {
|
||||
kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
kvm->arch.ipi = s;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(s);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static void kvm_ipi_destroy(struct kvm_device *dev)
|
||||
{
|
||||
struct kvm *kvm;
|
||||
struct loongarch_ipi *ipi;
|
||||
|
||||
if (!dev || !dev->kvm || !dev->kvm->arch.ipi)
|
||||
return;
|
||||
|
||||
kvm = dev->kvm;
|
||||
ipi = kvm->arch.ipi;
|
||||
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device);
|
||||
kfree(ipi);
|
||||
}
|
||||
|
||||
static struct kvm_device_ops kvm_ipi_dev_ops = {
|
||||
.name = "kvm-loongarch-ipi",
|
||||
.create = kvm_ipi_create,
|
||||
.destroy = kvm_ipi_destroy,
|
||||
.set_attr = kvm_ipi_set_attr,
|
||||
.get_attr = kvm_ipi_get_attr,
|
||||
};
|
||||
|
||||
int kvm_loongarch_register_ipi_device(void)
|
||||
{
|
||||
return kvm_register_device_ops(&kvm_ipi_dev_ops, KVM_DEV_TYPE_LOONGARCH_IPI);
|
||||
}
|
||||
519
arch/loongarch/kvm/intc/pch_pic.c
Normal file
519
arch/loongarch/kvm/intc/pch_pic.c
Normal file
@ -0,0 +1,519 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <asm/kvm_eiointc.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
#include <asm/kvm_vcpu.h>
|
||||
#include <linux/count_zeros.h>
|
||||
|
||||
/* update the isr according to irq level and route irq to eiointc */
|
||||
static void pch_pic_update_irq(struct loongarch_pch_pic *s, int irq, int level)
|
||||
{
|
||||
u64 mask = BIT(irq);
|
||||
|
||||
/*
|
||||
* set isr and route irq to eiointc and
|
||||
* the route table is in htmsi_vector[]
|
||||
*/
|
||||
if (level) {
|
||||
if (mask & s->irr & ~s->mask) {
|
||||
s->isr |= mask;
|
||||
irq = s->htmsi_vector[irq];
|
||||
eiointc_set_irq(s->kvm->arch.eiointc, irq, level);
|
||||
}
|
||||
} else {
|
||||
if (mask & s->isr & ~s->irr) {
|
||||
s->isr &= ~mask;
|
||||
irq = s->htmsi_vector[irq];
|
||||
eiointc_set_irq(s->kvm->arch.eiointc, irq, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* update batch irqs, the irq_mask is a bitmap of irqs */
|
||||
static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level)
|
||||
{
|
||||
int irq, bits;
|
||||
|
||||
/* find each irq by irqs bitmap and update each irq */
|
||||
bits = sizeof(irq_mask) * 8;
|
||||
irq = find_first_bit((void *)&irq_mask, bits);
|
||||
while (irq < bits) {
|
||||
pch_pic_update_irq(s, irq, level);
|
||||
bitmap_clear((void *)&irq_mask, irq, 1);
|
||||
irq = find_first_bit((void *)&irq_mask, bits);
|
||||
}
|
||||
}
|
||||
|
||||
/* called when a irq is triggered in pch pic */
|
||||
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level)
|
||||
{
|
||||
u64 mask = BIT(irq);
|
||||
|
||||
spin_lock(&s->lock);
|
||||
if (level)
|
||||
s->irr |= mask; /* set irr */
|
||||
else {
|
||||
/*
|
||||
* In edge triggered mode, 0 does not mean to clear irq
|
||||
* The irr register variable is cleared when cpu writes to the
|
||||
* PCH_PIC_CLEAR_START address area
|
||||
*/
|
||||
if (s->edge & mask) {
|
||||
spin_unlock(&s->lock);
|
||||
return;
|
||||
}
|
||||
s->irr &= ~mask;
|
||||
}
|
||||
pch_pic_update_irq(s, irq, level);
|
||||
spin_unlock(&s->lock);
|
||||
}
|
||||
|
||||
/* msi irq handler */
|
||||
void pch_msi_set_irq(struct kvm *kvm, int irq, int level)
|
||||
{
|
||||
eiointc_set_irq(kvm->arch.eiointc, irq, level);
|
||||
}
|
||||
|
||||
/*
|
||||
* pch pic register is 64-bit, but it is accessed by 32-bit,
|
||||
* so we use high to get whether low or high 32 bits we want
|
||||
* to read.
|
||||
*/
|
||||
static u32 pch_pic_read_reg(u64 *s, int high)
|
||||
{
|
||||
u64 val = *s;
|
||||
|
||||
/* read the high 32 bits when high is 1 */
|
||||
return high ? (u32)(val >> 32) : (u32)val;
|
||||
}
|
||||
|
||||
/*
|
||||
* pch pic register is 64-bit, but it is accessed by 32-bit,
|
||||
* so we use high to get whether low or high 32 bits we want
|
||||
* to write.
|
||||
*/
|
||||
static u32 pch_pic_write_reg(u64 *s, int high, u32 v)
|
||||
{
|
||||
u64 val = *s, data = v;
|
||||
|
||||
if (high) {
|
||||
/*
|
||||
* Clear val high 32 bits
|
||||
* Write the high 32 bits when the high is 1
|
||||
*/
|
||||
*s = (val << 32 >> 32) | (data << 32);
|
||||
val >>= 32;
|
||||
} else
|
||||
/*
|
||||
* Clear val low 32 bits
|
||||
* Write the low 32 bits when the high is 0
|
||||
*/
|
||||
*s = (val >> 32 << 32) | v;
|
||||
|
||||
return (u32)val;
|
||||
}
|
||||
|
||||
static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
|
||||
{
|
||||
int offset, index, ret = 0;
|
||||
u32 data = 0;
|
||||
u64 int_id = 0;
|
||||
|
||||
offset = addr - s->pch_pic_base;
|
||||
|
||||
spin_lock(&s->lock);
|
||||
switch (offset) {
|
||||
case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END:
|
||||
/* int id version */
|
||||
int_id |= (u64)PCH_PIC_INT_ID_VER << 32;
|
||||
/* irq number */
|
||||
int_id |= (u64)31 << (32 + 16);
|
||||
/* int id value */
|
||||
int_id |= PCH_PIC_INT_ID_VAL;
|
||||
*(u64 *)val = int_id;
|
||||
break;
|
||||
case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
|
||||
offset -= PCH_PIC_MASK_START;
|
||||
index = offset >> 2;
|
||||
/* read mask reg */
|
||||
data = pch_pic_read_reg(&s->mask, index);
|
||||
*(u32 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
|
||||
offset -= PCH_PIC_HTMSI_EN_START;
|
||||
index = offset >> 2;
|
||||
/* read htmsi enable reg */
|
||||
data = pch_pic_read_reg(&s->htmsi_en, index);
|
||||
*(u32 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
|
||||
offset -= PCH_PIC_EDGE_START;
|
||||
index = offset >> 2;
|
||||
/* read edge enable reg */
|
||||
data = pch_pic_read_reg(&s->edge, index);
|
||||
*(u32 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:
|
||||
case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END:
|
||||
/* we only use default mode: fixed interrupt distribution mode */
|
||||
*(u32 *)val = 0;
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
/* only route to int0: eiointc */
|
||||
*(u8 *)val = 1;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset -= PCH_PIC_HTMSI_VEC_START;
|
||||
/* read htmsi vector */
|
||||
data = s->htmsi_vector[offset];
|
||||
*(u8 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END:
|
||||
/* we only use defalut value 0: high level triggered */
|
||||
*(u32 *)val = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_read(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret;
|
||||
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
|
||||
|
||||
if (!s) {
|
||||
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* statistics of pch pic reading */
|
||||
vcpu->kvm->stat.pch_pic_read_exits++;
|
||||
ret = loongarch_pch_pic_read(s, addr, len, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr,
|
||||
int len, const void *val)
|
||||
{
|
||||
int ret;
|
||||
u32 old, data, offset, index;
|
||||
u64 irq;
|
||||
|
||||
ret = 0;
|
||||
data = *(u32 *)val;
|
||||
offset = addr - s->pch_pic_base;
|
||||
|
||||
spin_lock(&s->lock);
|
||||
switch (offset) {
|
||||
case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
|
||||
offset -= PCH_PIC_MASK_START;
|
||||
/* get whether high or low 32 bits we want to write */
|
||||
index = offset >> 2;
|
||||
old = pch_pic_write_reg(&s->mask, index, data);
|
||||
/* enable irq when mask value change to 0 */
|
||||
irq = (old & ~data) << (32 * index);
|
||||
pch_pic_update_batch_irqs(s, irq, 1);
|
||||
/* disable irq when mask value change to 1 */
|
||||
irq = (~old & data) << (32 * index);
|
||||
pch_pic_update_batch_irqs(s, irq, 0);
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
|
||||
offset -= PCH_PIC_HTMSI_EN_START;
|
||||
index = offset >> 2;
|
||||
pch_pic_write_reg(&s->htmsi_en, index, data);
|
||||
break;
|
||||
case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
|
||||
offset -= PCH_PIC_EDGE_START;
|
||||
index = offset >> 2;
|
||||
/* 1: edge triggered, 0: level triggered */
|
||||
pch_pic_write_reg(&s->edge, index, data);
|
||||
break;
|
||||
case PCH_PIC_CLEAR_START ... PCH_PIC_CLEAR_END:
|
||||
offset -= PCH_PIC_CLEAR_START;
|
||||
index = offset >> 2;
|
||||
/* write 1 to clear edge irq */
|
||||
old = pch_pic_read_reg(&s->irr, index);
|
||||
/*
|
||||
* get the irq bitmap which is edge triggered and
|
||||
* already set and to be cleared
|
||||
*/
|
||||
irq = old & pch_pic_read_reg(&s->edge, index) & data;
|
||||
/* write irr to the new state where irqs have been cleared */
|
||||
pch_pic_write_reg(&s->irr, index, old & ~irq);
|
||||
/* update cleared irqs */
|
||||
pch_pic_update_batch_irqs(s, irq, 0);
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:
|
||||
offset -= PCH_PIC_AUTO_CTRL0_START;
|
||||
index = offset >> 2;
|
||||
/* we only use default mode: fixed interrupt distribution mode */
|
||||
pch_pic_write_reg(&s->auto_ctrl0, index, 0);
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END:
|
||||
offset -= PCH_PIC_AUTO_CTRL1_START;
|
||||
index = offset >> 2;
|
||||
/* we only use default mode: fixed interrupt distribution mode */
|
||||
pch_pic_write_reg(&s->auto_ctrl1, index, 0);
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset -= PCH_PIC_ROUTE_ENTRY_START;
|
||||
/* only route to int0: eiointc */
|
||||
s->route_entry[offset] = 1;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
|
||||
/* route table to eiointc */
|
||||
offset -= PCH_PIC_HTMSI_VEC_START;
|
||||
s->htmsi_vector[offset] = (u8)data;
|
||||
break;
|
||||
case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END:
|
||||
offset -= PCH_PIC_POLARITY_START;
|
||||
index = offset >> 2;
|
||||
/* we only use defalut value 0: high level triggered */
|
||||
pch_pic_write_reg(&s->polarity, index, 0);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_write(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret;
|
||||
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
|
||||
|
||||
if (!s) {
|
||||
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* statistics of pch pic writing */
|
||||
vcpu->kvm->stat.pch_pic_write_exits++;
|
||||
ret = loongarch_pch_pic_write(s, addr, len, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct kvm_io_device_ops kvm_pch_pic_ops = {
|
||||
.read = kvm_pch_pic_read,
|
||||
.write = kvm_pch_pic_write,
|
||||
};
|
||||
|
||||
static int kvm_pch_pic_init(struct kvm_device *dev, u64 addr)
|
||||
{
|
||||
int ret;
|
||||
struct kvm *kvm = dev->kvm;
|
||||
struct kvm_io_device *device;
|
||||
struct loongarch_pch_pic *s = dev->kvm->arch.pch_pic;
|
||||
|
||||
s->pch_pic_base = addr;
|
||||
device = &s->device;
|
||||
/* init device by pch pic writing and reading ops */
|
||||
kvm_iodevice_init(device, &kvm_pch_pic_ops);
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
/* register pch pic device */
|
||||
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, PCH_PIC_SIZE, device);
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
|
||||
return (ret < 0) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/* used by user space to get or set pch pic registers */
|
||||
static int kvm_pch_pic_regs_access(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr,
|
||||
bool is_write)
|
||||
{
|
||||
int addr, offset, len = 8, ret = 0;
|
||||
void __user *data;
|
||||
void *p = NULL;
|
||||
struct loongarch_pch_pic *s;
|
||||
|
||||
s = dev->kvm->arch.pch_pic;
|
||||
addr = attr->attr;
|
||||
data = (void __user *)attr->addr;
|
||||
|
||||
/* get pointer to pch pic register by addr */
|
||||
switch (addr) {
|
||||
case PCH_PIC_MASK_START:
|
||||
p = &s->mask;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_START:
|
||||
p = &s->htmsi_en;
|
||||
break;
|
||||
case PCH_PIC_EDGE_START:
|
||||
p = &s->edge;
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_START:
|
||||
p = &s->auto_ctrl0;
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL1_START:
|
||||
p = &s->auto_ctrl1;
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset = addr - PCH_PIC_ROUTE_ENTRY_START;
|
||||
p = &s->route_entry[offset];
|
||||
len = 1;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset = addr - PCH_PIC_HTMSI_VEC_START;
|
||||
p = &s->htmsi_vector[offset];
|
||||
len = 1;
|
||||
break;
|
||||
case PCH_PIC_INT_IRR_START:
|
||||
p = &s->irr;
|
||||
break;
|
||||
case PCH_PIC_INT_ISR_START:
|
||||
p = &s->isr;
|
||||
break;
|
||||
case PCH_PIC_POLARITY_START:
|
||||
p = &s->polarity;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock(&s->lock);
|
||||
/* write or read value according to is_write */
|
||||
if (is_write) {
|
||||
if (copy_from_user(p, data, len))
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
if (copy_to_user(data, p, len))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
spin_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_get_attr(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
switch (attr->group) {
|
||||
case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS:
|
||||
return kvm_pch_pic_regs_access(dev, attr, false);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_set_attr(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
u64 addr;
|
||||
void __user *uaddr = (void __user *)(long)attr->addr;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL:
|
||||
switch (attr->attr) {
|
||||
case KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT:
|
||||
if (copy_from_user(&addr, uaddr, sizeof(addr)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!dev->kvm->arch.pch_pic) {
|
||||
kvm_err("%s: please create pch_pic irqchip first!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return kvm_pch_pic_init(dev, addr);
|
||||
default:
|
||||
kvm_err("%s: unknown group (%d) attr (%lld)\n", __func__, attr->group,
|
||||
attr->attr);
|
||||
return -EINVAL;
|
||||
}
|
||||
case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS:
|
||||
return kvm_pch_pic_regs_access(dev, attr, true);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_setup_default_irq_routing(struct kvm *kvm)
|
||||
{
|
||||
int i, ret;
|
||||
u32 nr = KVM_IRQCHIP_NUM_PINS;
|
||||
struct kvm_irq_routing_entry *entries;
|
||||
|
||||
entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL);
|
||||
if (!entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
entries[i].gsi = i;
|
||||
entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
|
||||
entries[i].u.irqchip.irqchip = 0;
|
||||
entries[i].u.irqchip.pin = i;
|
||||
}
|
||||
ret = kvm_set_irq_routing(kvm, entries, nr, 0);
|
||||
kfree(entries);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_create(struct kvm_device *dev, u32 type)
|
||||
{
|
||||
int ret;
|
||||
struct kvm *kvm = dev->kvm;
|
||||
struct loongarch_pch_pic *s;
|
||||
|
||||
/* pch pic should not has been created */
|
||||
if (kvm->arch.pch_pic)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kvm_setup_default_irq_routing(kvm);
|
||||
if (ret)
|
||||
return -ENOMEM;
|
||||
|
||||
s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&s->lock);
|
||||
s->kvm = kvm;
|
||||
kvm->arch.pch_pic = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_pch_pic_destroy(struct kvm_device *dev)
|
||||
{
|
||||
struct kvm *kvm;
|
||||
struct loongarch_pch_pic *s;
|
||||
|
||||
if (!dev || !dev->kvm || !dev->kvm->arch.pch_pic)
|
||||
return;
|
||||
|
||||
kvm = dev->kvm;
|
||||
s = kvm->arch.pch_pic;
|
||||
/* unregister pch pic device and free it's memory */
|
||||
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device);
|
||||
kfree(s);
|
||||
}
|
||||
|
||||
static struct kvm_device_ops kvm_pch_pic_dev_ops = {
|
||||
.name = "kvm-loongarch-pch-pic",
|
||||
.create = kvm_pch_pic_create,
|
||||
.destroy = kvm_pch_pic_destroy,
|
||||
.set_attr = kvm_pch_pic_set_attr,
|
||||
.get_attr = kvm_pch_pic_get_attr,
|
||||
};
|
||||
|
||||
int kvm_loongarch_register_pch_pic_device(void)
|
||||
{
|
||||
return kvm_register_device_ops(&kvm_pch_pic_dev_ops, KVM_DEV_TYPE_LOONGARCH_PCHPIC);
|
||||
}
|
||||
89
arch/loongarch/kvm/irqfd.c
Normal file
89
arch/loongarch/kvm/irqfd.c
Normal file
@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <trace/events/kvm.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
|
||||
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
||||
{
|
||||
/* PCH-PIC pin (0 ~ 64) <---> GSI (0 ~ 64) */
|
||||
pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* kvm_set_msi: inject the MSI corresponding to the
|
||||
* MSI routing entry
|
||||
*
|
||||
* This is the entry point for irqfd MSI injection
|
||||
* and userspace MSI injection.
|
||||
*/
|
||||
int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
||||
{
|
||||
if (!level)
|
||||
return -1;
|
||||
|
||||
pch_msi_set_irq(kvm, e->msi.data, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* kvm_set_routing_entry: populate a kvm routing entry
|
||||
* from a user routing entry
|
||||
*
|
||||
* @kvm: the VM this entry is applied to
|
||||
* @e: kvm kernel routing entry handle
|
||||
* @ue: user api routing entry handle
|
||||
* return 0 on success, -EINVAL on errors.
|
||||
*/
|
||||
int kvm_set_routing_entry(struct kvm *kvm,
|
||||
struct kvm_kernel_irq_routing_entry *e,
|
||||
const struct kvm_irq_routing_entry *ue)
|
||||
{
|
||||
switch (ue->type) {
|
||||
case KVM_IRQ_ROUTING_IRQCHIP:
|
||||
e->set = kvm_set_pic_irq;
|
||||
e->irqchip.irqchip = ue->u.irqchip.irqchip;
|
||||
e->irqchip.pin = ue->u.irqchip.pin;
|
||||
|
||||
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
case KVM_IRQ_ROUTING_MSI:
|
||||
e->set = kvm_set_msi;
|
||||
e->msi.address_lo = ue->u.msi.address_lo;
|
||||
e->msi.address_hi = ue->u.msi.address_hi;
|
||||
e->msi.data = ue->u.msi.data;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
||||
{
|
||||
switch (e->type) {
|
||||
case KVM_IRQ_ROUTING_IRQCHIP:
|
||||
pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level);
|
||||
return 0;
|
||||
case KVM_IRQ_ROUTING_MSI:
|
||||
pch_msi_set_irq(kvm, e->msi.data, level);
|
||||
return 0;
|
||||
default:
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
bool kvm_arch_intc_initialized(struct kvm *kvm)
|
||||
{
|
||||
return kvm_arch_irqchip_in_kernel(kvm);
|
||||
}
|
||||
@ -9,6 +9,8 @@
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/kvm_csr.h>
|
||||
#include <asm/kvm_eiointc.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
#include "trace.h"
|
||||
|
||||
unsigned long vpid_mask;
|
||||
@ -313,7 +315,7 @@ void kvm_arch_disable_virtualization_cpu(void)
|
||||
|
||||
static int kvm_loongarch_env_init(void)
|
||||
{
|
||||
int cpu, order;
|
||||
int cpu, order, ret;
|
||||
void *addr;
|
||||
struct kvm_context *context;
|
||||
|
||||
@ -368,7 +370,20 @@ static int kvm_loongarch_env_init(void)
|
||||
|
||||
kvm_init_gcsr_flag();
|
||||
|
||||
return 0;
|
||||
/* Register LoongArch IPI interrupt controller interface. */
|
||||
ret = kvm_loongarch_register_ipi_device();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Register LoongArch EIOINTC interrupt controller interface. */
|
||||
ret = kvm_loongarch_register_eiointc_device();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Register LoongArch PCH-PIC interrupt controller interface. */
|
||||
ret = kvm_loongarch_register_pch_pic_device();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvm_loongarch_env_exit(void)
|
||||
|
||||
@ -1475,6 +1475,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
/* Init */
|
||||
vcpu->arch.last_sched_cpu = -1;
|
||||
|
||||
/* Init ipi_state lock */
|
||||
spin_lock_init(&vcpu->arch.ipi_state.lock);
|
||||
|
||||
/*
|
||||
* Initialize guest register state to valid architectural reset state.
|
||||
*/
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_vcpu.h>
|
||||
#include <asm/kvm_eiointc.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
@ -76,6 +78,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
int r;
|
||||
|
||||
switch (ext) {
|
||||
case KVM_CAP_IRQCHIP:
|
||||
case KVM_CAP_ONE_REG:
|
||||
case KVM_CAP_ENABLE_CAP:
|
||||
case KVM_CAP_READONLY_MEM:
|
||||
@ -161,6 +164,8 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||
struct kvm_device_attr attr;
|
||||
|
||||
switch (ioctl) {
|
||||
case KVM_CREATE_IRQCHIP:
|
||||
return 0;
|
||||
case KVM_HAS_DEVICE_ATTR:
|
||||
if (copy_from_user(&attr, argp, sizeof(attr)))
|
||||
return -EFAULT;
|
||||
@ -170,3 +175,19 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, bool line_status)
|
||||
{
|
||||
if (!kvm_arch_irqchip_in_kernel(kvm))
|
||||
return -ENXIO;
|
||||
|
||||
irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
|
||||
irq_event->irq, irq_event->level, line_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
|
||||
{
|
||||
return (kvm->arch.ipi && kvm->arch.eiointc && kvm->arch.pch_pic);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#ifndef __ASM_MMAN_H__
|
||||
#define __ASM_MMAN_H__
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <uapi/asm/mman.h>
|
||||
|
||||
/* PARISC cannot allow mdwe as it needs writable stacks */
|
||||
@ -11,7 +12,7 @@ static inline bool arch_memory_deny_write_exec_supported(void)
|
||||
}
|
||||
#define arch_memory_deny_write_exec_supported arch_memory_deny_write_exec_supported
|
||||
|
||||
static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
|
||||
static inline unsigned long arch_calc_vm_flag_bits(struct file *file, unsigned long flags)
|
||||
{
|
||||
/*
|
||||
* The stack on parisc grows upwards, so if userspace requests memory
|
||||
@ -23,6 +24,6 @@ static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags)
|
||||
#define arch_calc_vm_flag_bits(file, flags) arch_calc_vm_flag_bits(file, flags)
|
||||
|
||||
#endif /* __ASM_MMAN_H__ */
|
||||
|
||||
@ -4898,6 +4898,18 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
|
||||
BOOK3S_INTERRUPT_EXTERNAL, 0);
|
||||
else
|
||||
lpcr |= LPCR_MER;
|
||||
} else {
|
||||
/*
|
||||
* L1's copy of L2's LPCR (vcpu->arch.vcore->lpcr) can get its MER bit
|
||||
* unexpectedly set - for e.g. during NMI handling when all register
|
||||
* states are synchronized from L0 to L1. L1 needs to inform L0 about
|
||||
* MER=1 only when there are pending external interrupts.
|
||||
* In the above if check, MER bit is set if there are pending
|
||||
* external interrupts. Hence, explicity mask off MER bit
|
||||
* here as otherwise it may generate spurious interrupts in L2 KVM
|
||||
* causing an endless loop, which results in L2 guest getting hung.
|
||||
*/
|
||||
lpcr &= ~LPCR_MER;
|
||||
}
|
||||
} else if (vcpu->arch.pending_exceptions ||
|
||||
vcpu->arch.doorbell_request ||
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
compatible = "snps,dw-apb-gpio-port";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
snps,nr-gpios = <32>;
|
||||
ngpios = <32>;
|
||||
reg = <0>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
@ -134,7 +134,7 @@
|
||||
compatible = "snps,dw-apb-gpio-port";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
snps,nr-gpios = <32>;
|
||||
ngpios = <32>;
|
||||
reg = <0>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
@ -156,7 +156,7 @@
|
||||
compatible = "snps,dw-apb-gpio-port";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
snps,nr-gpios = <32>;
|
||||
ngpios = <32>;
|
||||
reg = <0>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
|
||||
@ -128,7 +128,6 @@
|
||||
assigned-clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>,
|
||||
<&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>;
|
||||
assigned-clock-rates = <49500000>, <198000000>;
|
||||
status = "okay";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
@ -151,7 +150,6 @@
|
||||
&csi2rx {
|
||||
assigned-clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>;
|
||||
assigned-clock-rates = <297000000>;
|
||||
status = "okay";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
|
||||
@ -44,8 +44,7 @@
|
||||
};
|
||||
|
||||
&phy0 {
|
||||
rx-internal-delay-ps = <1900>;
|
||||
tx-internal-delay-ps = <1500>;
|
||||
rx-internal-delay-ps = <1500>;
|
||||
motorcomm,rx-clk-drv-microamp = <2910>;
|
||||
motorcomm,rx-data-drv-microamp = <2910>;
|
||||
motorcomm,tx-clk-adj-enabled;
|
||||
|
||||
@ -305,9 +305,4 @@ static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled
|
||||
extern void arch_scale_freq_tick(void);
|
||||
#define arch_scale_freq_tick arch_scale_freq_tick
|
||||
|
||||
#ifdef CONFIG_ACPI_CPPC_LIB
|
||||
void init_freq_invariance_cppc(void);
|
||||
#define arch_init_invariance_cppc init_freq_invariance_cppc
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_TOPOLOGY_H */
|
||||
|
||||
@ -110,7 +110,7 @@ static void amd_set_max_freq_ratio(void)
|
||||
|
||||
static DEFINE_MUTEX(freq_invariance_lock);
|
||||
|
||||
void init_freq_invariance_cppc(void)
|
||||
static inline void init_freq_invariance_cppc(void)
|
||||
{
|
||||
static bool init_done;
|
||||
|
||||
@ -127,6 +127,11 @@ void init_freq_invariance_cppc(void)
|
||||
mutex_unlock(&freq_invariance_lock);
|
||||
}
|
||||
|
||||
void acpi_processor_init_invariance_cppc(void)
|
||||
{
|
||||
init_freq_invariance_cppc();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the highest performance register value.
|
||||
* @cpu: CPU from which to get highest performance.
|
||||
|
||||
@ -671,10 +671,6 @@ static int pcc_data_alloc(int pcc_ss_id)
|
||||
* )
|
||||
*/
|
||||
|
||||
#ifndef arch_init_invariance_cppc
|
||||
static inline void arch_init_invariance_cppc(void) { }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* acpi_cppc_processor_probe - Search for per CPU _CPC objects.
|
||||
* @pr: Ptr to acpi_processor containing this CPU's logical ID.
|
||||
@ -905,8 +901,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
arch_init_invariance_cppc();
|
||||
|
||||
kfree(output.pointer);
|
||||
return 0;
|
||||
|
||||
|
||||
@ -237,6 +237,9 @@ static struct notifier_block acpi_processor_notifier_block = {
|
||||
.notifier_call = acpi_processor_notifier,
|
||||
};
|
||||
|
||||
void __weak acpi_processor_init_invariance_cppc(void)
|
||||
{ }
|
||||
|
||||
/*
|
||||
* We keep the driver loaded even when ACPI is not running.
|
||||
* This is needed for the powernow-k8 driver, that works even without
|
||||
@ -270,6 +273,12 @@ static int __init acpi_processor_driver_init(void)
|
||||
NULL, acpi_soft_cpu_dead);
|
||||
|
||||
acpi_processor_throttling_init();
|
||||
|
||||
/*
|
||||
* Frequency invariance calculations on AMD platforms can't be run until
|
||||
* after acpi_cppc_processor_probe() has been called for all online CPUs
|
||||
*/
|
||||
acpi_processor_init_invariance_cppc();
|
||||
return 0;
|
||||
err:
|
||||
driver_unregister(&acpi_processor_driver);
|
||||
|
||||
@ -366,7 +366,7 @@ void __weak freq_inv_set_max_ratio(int cpu, u64 max_rate)
|
||||
#ifdef CONFIG_ACPI_CPPC_LIB
|
||||
#include <acpi/cppc_acpi.h>
|
||||
|
||||
void topology_init_cpu_capacity_cppc(void)
|
||||
static inline void topology_init_cpu_capacity_cppc(void)
|
||||
{
|
||||
u64 capacity, capacity_scale = 0;
|
||||
struct cppc_perf_caps perf_caps;
|
||||
@ -417,6 +417,10 @@ void topology_init_cpu_capacity_cppc(void)
|
||||
exit:
|
||||
free_raw_capacity();
|
||||
}
|
||||
void acpi_processor_init_invariance_cppc(void)
|
||||
{
|
||||
topology_init_cpu_capacity_cppc();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
||||
@ -525,10 +525,6 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
|
||||
{
|
||||
struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
|
||||
|
||||
/* Give back zero bytes, as TPM chip has not yet fully resumed: */
|
||||
if (chip->flags & TPM_CHIP_FLAG_SUSPENDED)
|
||||
return 0;
|
||||
|
||||
return tpm_get_random(chip, data, max);
|
||||
}
|
||||
|
||||
|
||||
@ -370,6 +370,13 @@ int tpm_pm_suspend(struct device *dev)
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
|
||||
rc = tpm_try_get_ops(chip);
|
||||
if (rc) {
|
||||
/* Can be safely set out of locks, as no action cannot race: */
|
||||
chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
|
||||
goto suspended;
|
||||
|
||||
@ -377,21 +384,19 @@ int tpm_pm_suspend(struct device *dev)
|
||||
!pm_suspend_via_firmware())
|
||||
goto suspended;
|
||||
|
||||
rc = tpm_try_get_ops(chip);
|
||||
if (!rc) {
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
tpm2_end_auth_session(chip);
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
} else {
|
||||
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
|
||||
}
|
||||
|
||||
tpm_put_ops(chip);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
tpm2_end_auth_session(chip);
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
goto suspended;
|
||||
}
|
||||
|
||||
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
|
||||
|
||||
suspended:
|
||||
chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
|
||||
tpm_put_ops(chip);
|
||||
|
||||
out:
|
||||
if (rc)
|
||||
dev_err(dev, "Ignoring error %d while suspending\n", rc);
|
||||
return 0;
|
||||
@ -440,11 +445,18 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
|
||||
/* Give back zero bytes, as TPM chip has not yet fully resumed: */
|
||||
if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
rc = tpm2_get_random(chip, out, max);
|
||||
else
|
||||
rc = tpm1_get_random(chip, out, max);
|
||||
|
||||
out:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
|
||||
#define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL])
|
||||
# define PLL_POST_DIV_SHIFT 8
|
||||
# define PLL_POST_DIV_MASK(p) GENMASK((p)->width - 1, 0)
|
||||
# define PLL_POST_DIV_MASK(p) GENMASK((p)->width ? (p)->width - 1 : 3, 0)
|
||||
# define PLL_ALPHA_MSB BIT(15)
|
||||
# define PLL_ALPHA_EN BIT(24)
|
||||
# define PLL_ALPHA_MODE BIT(25)
|
||||
|
||||
@ -3123,7 +3123,7 @@ static struct clk_branch gcc_pcie_3_pipe_clk = {
|
||||
|
||||
static struct clk_branch gcc_pcie_3_pipediv2_clk = {
|
||||
.halt_reg = 0x58060,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.halt_check = BRANCH_HALT_SKIP,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52020,
|
||||
.enable_mask = BIT(5),
|
||||
@ -3248,7 +3248,7 @@ static struct clk_branch gcc_pcie_4_pipe_clk = {
|
||||
|
||||
static struct clk_branch gcc_pcie_4_pipediv2_clk = {
|
||||
.halt_reg = 0x6b054,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.halt_check = BRANCH_HALT_SKIP,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52010,
|
||||
.enable_mask = BIT(27),
|
||||
@ -3373,7 +3373,7 @@ static struct clk_branch gcc_pcie_5_pipe_clk = {
|
||||
|
||||
static struct clk_branch gcc_pcie_5_pipediv2_clk = {
|
||||
.halt_reg = 0x2f054,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.halt_check = BRANCH_HALT_SKIP,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52018,
|
||||
.enable_mask = BIT(19),
|
||||
@ -3511,7 +3511,7 @@ static struct clk_branch gcc_pcie_6a_pipe_clk = {
|
||||
|
||||
static struct clk_branch gcc_pcie_6a_pipediv2_clk = {
|
||||
.halt_reg = 0x31060,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.halt_check = BRANCH_HALT_SKIP,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52018,
|
||||
.enable_mask = BIT(28),
|
||||
@ -3649,7 +3649,7 @@ static struct clk_branch gcc_pcie_6b_pipe_clk = {
|
||||
|
||||
static struct clk_branch gcc_pcie_6b_pipediv2_clk = {
|
||||
.halt_reg = 0x8d060,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.halt_check = BRANCH_HALT_SKIP,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52010,
|
||||
.enable_mask = BIT(28),
|
||||
@ -6155,7 +6155,7 @@ static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = {
|
||||
.pd = {
|
||||
.name = "gcc_usb3_mp_ss1_phy_gdsc",
|
||||
},
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.pwrsts = PWRSTS_RET_ON,
|
||||
.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
|
||||
};
|
||||
|
||||
|
||||
@ -452,7 +452,7 @@ static struct gdsc mvs0_gdsc = {
|
||||
.pd = {
|
||||
.name = "mvs0_gdsc",
|
||||
},
|
||||
.flags = HW_CTRL | RETAIN_FF_ENABLE,
|
||||
.flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
};
|
||||
|
||||
@ -461,7 +461,7 @@ static struct gdsc mvs1_gdsc = {
|
||||
.pd = {
|
||||
.name = "mvs1_gdsc",
|
||||
},
|
||||
.flags = HW_CTRL | RETAIN_FF_ENABLE,
|
||||
.flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
};
|
||||
|
||||
|
||||
@ -1034,7 +1034,7 @@ static void __hybrid_init_cpu_capacity_scaling(void)
|
||||
hybrid_update_cpu_capacity_scaling();
|
||||
}
|
||||
|
||||
static void hybrid_init_cpu_capacity_scaling(void)
|
||||
static void hybrid_init_cpu_capacity_scaling(bool refresh)
|
||||
{
|
||||
bool disable_itmt = false;
|
||||
|
||||
@ -1045,7 +1045,7 @@ static void hybrid_init_cpu_capacity_scaling(void)
|
||||
* scaling has been enabled already and the driver is just changing the
|
||||
* operation mode.
|
||||
*/
|
||||
if (hybrid_max_perf_cpu) {
|
||||
if (refresh) {
|
||||
__hybrid_init_cpu_capacity_scaling();
|
||||
goto unlock;
|
||||
}
|
||||
@ -1071,6 +1071,18 @@ unlock:
|
||||
sched_clear_itmt_support();
|
||||
}
|
||||
|
||||
static bool hybrid_clear_max_perf_cpu(void)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
guard(mutex)(&hybrid_capacity_lock);
|
||||
|
||||
ret = !!hybrid_max_perf_cpu;
|
||||
hybrid_max_perf_cpu = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
|
||||
{
|
||||
u64 cap;
|
||||
@ -2263,6 +2275,11 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
|
||||
} else {
|
||||
cpu->pstate.scaling = perf_ctl_scaling;
|
||||
}
|
||||
/*
|
||||
* If the CPU is going online for the first time and it was
|
||||
* offline initially, asym capacity scaling needs to be updated.
|
||||
*/
|
||||
hybrid_update_capacity(cpu);
|
||||
} else {
|
||||
cpu->pstate.scaling = perf_ctl_scaling;
|
||||
cpu->pstate.max_pstate = pstate_funcs.get_max(cpu->cpu);
|
||||
@ -3352,6 +3369,7 @@ static void intel_pstate_driver_cleanup(void)
|
||||
|
||||
static int intel_pstate_register_driver(struct cpufreq_driver *driver)
|
||||
{
|
||||
bool refresh_cpu_cap_scaling;
|
||||
int ret;
|
||||
|
||||
if (driver == &intel_pstate)
|
||||
@ -3364,6 +3382,8 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
|
||||
|
||||
arch_set_max_freq_ratio(global.turbo_disabled);
|
||||
|
||||
refresh_cpu_cap_scaling = hybrid_clear_max_perf_cpu();
|
||||
|
||||
intel_pstate_driver = driver;
|
||||
ret = cpufreq_register_driver(intel_pstate_driver);
|
||||
if (ret) {
|
||||
@ -3373,7 +3393,7 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
|
||||
|
||||
global.min_perf_pct = min_perf_pct_min();
|
||||
|
||||
hybrid_init_cpu_capacity_scaling();
|
||||
hybrid_init_cpu_capacity_scaling(refresh_cpu_cap_scaling);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -342,9 +342,11 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
|
||||
int ecc_irq;
|
||||
int rc;
|
||||
|
||||
rc = qcom_llcc_core_setup(llcc_driv_data, llcc_driv_data->bcast_regmap);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (!llcc_driv_data->ecc_irq_configured) {
|
||||
rc = qcom_llcc_core_setup(llcc_driv_data, llcc_driv_data->bcast_regmap);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate edac control info */
|
||||
edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank",
|
||||
|
||||
@ -325,7 +325,10 @@ EXPORT_SYMBOL_GPL(scmi_driver_unregister);
|
||||
|
||||
static void scmi_device_release(struct device *dev)
|
||||
{
|
||||
kfree(to_scmi_dev(dev));
|
||||
struct scmi_device *scmi_dev = to_scmi_dev(dev);
|
||||
|
||||
kfree_const(scmi_dev->name);
|
||||
kfree(scmi_dev);
|
||||
}
|
||||
|
||||
static void __scmi_device_destroy(struct scmi_device *scmi_dev)
|
||||
@ -338,7 +341,6 @@ static void __scmi_device_destroy(struct scmi_device *scmi_dev)
|
||||
if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM)
|
||||
atomic_set(&scmi_syspower_registered, 0);
|
||||
|
||||
kfree_const(scmi_dev->name);
|
||||
ida_free(&scmi_bus_id, scmi_dev->id);
|
||||
device_unregister(&scmi_dev->dev);
|
||||
}
|
||||
@ -410,7 +412,6 @@ __scmi_device_create(struct device_node *np, struct device *parent,
|
||||
|
||||
return scmi_dev;
|
||||
put_dev:
|
||||
kfree_const(scmi_dev->name);
|
||||
put_device(&scmi_dev->dev);
|
||||
ida_free(&scmi_bus_id, id);
|
||||
return NULL;
|
||||
|
||||
@ -163,6 +163,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
|
||||
* used to initialize this channel
|
||||
* @dev: Reference to device in the SCMI hierarchy corresponding to this
|
||||
* channel
|
||||
* @is_p2a: A flag to identify a channel as P2A (RX)
|
||||
* @rx_timeout_ms: The configured RX timeout in milliseconds.
|
||||
* @handle: Pointer to SCMI entity handle
|
||||
* @no_completion_irq: Flag to indicate that this channel has no completion
|
||||
@ -174,6 +175,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
|
||||
struct scmi_chan_info {
|
||||
int id;
|
||||
struct device *dev;
|
||||
bool is_p2a;
|
||||
unsigned int rx_timeout_ms;
|
||||
struct scmi_handle *handle;
|
||||
bool no_completion_irq;
|
||||
|
||||
@ -1048,6 +1048,11 @@ static inline void scmi_xfer_command_release(struct scmi_info *info,
|
||||
static inline void scmi_clear_channel(struct scmi_info *info,
|
||||
struct scmi_chan_info *cinfo)
|
||||
{
|
||||
if (!cinfo->is_p2a) {
|
||||
dev_warn(cinfo->dev, "Invalid clear on A2P channel !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->desc->ops->clear_channel)
|
||||
info->desc->ops->clear_channel(cinfo);
|
||||
}
|
||||
@ -2638,6 +2643,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
|
||||
if (!cinfo)
|
||||
return -ENOMEM;
|
||||
|
||||
cinfo->is_p2a = !tx;
|
||||
cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms;
|
||||
|
||||
/* Create a unique name for this transport device */
|
||||
@ -3042,10 +3048,10 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev)
|
||||
|
||||
dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier));
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "max-rx-timeout-ms",
|
||||
ret = of_property_read_u32(dev->of_node, "arm,max-rx-timeout-ms",
|
||||
&trans->desc->max_rx_timeout_ms);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_err(dev, "Malformed max-rx-timeout-ms DT property.\n");
|
||||
dev_err(dev, "Malformed arm,max-rx-timeout-ms DT property.\n");
|
||||
|
||||
dev_info(dev, "SCMI max-rx-timeout: %dms\n",
|
||||
trans->desc->max_rx_timeout_ms);
|
||||
|
||||
@ -76,14 +76,11 @@
|
||||
#define AUTO_UPDATE_INFO_SIZE SZ_1M
|
||||
#define AUTO_UPDATE_BITSTREAM_BASE (AUTO_UPDATE_DIRECTORY_SIZE + AUTO_UPDATE_INFO_SIZE)
|
||||
|
||||
#define AUTO_UPDATE_TIMEOUT_MS 60000
|
||||
|
||||
struct mpfs_auto_update_priv {
|
||||
struct mpfs_sys_controller *sys_controller;
|
||||
struct device *dev;
|
||||
struct mtd_info *flash;
|
||||
struct fw_upload *fw_uploader;
|
||||
struct completion programming_complete;
|
||||
size_t size_per_bitstream;
|
||||
bool cancel_request;
|
||||
};
|
||||
@ -156,19 +153,6 @@ static void mpfs_auto_update_cancel(struct fw_upload *fw_uploader)
|
||||
|
||||
static enum fw_upload_err mpfs_auto_update_poll_complete(struct fw_upload *fw_uploader)
|
||||
{
|
||||
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* There is no meaningful way to get the status of the programming while
|
||||
* it is in progress, so attempting anything other than waiting for it
|
||||
* to complete would be misplaced.
|
||||
*/
|
||||
ret = wait_for_completion_timeout(&priv->programming_complete,
|
||||
msecs_to_jiffies(AUTO_UPDATE_TIMEOUT_MS));
|
||||
if (!ret)
|
||||
return FW_UPLOAD_ERR_TIMEOUT;
|
||||
|
||||
return FW_UPLOAD_ERR_NONE;
|
||||
}
|
||||
|
||||
@ -349,33 +333,23 @@ static enum fw_upload_err mpfs_auto_update_write(struct fw_upload *fw_uploader,
|
||||
u32 offset, u32 size, u32 *written)
|
||||
{
|
||||
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||
enum fw_upload_err err = FW_UPLOAD_ERR_NONE;
|
||||
int ret;
|
||||
|
||||
reinit_completion(&priv->programming_complete);
|
||||
|
||||
ret = mpfs_auto_update_write_bitstream(fw_uploader, data, offset, size, written);
|
||||
if (ret) {
|
||||
err = FW_UPLOAD_ERR_RW_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if (ret)
|
||||
return FW_UPLOAD_ERR_RW_ERROR;
|
||||
|
||||
if (priv->cancel_request) {
|
||||
err = FW_UPLOAD_ERR_CANCELED;
|
||||
goto out;
|
||||
}
|
||||
if (priv->cancel_request)
|
||||
return FW_UPLOAD_ERR_CANCELED;
|
||||
|
||||
if (mpfs_auto_update_is_bitstream_info(data, size))
|
||||
goto out;
|
||||
return FW_UPLOAD_ERR_NONE;
|
||||
|
||||
ret = mpfs_auto_update_verify_image(fw_uploader);
|
||||
if (ret)
|
||||
err = FW_UPLOAD_ERR_FW_INVALID;
|
||||
return FW_UPLOAD_ERR_FW_INVALID;
|
||||
|
||||
out:
|
||||
complete(&priv->programming_complete);
|
||||
|
||||
return err;
|
||||
return FW_UPLOAD_ERR_NONE;
|
||||
}
|
||||
|
||||
static const struct fw_upload_ops mpfs_auto_update_ops = {
|
||||
@ -461,8 +435,6 @@ static int mpfs_auto_update_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(dev, ret,
|
||||
"The current bitstream does not support auto-update\n");
|
||||
|
||||
init_completion(&priv->programming_complete);
|
||||
|
||||
fw_uploader = firmware_upload_register(THIS_MODULE, dev, "mpfs-auto-update",
|
||||
&mpfs_auto_update_ops, priv);
|
||||
if (IS_ERR(fw_uploader))
|
||||
|
||||
@ -112,6 +112,7 @@ enum qcom_scm_qseecom_tz_cmd_info {
|
||||
};
|
||||
|
||||
#define QSEECOM_MAX_APP_NAME_SIZE 64
|
||||
#define SHMBRIDGE_RESULT_NOTSUPP 4
|
||||
|
||||
/* Each bit configures cold/warm boot address for one of the 4 CPUs */
|
||||
static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
|
||||
@ -216,7 +217,7 @@ static DEFINE_SPINLOCK(scm_query_lock);
|
||||
|
||||
struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void)
|
||||
{
|
||||
return __scm->mempool;
|
||||
return __scm ? __scm->mempool : NULL;
|
||||
}
|
||||
|
||||
static enum qcom_scm_convention __get_convention(void)
|
||||
@ -545,7 +546,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
|
||||
} else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT,
|
||||
QCOM_SCM_BOOT_SET_DLOAD_MODE)) {
|
||||
ret = __qcom_scm_set_dload_mode(__scm->dev, !!dload_mode);
|
||||
} else {
|
||||
} else if (dload_mode) {
|
||||
dev_err(__scm->dev,
|
||||
"No available mechanism for setting download mode\n");
|
||||
}
|
||||
@ -1361,6 +1362,8 @@ EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh_available);
|
||||
|
||||
int qcom_scm_shm_bridge_enable(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_MP,
|
||||
.cmd = QCOM_SCM_MP_SHM_BRIDGE_ENABLE,
|
||||
@ -1373,7 +1376,15 @@ int qcom_scm_shm_bridge_enable(void)
|
||||
QCOM_SCM_MP_SHM_BRIDGE_ENABLE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return qcom_scm_call(__scm->dev, &desc, &res) ?: res.result[0];
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (res.result[0] == SHMBRIDGE_RESULT_NOTSUPP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return res.result[0];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_shm_bridge_enable);
|
||||
|
||||
|
||||
@ -16,7 +16,6 @@ static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
|
||||
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
|
||||
|
||||
bool __ro_after_init smccc_trng_available = false;
|
||||
u64 __ro_after_init smccc_has_sve_hint = false;
|
||||
s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED;
|
||||
s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;
|
||||
|
||||
@ -28,9 +27,6 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
|
||||
smccc_conduit = conduit;
|
||||
|
||||
smccc_trng_available = smccc_probe_trng();
|
||||
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
|
||||
smccc_version >= ARM_SMCCC_VERSION_1_3)
|
||||
smccc_has_sve_hint = true;
|
||||
|
||||
if ((smccc_version >= ARM_SMCCC_VERSION_1_2) &&
|
||||
(smccc_conduit != SMCCC_CONDUIT_NONE)) {
|
||||
|
||||
@ -172,8 +172,8 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
|
||||
&buffer);
|
||||
obj = (union acpi_object *)buffer.pointer;
|
||||
|
||||
/* Fail if calling the method fails and ATIF is supported */
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
/* Fail if calling the method fails */
|
||||
if (ACPI_FAILURE(status)) {
|
||||
DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
|
||||
acpi_format_exception(status));
|
||||
kfree(obj);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user