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:
Paolo Bonzini 2024-11-14 07:06:24 -05:00
commit 0586ade9e7
338 changed files with 4779 additions and 1361 deletions

View File

@ -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>

View File

@ -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)

View File

@ -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.

View File

@ -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``.

View File

@ -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
===========================

View File

@ -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

View File

@ -61,7 +61,7 @@ properties:
- gmii
- rgmii
- sgmii
- 1000BaseX
- 1000base-x
xlnx,phy-type:
description:

View File

@ -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:

View File

@ -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.

View File

@ -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最多可个路由到
个虚拟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模型
===============

View File

@ -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>

View File

@ -2,7 +2,7 @@
VERSION = 6
PATCHLEVEL = 12
SUBLEVEL = 0
EXTRAVERSION = -rc6
EXTRAVERSION = -rc7
NAME = Baby Opossum Posse
# *DOCUMENTATION*

View File

@ -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";

View File

@ -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";

View File

@ -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

View File

@ -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>;
};

View File

@ -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";

View File

@ -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";
};

View File

@ -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>;
};

View File

@ -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";

View File

@ -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>;
};

View File

@ -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>;

View File

@ -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 {

View File

@ -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>,

View File

@ -139,6 +139,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
regulator-boot-on;
};
vph_pwr: regulator-vph-pwr {

View File

@ -134,6 +134,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
regulator-boot-on;
};
};

View File

@ -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>;

View File

@ -205,6 +205,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
regulator-boot-on;
};
};

View File

@ -164,6 +164,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
regulator-boot-on;
};
};

View File

@ -253,6 +253,8 @@
pinctrl-names = "default";
pinctrl-0 = <&nvme_reg_en>;
regulator-boot-on;
};
};

View File

@ -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>;
};

View File

@ -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>;

View File

@ -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>;
};

View File

@ -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";
};

View File

@ -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>;

View File

@ -61,7 +61,6 @@
fan: fan@18 {
compatible = "ti,amc6821";
reg = <0x18>;
#cooling-cells = <2>;
};
rtc_twi: rtc@6f {

View File

@ -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";

View File

@ -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 {

View File

@ -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>;
};

View File

@ -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>;

View File

@ -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";

View File

@ -92,7 +92,7 @@
};
&i2c2 {
pintctrl-names = "default";
pinctrl-names = "default";
pinctrl-0 = <&i2c2m1_xfer>;
status = "okay";

View File

@ -79,7 +79,7 @@
};
&i2c2 {
pintctrl-names = "default";
pinctrl-names = "default";
pinctrl-0 = <&i2c2m1_xfer>;
status = "okay";

View File

@ -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>;

View File

@ -507,7 +507,6 @@
non-removable;
pinctrl-names = "default";
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
supports-emmc;
status = "okay";
};

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -589,7 +589,6 @@
non-removable;
pinctrl-names = "default";
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
supports-emmc;
status = "okay";
};

View File

@ -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>;

View File

@ -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 {

View File

@ -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>;

View File

@ -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>;

View File

@ -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>;
};

View File

@ -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 {

View File

@ -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>;

View File

@ -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>;

View File

@ -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)

View File

@ -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

View File

@ -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);
}
}

View File

@ -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
/*

View File

@ -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 */

View 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 */

View File

@ -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];

View 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

View 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 */

View File

@ -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 */

View File

@ -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

View File

@ -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,)

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View 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);
}

View 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);
}

View 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);
}

View File

@ -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)

View File

@ -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.
*/

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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 ||

View File

@ -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>;

View File

@ -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>;

View File

@ -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;

View File

@ -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 */

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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;
}

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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))

View File

@ -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);

View File

@ -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)) {

View File

@ -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