Compare commits
No commits in common. "master" and "v7.1-rc5" have entirely different histories.
6
.mailmap
6
.mailmap
|
|
@ -263,9 +263,8 @@ Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
|
|||
Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com>
|
||||
Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
|
||||
Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@microchip.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@linaro.org>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@collabora.com>
|
||||
Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@microchip.com>
|
||||
Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@collabora.com>
|
||||
Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||
Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> <ezequiel@collabora.com>
|
||||
Faith Ekstrand <faith.ekstrand@collabora.com> <jason@jlekstrand.net>
|
||||
|
|
@ -340,7 +339,6 @@ Henrik Rydberg <rydberg@bitmath.org>
|
|||
Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||
Ian Ray <ian.ray@gehealthcare.com> <ian.ray@ge.com>
|
||||
Ignat Korchagin <ignat@linux.win> <ignat@cloudflare.com>
|
||||
Igor Korotin <igor.korotin@linux.dev> <igor.korotin.linux@gmail.com>
|
||||
Ike Panhc <ikepanhc@gmail.com> <ike.pan@canonical.com>
|
||||
|
|
|
|||
|
|
@ -789,6 +789,24 @@ Kernel parameters
|
|||
cio_ignore= [S390]
|
||||
See Documentation/arch/s390/common_io.rst for details.
|
||||
|
||||
clearcpuid=X[,X...] [X86]
|
||||
Disable CPUID feature X for the kernel. See
|
||||
arch/x86/include/asm/cpufeatures.h for the valid bit
|
||||
numbers X. Note the Linux-specific bits are not necessarily
|
||||
stable over kernel options, but the vendor-specific
|
||||
ones should be.
|
||||
X can also be a string as appearing in the flags: line
|
||||
in /proc/cpuinfo which does not have the above
|
||||
instability issue. However, not all features have names
|
||||
in /proc/cpuinfo.
|
||||
Note that using this option will taint your kernel.
|
||||
Also note that user programs calling CPUID directly
|
||||
or using the feature without checking anything
|
||||
will still see it. This just prevents it from
|
||||
being used by the kernel or shown in /proc/cpuinfo.
|
||||
Also note the kernel might malfunction if you disable
|
||||
some critical bits.
|
||||
|
||||
clk_ignore_unused
|
||||
[CLK]
|
||||
Prevents the clock framework from automatically gating
|
||||
|
|
|
|||
|
|
@ -187,10 +187,6 @@ to disable features using the feature number as defined in
|
|||
Protection can be disabled using clearcpuid=514. The number 514 is calculated
|
||||
from #define X86_FEATURE_UMIP (16*32 + 2).
|
||||
|
||||
DO NOT USE this cmdline option in production - it is meant to be used only as
|
||||
a quick'n'dirty debugging aid to rule out a feature-enabling code is the
|
||||
culprit. If you use it, it'll taint the kernel.
|
||||
|
||||
In addition, there exists a variety of custom command-line parameters that
|
||||
disable specific features. The list of parameters includes, but is not limited
|
||||
to, nofsgsbase, nosgx, noxsave, etc. 5-level paging can also be disabled using
|
||||
|
|
|
|||
|
|
@ -30,16 +30,6 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: core
|
||||
- const: iface
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
operating-points-v2: true
|
||||
|
|
@ -54,25 +44,6 @@ required:
|
|||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,eliza-inline-crypto-engine
|
||||
- qcom,milos-inline-crypto-engine
|
||||
|
||||
then:
|
||||
required:
|
||||
- power-domains
|
||||
- clock-names
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
clock-names:
|
||||
minItems: 2
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,sm8550-gcc.h>
|
||||
|
|
@ -81,11 +52,7 @@ examples:
|
|||
compatible = "qcom,sm8550-inline-crypto-engine",
|
||||
"qcom,inline-crypto-engine";
|
||||
reg = <0x01d88000 0x8000>;
|
||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
|
||||
<&gcc GCC_UFS_PHY_AHB_CLK>;
|
||||
clock-names = "core",
|
||||
"iface";
|
||||
power-domains = <&gcc UFS_PHY_GDSC>;
|
||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
|
||||
|
||||
operating-points-v2 = <&ice_opp_table>;
|
||||
|
||||
|
|
|
|||
|
|
@ -84,8 +84,7 @@ properties:
|
|||
This reference is provided for background information only.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- minItems: 4
|
||||
items:
|
||||
- items:
|
||||
- description: Phandle to HSP(High-Speed Peripheral) device
|
||||
- description: Offset of phy control register for internal
|
||||
or external clock selection
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- qcom,ipq5018-snand
|
||||
- qcom,ipq5210-snand
|
||||
- qcom,ipq5332-snand
|
||||
- qcom,ipq5424-snand
|
||||
- const: qcom,ipq9574-snand
|
||||
|
|
|
|||
|
|
@ -41,13 +41,12 @@ properties:
|
|||
- const: usb_en
|
||||
|
||||
resets:
|
||||
maxItems: 3
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: vaux
|
||||
- const: usb_rst
|
||||
- const: usb_phy
|
||||
|
||||
eswin,hsp-sp-csr:
|
||||
description:
|
||||
|
|
@ -86,8 +85,8 @@ examples:
|
|||
interrupt-parent = <&plic>;
|
||||
interrupts = <85>;
|
||||
interrupt-names = "peripheral";
|
||||
resets = <&reset 84>, <&hspcrg 2>, <&hspcrg 4>;
|
||||
reset-names = "vaux", "usb_rst", "usb_phy";
|
||||
resets = <&reset 84>, <&hspcrg 2>;
|
||||
reset-names = "vaux", "usb_rst";
|
||||
dr_mode = "peripheral";
|
||||
maximum-speed = "high-speed";
|
||||
phy_type = "utmi";
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ properties:
|
|||
const: usb2-phy
|
||||
|
||||
usb-phy:
|
||||
maxItems: 1
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: Phandle for the PHY device.
|
||||
deprecated: true
|
||||
|
||||
ctrl-module:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
@ -94,9 +96,6 @@ required:
|
|||
- interrupts
|
||||
- interrupt-names
|
||||
|
||||
allOf:
|
||||
- $ref: usb-hcd.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -12,12 +12,6 @@ protocol: genetlink
|
|||
doc: Netlink protocol to request a transport layer security handshake.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: const
|
||||
name: max-errno
|
||||
value: 4095
|
||||
header: linux/err.h
|
||||
scope: kernel
|
||||
-
|
||||
type: enum
|
||||
name: handler-class
|
||||
|
|
@ -86,8 +80,6 @@ attribute-sets:
|
|||
-
|
||||
name: status
|
||||
type: u32
|
||||
checks:
|
||||
max: max-errno
|
||||
-
|
||||
name: sockfd
|
||||
type: s32
|
||||
|
|
|
|||
21
MAINTAINERS
21
MAINTAINERS
|
|
@ -1150,9 +1150,8 @@ F: Documentation/arch/x86/amd-hfi.rst
|
|||
F: drivers/platform/x86/amd/hfi/
|
||||
|
||||
AMD IOMMU (AMD-VI)
|
||||
M: Joerg Roedel (AMD) <joro@8bytes.org>
|
||||
M: Joerg Roedel <joro@8bytes.org>
|
||||
R: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
|
||||
R: Vasant Hegde <vasant.hegde@amd.com>
|
||||
L: iommu@lists.linux.dev
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
|
||||
|
|
@ -6535,7 +6534,7 @@ F: include/linux/blk-cgroup.h
|
|||
|
||||
CONTROL GROUP - CPUSET
|
||||
M: Waiman Long <longman@redhat.com>
|
||||
R: Ridong Chen <ridong.chen@linux.dev>
|
||||
R: Chen Ridong <chenridong@huaweicloud.com>
|
||||
L: cgroups@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
|
||||
|
|
@ -10836,7 +10835,7 @@ F: include/linux/generic-radix-tree.h
|
|||
F: lib/generic-radix-tree.c
|
||||
|
||||
GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/input/touchscreen/resistive-adc-touch.c
|
||||
|
|
@ -13484,7 +13483,7 @@ F: include/linux/iommu-dma.h
|
|||
F: include/linux/iova.h
|
||||
|
||||
IOMMU SUBSYSTEM
|
||||
M: Joerg Roedel (AMD) <joro@8bytes.org>
|
||||
M: Joerg Roedel <joro@8bytes.org>
|
||||
M: Will Deacon <will@kernel.org>
|
||||
R: Robin Murphy <robin.murphy@arm.com>
|
||||
L: iommu@lists.linux.dev
|
||||
|
|
@ -16507,7 +16506,7 @@ F: drivers/usb/mtu3/
|
|||
|
||||
MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
|
||||
M: Peter Senna Tschudin <peter.senna@gmail.com>
|
||||
M: Ian Ray <ian.ray@gehealthcare.com>
|
||||
M: Ian Ray <ian.ray@ge.com>
|
||||
M: Martyn Welch <martyn.welch@collabora.co.uk>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
|
||||
|
|
@ -17346,7 +17345,7 @@ F: Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt
|
|||
F: sound/soc/atmel
|
||||
|
||||
MICROCHIP CSI2DC DRIVER
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/microchip,csi2dc.yaml
|
||||
|
|
@ -17373,7 +17372,7 @@ F: drivers/i2c/busses/i2c-at91-*.c
|
|||
F: drivers/i2c/busses/i2c-at91.h
|
||||
|
||||
MICROCHIP ISC DRIVER
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/atmel,isc.yaml
|
||||
|
|
@ -17385,7 +17384,7 @@ F: drivers/staging/media/deprecated/atmel/atmel-sama*-isc*
|
|||
F: include/linux/atmel-isc-media.h
|
||||
|
||||
MICROCHIP ISI DRIVER
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/media/platform/atmel/atmel-isi.c
|
||||
|
|
@ -17575,7 +17574,7 @@ F: Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml
|
|||
F: drivers/gpu/drm/bridge/microchip-lvds.c
|
||||
|
||||
MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
|
||||
|
|
@ -24125,7 +24124,7 @@ F: drivers/mmc/host/sdhci*
|
|||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||
M: Aubin Constans <aubin.constans@microchip.com>
|
||||
R: Eugen Hristev <ehristev@kernel.org>
|
||||
R: Eugen Hristev <eugen.hristev@collabora.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/sdhci-of-at91.c
|
||||
|
|
|
|||
5
Makefile
5
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc7
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
@ -607,7 +607,6 @@ KBUILD_RUSTFLAGS := $(rust_common_flags) \
|
|||
-Crelocation-model=static \
|
||||
-Zfunction-sections=n \
|
||||
-Wclippy::float_arithmetic
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS :=
|
||||
|
||||
KBUILD_AFLAGS_KERNEL :=
|
||||
KBUILD_CFLAGS_KERNEL :=
|
||||
|
|
@ -644,7 +643,7 @@ export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS
|
|||
|
||||
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
|
||||
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
|
||||
export KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE KBUILD_RUSTFLAGS_OPTION_CHKS
|
||||
export KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE
|
||||
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
|
||||
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTFLAGS_MODULE KBUILD_LDFLAGS_MODULE
|
||||
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ config ARM
|
|||
select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
select HAVE_RSEQ
|
||||
select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7 && !KASAN
|
||||
select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7
|
||||
select HAVE_STACKPROTECTOR
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_UID16
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@
|
|||
partitions {
|
||||
compatible = "redboot-fis";
|
||||
/* Eraseblock at 0xfe0000 */
|
||||
fis-index-block = <0x7f>;
|
||||
fis-index-block = <0x1fc>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@
|
|||
partitions {
|
||||
compatible = "redboot-fis";
|
||||
/* Eraseblock at 0xfe0000 */
|
||||
fis-index-block = <0x7f>;
|
||||
fis-index-block = <0x1fc>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -990,9 +990,9 @@
|
|||
<62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */
|
||||
<63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */
|
||||
<64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */
|
||||
clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>;
|
||||
clock-names = "hclk", "pclk", "tsu_clk";
|
||||
assigned-clocks = <&pmc PMC_TYPE_GCK 24>;
|
||||
clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>, <&pmc PMC_TYPE_GCK 67>;
|
||||
clock-names = "hclk", "pclk", "tx_clk", "tsu_clk";
|
||||
assigned-clocks = <&pmc PMC_TYPE_GCK 67>;
|
||||
assigned-clock-rates = <266666666>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
|
|||
}
|
||||
|
||||
socfpga_scu_base_addr = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
if (!socfpga_scu_base_addr)
|
||||
return;
|
||||
scu_enable(socfpga_scu_base_addr);
|
||||
|
|
|
|||
|
|
@ -63,9 +63,6 @@ else
|
|||
KBUILD_CFLAGS += -fasynchronous-unwind-tables
|
||||
KBUILD_AFLAGS += -fasynchronous-unwind-tables
|
||||
KBUILD_RUSTFLAGS += -Cforce-unwind-tables=y -Zuse-sync-unwind=n
|
||||
# Work around rustc bug on compilers without
|
||||
# https://github.com/rust-lang/rust/pull/156973.
|
||||
KBUILD_RUSTFLAGS += $(if $(call rustc-min-version,109800),,-Zllvm_module_flag=uwtable:u32:2:max)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
|
||||
|
|
|
|||
|
|
@ -843,11 +843,7 @@
|
|||
"qcom,inline-crypto-engine";
|
||||
reg = <0x0 0x01d88000 0x0 0x18000>;
|
||||
|
||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
|
||||
<&gcc GCC_UFS_PHY_AHB_CLK>;
|
||||
clock-names = "core",
|
||||
"iface";
|
||||
power-domains = <&gcc GCC_UFS_PHY_GDSC>;
|
||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
|
||||
};
|
||||
|
||||
tcsr_mutex: hwlock@1f40000 {
|
||||
|
|
|
|||
|
|
@ -2314,9 +2314,11 @@
|
|||
|
||||
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
|
||||
<&tcsr TCSR_USB3_0_CLKREF_EN>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
|
||||
<&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
|
||||
clock-names = "aux",
|
||||
"clkref",
|
||||
"ref",
|
||||
"com_aux",
|
||||
"pipe";
|
||||
|
|
@ -2341,9 +2343,11 @@
|
|||
|
||||
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
|
||||
<&tcsr TCSR_USB3_1_CLKREF_EN>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
|
||||
<&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
|
||||
clock-names = "aux",
|
||||
"clkref",
|
||||
"ref",
|
||||
"com_aux",
|
||||
"pipe";
|
||||
|
|
@ -2478,13 +2482,15 @@
|
|||
reg = <0x0 0x00fde000 0x0 0x8000>;
|
||||
|
||||
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
|
||||
<&tcsr TCSR_USB4_1_CLKREF_EN>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
|
||||
<&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
|
||||
<&gcc GCC_USB3_SEC_PHY_PIPE_CLK>,
|
||||
<&tcsr TCSR_USB4_1_CLKREF_EN>;
|
||||
clock-names = "aux",
|
||||
"ref",
|
||||
"com_aux",
|
||||
"usb3_pipe";
|
||||
"usb3_pipe",
|
||||
"clkref";
|
||||
|
||||
power-domains = <&gcc GCC_USB_1_PHY_GDSC>;
|
||||
|
||||
|
|
@ -3744,13 +3750,15 @@
|
|||
reg = <0x0 0x088e1000 0x0 0x8000>;
|
||||
|
||||
clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>,
|
||||
<&tcsr TCSR_USB4_2_CLKREF_EN>,
|
||||
<&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>,
|
||||
<&gcc GCC_USB3_TERT_PHY_PIPE_CLK>;
|
||||
<&gcc GCC_USB3_TERT_PHY_PIPE_CLK>,
|
||||
<&tcsr TCSR_USB4_2_CLKREF_EN>;
|
||||
clock-names = "aux",
|
||||
"ref",
|
||||
"com_aux",
|
||||
"usb3_pipe";
|
||||
"usb3_pipe",
|
||||
"clkref";
|
||||
|
||||
power-domains = <&gcc GCC_USB_2_PHY_GDSC>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1275,11 +1275,7 @@
|
|||
"qcom,inline-crypto-engine";
|
||||
reg = <0x0 0x01d88000 0x0 0x18000>;
|
||||
|
||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
|
||||
<&gcc GCC_UFS_PHY_AHB_CLK>;
|
||||
clock-names = "core",
|
||||
"iface";
|
||||
power-domains = <&gcc UFS_PHY_GDSC>;
|
||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
|
||||
};
|
||||
|
||||
tcsr_mutex: hwlock@1f40000 {
|
||||
|
|
|
|||
|
|
@ -982,6 +982,12 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c20 {
|
||||
clock-frequency = <400000>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&lpass_tlmm {
|
||||
spkr_01_sd_n_active: spkr-01-sd-n-active-state {
|
||||
pins = "gpio12";
|
||||
|
|
@ -1302,7 +1308,6 @@
|
|||
&tlmm {
|
||||
gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */
|
||||
<76 4>, /* SPI19 (TZ Protected) */
|
||||
<80 2>, /* I2C20 (Battery SMBus) */
|
||||
<238 1>; /* UFS Reset */
|
||||
|
||||
cam_rgb_default: cam-rgb-default-state {
|
||||
|
|
|
|||
|
|
@ -260,7 +260,6 @@ CONFIG_PCI_ENDPOINT=y
|
|||
CONFIG_PCI_ENDPOINT_CONFIGFS=y
|
||||
CONFIG_PCI_EPF_TEST=m
|
||||
CONFIG_PCI_PWRCTRL_GENERIC=m
|
||||
CONFIG_POWER_SEQUENCING_PCIE_M2=m
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_FW_LOADER_USER_HELPER=y
|
||||
|
|
|
|||
|
|
@ -511,6 +511,7 @@ enum vcpu_sysreg {
|
|||
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
|
||||
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
|
||||
HACR_EL2, /* Hypervisor Auxiliary Control Register */
|
||||
ZCR_EL2, /* SVE Control Register (EL2) */
|
||||
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
|
||||
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
|
||||
TCR_EL2, /* Translation Control Register (EL2) */
|
||||
|
|
@ -542,7 +543,6 @@ enum vcpu_sysreg {
|
|||
SCTLR2_EL2, /* System Control Register 2 (EL2) */
|
||||
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
|
||||
CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */
|
||||
ZCR_EL2, /* SVE Control Register (EL2) */
|
||||
|
||||
/* Any VNCR-capable reg goes after this point */
|
||||
MARKER(__VNCR_START__),
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ static inline bool kvm_s2_trans_exec_el0(struct kvm *kvm, struct kvm_s2_trans *t
|
|||
u8 xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, trans->desc);
|
||||
|
||||
if (!kvm_has_xnx(kvm))
|
||||
xn &= 0b10;
|
||||
xn &= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, 0b10);
|
||||
|
||||
switch (xn) {
|
||||
case 0b00:
|
||||
|
|
@ -148,7 +148,7 @@ static inline bool kvm_s2_trans_exec_el1(struct kvm *kvm, struct kvm_s2_trans *t
|
|||
u8 xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, trans->desc);
|
||||
|
||||
if (!kvm_has_xnx(kvm))
|
||||
xn &= 0b10;
|
||||
xn &= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, 0b10);
|
||||
|
||||
switch (xn) {
|
||||
case 0b00:
|
||||
|
|
|
|||
|
|
@ -1569,8 +1569,7 @@ int __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
|||
/* Do the stage-2 translation */
|
||||
ipa = (par & GENMASK_ULL(47, 12)) | (vaddr & GENMASK_ULL(11, 0));
|
||||
out.esr = 0;
|
||||
scoped_guard(srcu, &vcpu->kvm->srcu)
|
||||
ret = kvm_walk_nested_s2(vcpu, ipa, &out);
|
||||
ret = kvm_walk_nested_s2(vcpu, ipa, &out);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1666,8 +1665,7 @@ int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa, int *level)
|
|||
}
|
||||
|
||||
/* Walk the guest's PT, looking for a match along the way */
|
||||
scoped_guard(srcu, &vcpu->kvm->srcu)
|
||||
ret = walk_s1(vcpu, &wi, &wr, va);
|
||||
ret = walk_s1(vcpu, &wi, &wr, va);
|
||||
switch (ret) {
|
||||
case -EINTR:
|
||||
/* We interrupted the walk on a match, return the level */
|
||||
|
|
|
|||
|
|
@ -181,8 +181,6 @@ static inline void __deactivate_cptr_traps_vhe(struct kvm_vcpu *vcpu)
|
|||
val |= CPACR_EL1_ZEN;
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val |= CPACR_EL1_SMEN;
|
||||
if (cpus_have_final_cap(ARM64_HAS_S1POE))
|
||||
val |= CPACR_EL1_E0POE;
|
||||
|
||||
write_sysreg(val, cpacr_el1);
|
||||
}
|
||||
|
|
@ -464,13 +462,11 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
|
|||
|
||||
static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
|
||||
|
||||
/*
|
||||
* The vCPU's saved SVE state layout always matches the max VL of the
|
||||
* vCPU. Start off with the max VL so we can load the SVE state.
|
||||
*/
|
||||
sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
|
||||
sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
|
||||
__sve_restore_state(vcpu_sve_pffr(vcpu),
|
||||
&vcpu->arch.ctxt.fp_regs.fpsr,
|
||||
true);
|
||||
|
|
@ -480,10 +476,8 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
|
|||
* nested guest, as the guest hypervisor could select a smaller VL. Slap
|
||||
* that into hardware before wrapping up.
|
||||
*/
|
||||
if (is_nested_ctxt(vcpu)) {
|
||||
zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
|
||||
sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
|
||||
}
|
||||
if (is_nested_ctxt(vcpu))
|
||||
sve_cond_update_zcr_vq(__vcpu_sys_reg(vcpu, ZCR_EL2), SYS_ZCR_EL2);
|
||||
|
||||
write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
|
||||
}
|
||||
|
|
@ -507,11 +501,11 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
|
|||
return;
|
||||
|
||||
if (vcpu_has_sve(vcpu)) {
|
||||
zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
|
||||
|
||||
/* A guest hypervisor may restrict the effective max VL. */
|
||||
if (is_nested_ctxt(vcpu))
|
||||
zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
|
||||
zcr_el2 = __vcpu_sys_reg(vcpu, ZCR_EL2);
|
||||
else
|
||||
zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
|
||||
|
||||
write_sysreg_el2(zcr_el2, SYS_ZCR);
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ SYM_FUNC_START(__hyp_do_panic)
|
|||
|
||||
mov x29, x0
|
||||
|
||||
#ifdef CONFIG_PKVM_DISABLE_STAGE2_ON_PANIC
|
||||
#ifdef PKVM_DISABLE_STAGE2_ON_PANIC
|
||||
/* Ensure host stage-2 is disabled */
|
||||
mrs x0, hcr_el2
|
||||
bic x0, x0, #HCR_VM
|
||||
|
|
|
|||
|
|
@ -925,9 +925,7 @@ static bool stage2_pte_cacheable(struct kvm_pgtable *pgt, kvm_pte_t pte)
|
|||
|
||||
static bool stage2_pte_executable(kvm_pte_t pte)
|
||||
{
|
||||
enum kvm_pgtable_prot prot = kvm_pgtable_stage2_pte_prot(pte);
|
||||
|
||||
return prot & (KVM_PGTABLE_PROT_UX | KVM_PGTABLE_PROT_PX);
|
||||
return kvm_pte_valid(pte) && !(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN);
|
||||
}
|
||||
|
||||
static u64 stage2_map_walker_phys_addr(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ static void hyp_trace_buffer_unshare_hyp(struct hyp_trace_buffer *trace_buffer,
|
|||
if (cpu > last_cpu)
|
||||
break;
|
||||
|
||||
__unshare_page(rb_desc->meta_va);
|
||||
__share_page(rb_desc->meta_va);
|
||||
for (p = 0; p < rb_desc->nr_page_va; p++)
|
||||
__unshare_page(rb_desc->page_va[p]);
|
||||
}
|
||||
|
|
@ -212,15 +212,14 @@ static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
while (--p >= 0)
|
||||
for (p--; p >= 0; p--)
|
||||
__unshare_page(rb_desc->page_va[p]);
|
||||
__unshare_page(rb_desc->meta_va);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
hyp_trace_buffer_unshare_hyp(trace_buffer, --cpu);
|
||||
hyp_trace_buffer_unshare_hyp(trace_buffer, cpu--);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -249,7 +248,6 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
|
|||
goto err_free_desc;
|
||||
|
||||
trace_buffer->desc = desc;
|
||||
trace_buffer->desc_size = desc_size;
|
||||
|
||||
ret = hyp_trace_buffer_alloc_bpages_backing(trace_buffer, size);
|
||||
if (ret)
|
||||
|
|
@ -299,7 +297,6 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
|
|||
hyp_trace_buffer_free_bpages_backing(trace_buffer);
|
||||
free_pages_exact(trace_buffer->desc, trace_buffer->desc_size);
|
||||
trace_buffer->desc = NULL;
|
||||
trace_buffer->desc_size = 0;
|
||||
}
|
||||
|
||||
static int hyp_trace_enable_tracing(bool enable, void *priv)
|
||||
|
|
|
|||
|
|
@ -89,28 +89,21 @@ int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu)
|
|||
* again, and there is no reason to affect the whole VM for this.
|
||||
*/
|
||||
num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU;
|
||||
tmp = kvrealloc(kvm->arch.nested_mmus,
|
||||
size_mul(sizeof(*kvm->arch.nested_mmus), num_mmus),
|
||||
GFP_KERNEL_ACCOUNT | __GFP_ZERO);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
if (num_mmus > kvm->arch.nested_mmus_size) {
|
||||
tmp = kvcalloc(num_mmus, sizeof(*tmp), GFP_KERNEL_ACCOUNT);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
swap(kvm->arch.nested_mmus, tmp);
|
||||
|
||||
write_lock(&kvm->mmu_lock);
|
||||
|
||||
if (kvm->arch.nested_mmus_size) {
|
||||
memcpy(tmp, kvm->arch.nested_mmus,
|
||||
size_mul(sizeof(*tmp), kvm->arch.nested_mmus_size));
|
||||
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++)
|
||||
tmp[i].pgt->mmu = &tmp[i];
|
||||
}
|
||||
|
||||
swap(kvm->arch.nested_mmus, tmp);
|
||||
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
|
||||
kvfree(tmp);
|
||||
}
|
||||
/*
|
||||
* If we went through a realocation, adjust the MMU back-pointers in
|
||||
* the previously initialised kvm_pgtable structures.
|
||||
*/
|
||||
if (kvm->arch.nested_mmus != tmp)
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++)
|
||||
kvm->arch.nested_mmus[i].pgt->mmu = &kvm->arch.nested_mmus[i];
|
||||
|
||||
for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++)
|
||||
ret = init_nested_s2_mmu(kvm, &kvm->arch.nested_mmus[i]);
|
||||
|
|
@ -1841,11 +1834,6 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
|
|||
resx.res1 = VNCR_EL2_RES1;
|
||||
set_sysreg_masks(kvm, VNCR_EL2, resx);
|
||||
|
||||
/* ZCR_EL2 - bits 8:4 are RAZ/WI so treat them as RES0 */
|
||||
resx.res0 = ZCR_ELx_RES0 | GENMASK_ULL(8, 4);
|
||||
resx.res1 = ZCR_ELx_RES1;
|
||||
set_sysreg_masks(kvm, ZCR_EL2, resx);
|
||||
|
||||
out:
|
||||
for (enum vcpu_sysreg sr = __SANITISED_REG_START__; sr < NR_SYS_REGS; sr++)
|
||||
__vcpu_rmw_sys_reg(vcpu, sr, |=, 0);
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ static void kvm_pmu_set_pmc_value(struct kvm_pmc *pmc, u64 val, bool force)
|
|||
* action is to use PMCR.P, which will reset them to
|
||||
* 0 (the only use of the 'force' parameter).
|
||||
*/
|
||||
val = (__vcpu_sys_reg(vcpu, reg) & GENMASK(63, 32)) |
|
||||
lower_32_bits(val);
|
||||
val = __vcpu_sys_reg(vcpu, reg) & GENMASK(63, 32);
|
||||
val |= lower_32_bits(val);
|
||||
}
|
||||
|
||||
__vcpu_assign_sys_reg(vcpu, reg, val);
|
||||
|
|
|
|||
|
|
@ -2862,16 +2862,21 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
|
|||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
unsigned int vq;
|
||||
|
||||
if (guest_hyp_sve_traps_enabled(vcpu)) {
|
||||
kvm_inject_nested_sve_trap(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!p->is_write)
|
||||
if (!p->is_write) {
|
||||
p->regval = __vcpu_sys_reg(vcpu, ZCR_EL2);
|
||||
else
|
||||
__vcpu_assign_sys_reg(vcpu, ZCR_EL2, p->regval);
|
||||
return true;
|
||||
}
|
||||
|
||||
vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1;
|
||||
vq = min(vq, vcpu_sve_max_vq(vcpu));
|
||||
__vcpu_assign_sys_reg(vcpu, ZCR_EL2, vq - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -597,10 +597,8 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
|
|||
unsigned long idx;
|
||||
|
||||
xa_for_each(&its->translation_cache, idx, irq) {
|
||||
/* Only the context that erases the entry drops its cache ref. */
|
||||
irq = xa_erase(&its->translation_cache, idx);
|
||||
if (irq)
|
||||
vgic_put_irq(kvm, irq);
|
||||
xa_erase(&its->translation_cache, idx);
|
||||
vgic_put_irq(kvm, irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,6 @@
|
|||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/ioasic_addrs.h>
|
||||
#include <asm/dec/kn01.h>
|
||||
#include <asm/dec/kn02.h>
|
||||
#include <asm/dec/system.h>
|
||||
|
||||
static struct resource dec_rtc_resources[] = {
|
||||
{
|
||||
.name = "rtc",
|
||||
|
|
@ -38,110 +30,11 @@ static struct platform_device dec_rtc_device = {
|
|||
.num_resources = ARRAY_SIZE(dec_rtc_resources),
|
||||
};
|
||||
|
||||
static struct resource dec_dz_resources[] = {
|
||||
{ .name = "dz", .flags = IORESOURCE_MEM, },
|
||||
{ .name = "dz", .flags = IORESOURCE_IRQ, },
|
||||
};
|
||||
|
||||
static struct platform_device dec_dz_device = {
|
||||
.name = "dz",
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.resource = dec_dz_resources,
|
||||
.num_resources = ARRAY_SIZE(dec_dz_resources),
|
||||
};
|
||||
|
||||
static struct platform_device *dec_dz_devices[] __initdata = {
|
||||
&dec_dz_device,
|
||||
};
|
||||
|
||||
static struct resource dec_zs_resources[][2] = {
|
||||
{
|
||||
{ .name = "scc0", .flags = IORESOURCE_MEM, },
|
||||
{ .name = "scc0", .flags = IORESOURCE_IRQ, },
|
||||
},
|
||||
{
|
||||
{ .name = "scc1", .flags = IORESOURCE_MEM, },
|
||||
{ .name = "scc1", .flags = IORESOURCE_IRQ, },
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device dec_zs_device[] = {
|
||||
{
|
||||
.name = "zs",
|
||||
.id = 0,
|
||||
.resource = dec_zs_resources[0],
|
||||
.num_resources = ARRAY_SIZE(dec_zs_resources[0]),
|
||||
},
|
||||
{
|
||||
.name = "zs",
|
||||
.id = 1,
|
||||
.resource = dec_zs_resources[1],
|
||||
.num_resources = ARRAY_SIZE(dec_zs_resources[1]),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dec_add_devices(void)
|
||||
{
|
||||
struct platform_device *dec_zs_devices[ARRAY_SIZE(dec_zs_device)];
|
||||
int ret1, ret2, ret3;
|
||||
int num_dz, num_zs;
|
||||
int irq, i;
|
||||
|
||||
dec_rtc_resources[0].start = RTC_PORT(0);
|
||||
dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1;
|
||||
|
||||
i = 0;
|
||||
irq = dec_interrupt[DEC_IRQ_DZ11];
|
||||
if (IS_ENABLED(CONFIG_32BIT) && irq >= 0) {
|
||||
resource_size_t base;
|
||||
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS23100:
|
||||
case MACH_DS5100:
|
||||
base = dec_kn_slot_base + KN01_DZ11;
|
||||
break;
|
||||
default:
|
||||
base = dec_kn_slot_base + KN02_DZ11;
|
||||
break;
|
||||
}
|
||||
dec_dz_device.resource[0].start = base;
|
||||
dec_dz_device.resource[0].end = base + dec_kn_slot_size - 1;
|
||||
dec_dz_device.resource[1].start = irq;
|
||||
dec_dz_device.resource[1].end = irq;
|
||||
i++;
|
||||
}
|
||||
num_dz = i;
|
||||
|
||||
i = 0;
|
||||
irq = dec_interrupt[DEC_IRQ_SCC0];
|
||||
if (irq >= 0) {
|
||||
resource_size_t base = dec_kn_slot_base + IOASIC_SCC0;
|
||||
|
||||
dec_zs_device[i].resource[0].start = base;
|
||||
dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
|
||||
dec_zs_device[i].resource[1].start = irq;
|
||||
dec_zs_device[i].resource[1].end = irq;
|
||||
dec_zs_devices[i] = &dec_zs_device[i];
|
||||
i++;
|
||||
}
|
||||
irq = dec_interrupt[DEC_IRQ_SCC1];
|
||||
if (irq >= 0) {
|
||||
resource_size_t base = dec_kn_slot_base + IOASIC_SCC1;
|
||||
|
||||
dec_zs_device[i].resource[0].start = base;
|
||||
dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
|
||||
dec_zs_device[i].resource[1].start = irq;
|
||||
dec_zs_device[i].resource[1].end = irq;
|
||||
dec_zs_devices[i] = &dec_zs_device[i];
|
||||
i++;
|
||||
}
|
||||
num_zs = i;
|
||||
|
||||
ret1 = platform_device_register(&dec_rtc_device);
|
||||
ret2 = IS_ENABLED(CONFIG_32BIT) ?
|
||||
platform_add_devices(dec_dz_devices, num_dz) : 0;
|
||||
ret3 = platform_add_devices(dec_zs_devices, num_zs);
|
||||
return ret1 ? ret1 : ret2 ? ret2 : ret3;
|
||||
return platform_device_register(&dec_rtc_device);
|
||||
}
|
||||
|
||||
device_initcall(dec_add_devices);
|
||||
|
|
|
|||
|
|
@ -32,10 +32,6 @@ asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *);
|
|||
__diag_push(); \
|
||||
__diag_ignore(GCC, 8, "-Wattribute-alias", \
|
||||
"Type aliasing is used to sanitize syscall arguments"); \
|
||||
__diag_ignore(clang, 23, "-Wunknown-warning-option", \
|
||||
"Avoid breaking versions without -Wattribute-alias"); \
|
||||
__diag_ignore(clang, 23, "-Wattribute-alias", \
|
||||
"Type aliasing is used to sanitize syscall arguments"); \
|
||||
static long __se_##prefix##name(ulong, ulong, ulong, ulong, ulong, ulong, \
|
||||
ulong) \
|
||||
__attribute__((alias(__stringify(___se_##prefix##name)))); \
|
||||
|
|
|
|||
|
|
@ -56,10 +56,6 @@ CONFIG_EXPOLINE_AUTO=y
|
|||
CONFIG_CHSC_SCH=y
|
||||
CONFIG_VFIO_CCW=m
|
||||
CONFIG_VFIO_AP=m
|
||||
CONFIG_VFIO_DEVICE_CDEV=y
|
||||
CONFIG_IOMMUFD_DRIVER=y
|
||||
CONFIG_IOMMUFD_DRIVER_CORE=y
|
||||
CONFIG_IOMMUFD=y
|
||||
CONFIG_CMM=m
|
||||
CONFIG_APPLDATA_BASE=y
|
||||
CONFIG_S390_HYPFS_FS=y
|
||||
|
|
|
|||
|
|
@ -54,10 +54,6 @@ CONFIG_EXPOLINE_AUTO=y
|
|||
CONFIG_CHSC_SCH=y
|
||||
CONFIG_VFIO_CCW=m
|
||||
CONFIG_VFIO_AP=m
|
||||
CONFIG_VFIO_DEVICE_CDEV=y
|
||||
CONFIG_IOMMUFD_DRIVER=y
|
||||
CONFIG_IOMMUFD_DRIVER_CORE=y
|
||||
CONFIG_IOMMUFD=y
|
||||
CONFIG_CMM=m
|
||||
CONFIG_APPLDATA_BASE=y
|
||||
CONFIG_S390_HYPFS_FS=y
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ menu "Accelerated Cryptographic Algorithms for CPU (s390)"
|
|||
|
||||
config CRYPTO_AES_S390
|
||||
tristate "Ciphers: AES, modes: ECB, CBC, CTR, XTS, GCM"
|
||||
select CRYPTO_AEAD
|
||||
select CRYPTO_SKCIPHER
|
||||
help
|
||||
AEAD cipher: AES with GCM
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@
|
|||
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
#define __BUG_ENTRY_VERBOSE(file, line) \
|
||||
#define __BUG_ENTRY_VERBOSE(format, file, line) \
|
||||
" .long " format " - . # bug_entry::format\n" \
|
||||
" .long " file " - . # bug_entry::file\n" \
|
||||
" .short " line " # bug_entry::line\n"
|
||||
#else
|
||||
#define __BUG_ENTRY_VERBOSE(file, line)
|
||||
#define __BUG_ENTRY_VERBOSE(format, file, line)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED
|
||||
|
|
@ -27,10 +28,9 @@
|
|||
|
||||
#define __BUG_ENTRY(format, file, line, flags, size) \
|
||||
" .section __bug_table,\"aw\"\n" \
|
||||
"1: .long 0b - . # bug_entry::bug_addr\n"\
|
||||
" .long " format " - . # bug_entry::format\n" \
|
||||
__BUG_ENTRY_VERBOSE(file, line) \
|
||||
" .short "flags" # bug_entry::flags\n" \
|
||||
"1: .long 0b - . # bug_entry::bug_addr\n" \
|
||||
__BUG_ENTRY_VERBOSE(format, file, line) \
|
||||
" .short "flags" # bug_entry::flags\n" \
|
||||
" .org 1b+"size"\n" \
|
||||
" .previous"
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,5 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr);
|
|||
void gmap_helper_discard(struct mm_struct *mm, unsigned long vmaddr, unsigned long end);
|
||||
int gmap_helper_disable_cow_sharing(void);
|
||||
void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr);
|
||||
pte_t *try_get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl);
|
||||
|
||||
#endif /* _ASM_S390_GMAP_HELPERS_H */
|
||||
|
|
|
|||
|
|
@ -7,6 +7,4 @@
|
|||
#define __ALIGN .balign CONFIG_FUNCTION_ALIGNMENT, 0x07
|
||||
#define __ALIGN_STR __stringify(__ALIGN)
|
||||
|
||||
#define _THIS_IP_ ({ unsigned long __ip; asm volatile("larl %0, ." : "=d" (__ip)); __ip; })
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,8 +36,7 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
struct kvm_s390_mmu_cache *mc = NULL;
|
||||
struct kvm_memory_slot *slot;
|
||||
unsigned long inv_seq;
|
||||
int rc = -EAGAIN;
|
||||
int foll;
|
||||
int foll, rc = 0;
|
||||
|
||||
foll = f->write_attempt ? FOLL_WRITE : 0;
|
||||
foll |= f->attempt_pfault ? FOLL_NOWAIT : 0;
|
||||
|
|
@ -54,14 +53,7 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!mc) {
|
||||
local_mc = kvm_s390_new_mmu_cache();
|
||||
if (!local_mc)
|
||||
return -ENOMEM;
|
||||
mc = local_mc;
|
||||
}
|
||||
|
||||
while (rc == -EAGAIN) {
|
||||
while (1) {
|
||||
f->valid = false;
|
||||
inv_seq = kvm->mmu_invalidate_seq;
|
||||
/* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */
|
||||
|
|
@ -101,7 +93,14 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
if (is_error_pfn(f->pfn))
|
||||
return -EFAULT;
|
||||
|
||||
/* Loop, release the faulted page. */
|
||||
if (!mc) {
|
||||
local_mc = kvm_s390_new_mmu_cache();
|
||||
if (!local_mc)
|
||||
return -ENOMEM;
|
||||
mc = local_mc;
|
||||
}
|
||||
|
||||
/* Loop, will automatically release the faulted page. */
|
||||
if (mmu_invalidate_retry_gfn_unsafe(kvm, inv_seq, f->gfn)) {
|
||||
kvm_release_faultin_page(kvm, f->page, true, false);
|
||||
continue;
|
||||
|
|
@ -111,19 +110,20 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
if (!mmu_invalidate_retry_gfn(kvm, inv_seq, f->gfn)) {
|
||||
f->valid = true;
|
||||
rc = gmap_link(mc, kvm->arch.gmap, f, slot);
|
||||
kvm_release_faultin_page(kvm, f->page, !!rc, f->write_attempt);
|
||||
f->page = NULL;
|
||||
}
|
||||
kvm_release_faultin_page(kvm, f->page, !!rc, f->write_attempt);
|
||||
}
|
||||
kvm_release_faultin_page(kvm, f->page, true, false);
|
||||
|
||||
if (rc == -ENOMEM) {
|
||||
rc = kvm_s390_mmu_cache_topup(mc);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = -EAGAIN;
|
||||
} else if (rc != -EAGAIN) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int kvm_s390_get_guest_page(struct kvm *kvm, struct guest_fault *f, gfn_t gfn, bool w)
|
||||
|
|
|
|||
|
|
@ -1466,17 +1466,15 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
|
|||
struct guest_fault *f, bool p)
|
||||
{
|
||||
union crste newcrste, oldcrste;
|
||||
unsigned long mask;
|
||||
gfn_t r_gfn;
|
||||
gfn_t gfn;
|
||||
int rc;
|
||||
|
||||
lockdep_assert_held(&sg->kvm->mmu_lock);
|
||||
lockdep_assert_held(&sg->parent->children_lock);
|
||||
|
||||
mask = is_pmd(*table) ? _SEGMENT_FR_MASK : _REGION3_FR_MASK;
|
||||
r_gfn = gpa_to_gfn(raddr) & mask;
|
||||
gfn = f->gfn & (is_pmd(*table) ? _SEGMENT_FR_MASK : _REGION3_FR_MASK);
|
||||
scoped_guard(spinlock, &sg->host_to_rmap_lock)
|
||||
rc = gmap_insert_rmap(sg, f->gfn & mask, r_gfn, host->h.tt);
|
||||
rc = gmap_insert_rmap(sg, gfn, gpa_to_gfn(raddr), host->h.tt);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1499,7 +1497,8 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
|
|||
return -EAGAIN;
|
||||
|
||||
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p);
|
||||
while (!dat_crstep_xchg_atomic(table, READ_ONCE(*table), newcrste, r_gfn, sg->asce))
|
||||
gfn = gpa_to_gfn(raddr);
|
||||
while (!dat_crstep_xchg_atomic(table, READ_ONCE(*table), newcrste, gfn, sg->asce))
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,28 +395,15 @@ static long _gmap_unmap_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct
|
|||
struct gmap_unmap_priv *priv = walk->priv;
|
||||
struct folio *folio = NULL;
|
||||
union crste old = *crstep;
|
||||
bool ok;
|
||||
|
||||
if (!old.h.fc)
|
||||
return 0;
|
||||
|
||||
if (old.s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
|
||||
folio = phys_to_folio(crste_origin_large(old));
|
||||
/*
|
||||
* No races should happen because kvm->mmu_lock is held in write mode,
|
||||
* but the unmap operation could have triggered an unshadow, which
|
||||
* causes gmap_crstep_xchg_atomic() to return false and clear the
|
||||
* vsie_notif bit. Allow the operation to fail once, if the old crste
|
||||
* had the vsie_notif bit set. A second failure is not allowed, for
|
||||
* the reasons above.
|
||||
*/
|
||||
ok = gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn);
|
||||
if (!ok) {
|
||||
KVM_BUG_ON(!old.s.fc1.vsie_notif, priv->gmap->kvm);
|
||||
old.s.fc1.vsie_notif = 0;
|
||||
ok = gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn);
|
||||
KVM_BUG_ON(!ok, priv->gmap->kvm);
|
||||
}
|
||||
/* No races should happen because kvm->mmu_lock is held in write mode */
|
||||
KVM_BUG_ON(!gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn),
|
||||
priv->gmap->kvm);
|
||||
if (folio)
|
||||
uv_convert_from_secure_folio(folio);
|
||||
|
||||
|
|
|
|||
|
|
@ -273,14 +273,11 @@ static inline bool __must_check _gmap_crstep_xchg_atomic(struct gmap *gmap, unio
|
|||
gmap_unmap_prefix(gmap, gfn, gfn + align);
|
||||
}
|
||||
if (crste_leaf(oldcrste) && crste_needs_unshadow(oldcrste, newcrste)) {
|
||||
newcrste = oldcrste;
|
||||
newcrste.s.fc1.vsie_notif = 0;
|
||||
if (needs_lock)
|
||||
gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||
else
|
||||
_gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||
dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, gmap->asce);
|
||||
return false;
|
||||
}
|
||||
if (!oldcrste.s.fc1.d && newcrste.s.fc1.d && !newcrste.s.fc1.s)
|
||||
SetPageDirty(phys_to_page(crste_origin_large(newcrste)));
|
||||
|
|
|
|||
|
|
@ -999,10 +999,7 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||
break;
|
||||
}
|
||||
case KVM_S390_VM_MEM_LIMIT_SIZE: {
|
||||
struct kvm_memslots *slots;
|
||||
struct kvm_memory_slot *ms;
|
||||
unsigned long new_limit;
|
||||
int bkt;
|
||||
|
||||
if (kvm_is_ucontrol(kvm))
|
||||
return -EINVAL;
|
||||
|
|
@ -1010,9 +1007,6 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||
if (get_user(new_limit, (u64 __user *)attr->addr))
|
||||
return -EFAULT;
|
||||
|
||||
guard(mutex)(&kvm->lock);
|
||||
|
||||
new_limit = ALIGN(new_limit, HPAGE_SIZE);
|
||||
if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT &&
|
||||
new_limit > kvm->arch.mem_limit)
|
||||
return -E2BIG;
|
||||
|
|
@ -1020,27 +1014,12 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||
if (!new_limit)
|
||||
return -EINVAL;
|
||||
|
||||
if (kvm->created_vcpus)
|
||||
return -EBUSY;
|
||||
|
||||
ret = 0;
|
||||
scoped_guard(mutex, &kvm->slots_lock) {
|
||||
slots = kvm_memslots(kvm);
|
||||
if (slots && !kvm_memslots_empty(slots)) {
|
||||
kvm_for_each_memslot(ms, bkt, slots) {
|
||||
if (gpa_to_gfn(new_limit) < ms->base_gfn + ms->npages) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
ret = gmap_set_limit(kvm->arch.gmap, gpa_to_gfn(new_limit));
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
ret = -EBUSY;
|
||||
if (!kvm->created_vcpus)
|
||||
ret = gmap_set_limit(kvm->arch.gmap, gpa_to_gfn(new_limit));
|
||||
VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit);
|
||||
VM_EVENT(kvm, 3, "New guest asce: 0x%p", (void *)kvm->arch.gmap->asce.val);
|
||||
VM_EVENT(kvm, 3, "New guest asce: 0x%p",
|
||||
(void *)kvm->arch.gmap->asce.val);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -5693,8 +5672,6 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
|||
return -EINVAL;
|
||||
if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit)
|
||||
return -EINVAL;
|
||||
if (!asce_contains_gfn(kvm->arch.gmap->asce, new->base_gfn + new->npages - 1))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!kvm->arch.migration_mode)
|
||||
|
|
|
|||
|
|
@ -1188,7 +1188,6 @@ static void _essa_clear_cbrl(struct kvm_vcpu *vcpu, unsigned long *cbrl, int len
|
|||
union crste *crstep;
|
||||
union pgste pgste;
|
||||
union pte *ptep;
|
||||
hva_t hva;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&vcpu->kvm->mmu_lock);
|
||||
|
|
@ -1200,11 +1199,8 @@ static void _essa_clear_cbrl(struct kvm_vcpu *vcpu, unsigned long *cbrl, int len
|
|||
if (!ptep || ptep->s.pr)
|
||||
continue;
|
||||
pgste = pgste_get_lock(ptep);
|
||||
if (pgste.usage == PGSTE_GPS_USAGE_UNUSED || pgste.zero) {
|
||||
hva = gpa_to_hva(vcpu->kvm, cbrl[i]);
|
||||
if (!kvm_is_error_hva(hva))
|
||||
gmap_helper_zap_one_page(vcpu->kvm->mm, hva);
|
||||
}
|
||||
if (pgste.usage == PGSTE_GPS_USAGE_UNUSED || pgste.zero)
|
||||
gmap_helper_zap_one_page(vcpu->kvm->mm, cbrl[i]);
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/pagewalk.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <asm/gmap_helpers.h>
|
||||
#include "kvm-s390.h"
|
||||
#include "dat.h"
|
||||
#include "gaccess.h"
|
||||
|
|
@ -74,7 +73,6 @@ static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_str
|
|||
struct pv_make_secure {
|
||||
void *uvcb;
|
||||
struct folio *folio;
|
||||
struct kvm *kvm;
|
||||
int rc;
|
||||
bool needs_export;
|
||||
};
|
||||
|
|
@ -105,21 +103,9 @@ static void _kvm_s390_pv_make_secure(struct guest_fault *f)
|
|||
{
|
||||
struct pv_make_secure *priv = f->priv;
|
||||
struct folio *folio;
|
||||
spinlock_t *ptl; /* pte lock from try_get_locked_pte() */
|
||||
pte_t *ptep;
|
||||
|
||||
folio = pfn_folio(f->pfn);
|
||||
priv->rc = -EAGAIN;
|
||||
|
||||
if (!mmap_read_trylock(priv->kvm->mm))
|
||||
return;
|
||||
|
||||
ptep = try_get_locked_pte(priv->kvm->mm, gfn_to_hva(priv->kvm, f->gfn), &ptl);
|
||||
if (IS_ERR_VALUE(ptep)) {
|
||||
priv->rc = PTR_ERR(ptep);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (folio_trylock(folio)) {
|
||||
priv->rc = __kvm_s390_pv_make_secure(f, folio);
|
||||
if (priv->rc == -E2BIG || priv->rc == -EBUSY) {
|
||||
|
|
@ -128,11 +114,6 @@ static void _kvm_s390_pv_make_secure(struct guest_fault *f)
|
|||
}
|
||||
folio_unlock(folio);
|
||||
}
|
||||
|
||||
if (ptep)
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
out:
|
||||
mmap_read_unlock(priv->kvm->mm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -146,7 +127,7 @@ out:
|
|||
*/
|
||||
int kvm_s390_pv_make_secure(struct kvm *kvm, unsigned long gaddr, void *uvcb)
|
||||
{
|
||||
struct pv_make_secure priv = { .uvcb = uvcb, .kvm = kvm, };
|
||||
struct pv_make_secure priv = { .uvcb = uvcb };
|
||||
struct guest_fault f = {
|
||||
.write_attempt = true,
|
||||
.gfn = gpa_to_gfn(gaddr),
|
||||
|
|
|
|||
|
|
@ -17,68 +17,22 @@
|
|||
#include <asm/gmap_helpers.h>
|
||||
|
||||
/**
|
||||
* try_get_locked_pte() - like get_locked_pte(), but atomic and with trylock
|
||||
* ptep_zap_softleaf_entry() - discard a software leaf entry.
|
||||
* @mm: the mm
|
||||
* @vmaddr: the userspace virtual address whose pte is to be found
|
||||
* @ptl: will be set to the pointer to the lock used to lock the pte in case
|
||||
* of success.
|
||||
* @entry: the software leaf entry that needs to be zapped
|
||||
*
|
||||
* This function returns the pointer to the pte corresponding to @addr in @mm,
|
||||
* similarly to get_locked_pte(). Unlike get_locked_pte(), no attempt is made
|
||||
* to allocate missing page tables. If a missing or large entry is found, the
|
||||
* function will return NULL. If the ptl lock is contended, %-EAGAIN is
|
||||
* returned.
|
||||
*
|
||||
* In case of success, *@ptl will point to the locked pte lock for the returned
|
||||
* pte, like get_locked_pte() does.
|
||||
*
|
||||
* Context: mmap_lock or vma lock for read or for write needs to be held.
|
||||
* Return:
|
||||
* * %NULL if the pte cannot be reached.
|
||||
* * %-EAGAIN if the pte can be reached, but cannot be locked.
|
||||
* * the pointer to the pte corresponding to @addr in @mm, if it can be reached
|
||||
* and locked.
|
||||
* Discards the given software leaf entry. If the leaf entry was an actual
|
||||
* swap entry (and not a migration entry, for example), the actual swapped
|
||||
* page is also discarded from swap.
|
||||
*/
|
||||
pte_t *try_get_locked_pte(struct mm_struct *mm, unsigned long vmaddr, spinlock_t **ptl)
|
||||
static void ptep_zap_softleaf_entry(struct mm_struct *mm, softleaf_t entry)
|
||||
{
|
||||
pmd_t *pmdp, pmd, pmdval;
|
||||
pud_t *pudp, pud;
|
||||
p4d_t *p4dp, p4d;
|
||||
pgd_t *pgdp, pgd;
|
||||
pte_t *ptep;
|
||||
|
||||
pgdp = pgd_offset(mm, vmaddr);
|
||||
pgd = pgdp_get(pgdp);
|
||||
if (pgd_none(pgd) || !pgd_present(pgd))
|
||||
return NULL;
|
||||
p4dp = p4d_offset(pgdp, vmaddr);
|
||||
p4d = p4dp_get(p4dp);
|
||||
if (p4d_none(p4d) || !p4d_present(p4d))
|
||||
return NULL;
|
||||
pudp = pud_offset(p4dp, vmaddr);
|
||||
pud = pudp_get(pudp);
|
||||
if (pud_none(pud) || pud_leaf(pud) || !pud_present(pud))
|
||||
return NULL;
|
||||
pmdp = pmd_offset(pudp, vmaddr);
|
||||
pmd = pmdp_get_lockless(pmdp);
|
||||
if (pmd_none(pmd) || pmd_leaf(pmd) || !pmd_present(pmd))
|
||||
return NULL;
|
||||
ptep = pte_offset_map_rw_nolock(mm, pmdp, vmaddr, &pmdval, ptl);
|
||||
if (!ptep)
|
||||
return NULL;
|
||||
|
||||
if (spin_trylock(*ptl)) {
|
||||
if (unlikely(!pmd_same(pmdval, pmdp_get_lockless(pmdp)))) {
|
||||
pte_unmap_unlock(ptep, *ptl);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
return ptep;
|
||||
}
|
||||
|
||||
pte_unmap(ptep);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
if (softleaf_is_swap(entry))
|
||||
dec_mm_counter(mm, MM_SWAPENTS);
|
||||
else if (softleaf_is_migration(entry))
|
||||
dec_mm_counter(mm, mm_counter(softleaf_to_folio(entry)));
|
||||
swap_put_entries_direct(entry, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(try_get_locked_pte);
|
||||
|
||||
/**
|
||||
* gmap_helper_zap_one_page() - discard a page if it was swapped.
|
||||
|
|
@ -92,8 +46,7 @@ EXPORT_SYMBOL_GPL(try_get_locked_pte);
|
|||
void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
spinlock_t *ptl; /* Lock for the host (userspace) page table */
|
||||
softleaf_t sl;
|
||||
spinlock_t *ptl;
|
||||
pte_t *ptep;
|
||||
|
||||
mmap_assert_locked(mm);
|
||||
|
|
@ -104,13 +57,11 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
|
|||
return;
|
||||
|
||||
/* Get pointer to the page table entry */
|
||||
ptep = try_get_locked_pte(mm, vmaddr, &ptl);
|
||||
if (IS_ERR_OR_NULL(ptep))
|
||||
ptep = get_locked_pte(mm, vmaddr, &ptl);
|
||||
if (unlikely(!ptep))
|
||||
return;
|
||||
sl = softleaf_from_pte(*ptep);
|
||||
if (pte_swap(*ptep) && softleaf_is_swap(sl)) {
|
||||
dec_mm_counter(mm, MM_SWAPENTS);
|
||||
swap_put_entries_direct(sl, 1);
|
||||
if (pte_swap(*ptep)) {
|
||||
ptep_zap_softleaf_entry(mm, softleaf_from_pte(*ptep));
|
||||
pte_clear(mm, vmaddr, ptep);
|
||||
}
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
|
|
@ -162,9 +113,37 @@ EXPORT_SYMBOL_GPL(gmap_helper_discard);
|
|||
*/
|
||||
void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr)
|
||||
{
|
||||
pmd_t *pmdp, pmd, pmdval;
|
||||
pud_t *pudp, pud;
|
||||
p4d_t *p4dp, p4d;
|
||||
pgd_t *pgdp, pgd;
|
||||
spinlock_t *ptl; /* Lock for the host (userspace) page table */
|
||||
pte_t *ptep;
|
||||
|
||||
pgdp = pgd_offset(mm, vmaddr);
|
||||
pgd = pgdp_get(pgdp);
|
||||
if (pgd_none(pgd) || !pgd_present(pgd))
|
||||
return;
|
||||
|
||||
p4dp = p4d_offset(pgdp, vmaddr);
|
||||
p4d = p4dp_get(p4dp);
|
||||
if (p4d_none(p4d) || !p4d_present(p4d))
|
||||
return;
|
||||
|
||||
pudp = pud_offset(p4dp, vmaddr);
|
||||
pud = pudp_get(pudp);
|
||||
if (pud_none(pud) || pud_leaf(pud) || !pud_present(pud))
|
||||
return;
|
||||
|
||||
pmdp = pmd_offset(pudp, vmaddr);
|
||||
pmd = pmdp_get_lockless(pmdp);
|
||||
if (pmd_none(pmd) || pmd_leaf(pmd) || !pmd_present(pmd))
|
||||
return;
|
||||
|
||||
ptep = pte_offset_map_rw_nolock(mm, pmdp, vmaddr, &pmdval, &ptl);
|
||||
if (!ptep)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Several paths exists that takes the ptl lock and then call the
|
||||
* mmu_notifier, which takes the mmu_lock. The unmap path, instead,
|
||||
|
|
@ -177,12 +156,21 @@ void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr)
|
|||
* If the lock is contended the bit is not set and the deadlock is
|
||||
* avoided.
|
||||
*/
|
||||
ptep = try_get_locked_pte(mm, vmaddr, &ptl);
|
||||
if (IS_ERR_OR_NULL(ptep))
|
||||
return;
|
||||
if (spin_trylock(ptl)) {
|
||||
/*
|
||||
* Make sure the pte we are touching is still the correct
|
||||
* one. In theory this check should not be needed, but
|
||||
* better safe than sorry.
|
||||
* Disabling interrupts or holding the mmap lock is enough to
|
||||
* guarantee that no concurrent updates to the page tables
|
||||
* are possible.
|
||||
*/
|
||||
if (likely(pmd_same(pmdval, pmdp_get_lockless(pmdp))))
|
||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||
spin_unlock(ptl);
|
||||
}
|
||||
|
||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
pte_unmap(ptep);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gmap_helper_try_set_pte_unused);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,10 +77,6 @@ KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-sse4a
|
|||
KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json
|
||||
KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2
|
||||
|
||||
# The target.json file is not available when invoking rustc-option, so use the
|
||||
# built-in target when checking whether flags are supported instead.
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS += --target=x86_64-unknown-none
|
||||
|
||||
#
|
||||
# CFLAGS for compiling floating point code inside the kernel.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -14,14 +14,6 @@ endif
|
|||
|
||||
KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json
|
||||
|
||||
# The target.json file is not available when invoking rustc-option, so use the
|
||||
# built-in target when checking whether flags are supported instead.
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS += --target=i686-unknown-linux-gnu
|
||||
else
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS += --target=x86_64-unknown-linux-gnu
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
START := 0x8048000
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ noinstr void x86_entry_from_kvm(unsigned int event_type, unsigned int vector)
|
|||
* The FRED NMI context is significantly different and will not work
|
||||
* right (specifically FRED fixed the NMI recursion issue).
|
||||
*/
|
||||
idt_do_nmi_irqoff();
|
||||
idt_entry_from_kvm(vector);
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_KVM(x86_entry_from_kvm);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -109,13 +109,11 @@ EXPORT_SYMBOL(__ref_stack_chk_guard);
|
|||
RET
|
||||
.endm
|
||||
|
||||
#ifndef CONFIG_X86_64
|
||||
.pushsection .text, "ax"
|
||||
SYM_FUNC_START(idt_do_interrupt_irqoff)
|
||||
IDT_DO_EVENT_IRQOFF CALL_NOSPEC _ASM_ARG1
|
||||
SYM_FUNC_END(idt_do_interrupt_irqoff)
|
||||
.popsection
|
||||
#endif
|
||||
|
||||
.pushsection .noinstr.text, "ax"
|
||||
SYM_FUNC_START(idt_do_nmi_irqoff)
|
||||
|
|
|
|||
|
|
@ -1504,7 +1504,6 @@ struct kvm_arch {
|
|||
bool use_master_clock;
|
||||
u64 master_kernel_ns;
|
||||
u64 master_cycle_now;
|
||||
struct ratelimit_state kvmclock_update_rs;
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
struct kvm_hv hyperv;
|
||||
|
|
|
|||
|
|
@ -733,7 +733,6 @@ bool xen_set_default_idle(void);
|
|||
#endif
|
||||
|
||||
void __noreturn stop_this_cpu(void *dummy);
|
||||
extern bool x86_hypervisor_present;
|
||||
void microcode_check(struct cpuinfo_x86 *prev_info);
|
||||
void store_cpu_caps(struct cpuinfo_x86 *info);
|
||||
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
|
|||
break;
|
||||
case 0x50 ... 0x5f:
|
||||
case 0x80 ... 0xaf:
|
||||
case 0xc0 ... 0xef:
|
||||
case 0xc0 ... 0xcf:
|
||||
setup_force_cpu_cap(X86_FEATURE_ZEN6);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ static u32 get_patch_level(void)
|
|||
{
|
||||
u32 rev, dummy __always_unused;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && x86_hypervisor_present) {
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && hypervisor_present) {
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (!microcode_rev[cpu]) {
|
||||
|
|
@ -714,7 +714,7 @@ static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev,
|
|||
invlpg(p_addr_end);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && x86_hypervisor_present)
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && hypervisor_present)
|
||||
microcode_rev[smp_processor_id()] = mc->hdr.patch_id;
|
||||
|
||||
/* verify patch application was successful */
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
|
|||
u32 base_rev;
|
||||
u32 microcode_rev[NR_CPUS] = {};
|
||||
|
||||
bool __ro_after_init x86_hypervisor_present;
|
||||
bool hypervisor_present;
|
||||
|
||||
/*
|
||||
* Synchronization.
|
||||
|
|
@ -118,9 +118,14 @@ bool __init microcode_loader_disabled(void)
|
|||
/*
|
||||
* Disable when:
|
||||
*
|
||||
* 1) The CPU does not support CPUID, detected below in
|
||||
* load_ucode_bsp().
|
||||
*
|
||||
* 1) The CPU does not support CPUID.
|
||||
*/
|
||||
if (!cpuid_feature()) {
|
||||
dis_ucode_ldr = true;
|
||||
return dis_ucode_ldr;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2) Bit 31 in CPUID[1]:ECX is clear
|
||||
* The bit is reserved for hypervisor use. This is still not
|
||||
* completely accurate as XEN PV guests don't see that CPUID bit
|
||||
|
|
@ -130,7 +135,9 @@ bool __init microcode_loader_disabled(void)
|
|||
* 3) Certain AMD patch levels are not allowed to be
|
||||
* overwritten.
|
||||
*/
|
||||
if ((x86_hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) ||
|
||||
hypervisor_present = native_cpuid_ecx(1) & BIT(31);
|
||||
|
||||
if ((hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) ||
|
||||
amd_check_current_patch_level())
|
||||
dis_ucode_ldr = true;
|
||||
|
||||
|
|
@ -172,11 +179,6 @@ void __init load_ucode_bsp(void)
|
|||
|
||||
early_parse_cmdline();
|
||||
|
||||
if (!cpuid_feature())
|
||||
dis_ucode_ldr = true;
|
||||
else
|
||||
x86_hypervisor_present = native_cpuid_ecx(1) & BIT(31);
|
||||
|
||||
if (microcode_loader_disabled())
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -138,9 +138,6 @@ u32 intel_get_platform_id(void)
|
|||
{
|
||||
unsigned int val[2];
|
||||
|
||||
if (x86_hypervisor_present)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* This can be called early. Use CPUID directly instead of
|
||||
* relying on cpuinfo_x86 which may not be fully initialized.
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ extern struct early_load_data early_data;
|
|||
extern struct ucode_cpu_info ucode_cpu_info[];
|
||||
extern u32 microcode_rev[NR_CPUS];
|
||||
extern u32 base_rev;
|
||||
extern bool hypervisor_present;
|
||||
|
||||
struct cpio_data find_microcode_in_initrd(const char *path);
|
||||
|
||||
|
|
|
|||
|
|
@ -377,12 +377,7 @@ static const struct x86_cpu_id snc_cpu_ids[] __initconst = {
|
|||
|
||||
static __init int snc_get_config(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
|
||||
return 1;
|
||||
|
||||
ret = topology_num_nodes_per_package();
|
||||
int ret = topology_num_nodes_per_package();
|
||||
|
||||
if (ret > 1 && !x86_match_cpu(snc_cpu_ids)) {
|
||||
pr_warn("CoD enabled system? Resctrl not supported\n");
|
||||
|
|
|
|||
|
|
@ -27,19 +27,14 @@
|
|||
static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
|
||||
struct _fpx_sw_bytes *fx_sw)
|
||||
{
|
||||
int min_xstate_size = sizeof(struct fxregs_state) +
|
||||
sizeof(struct xstate_header);
|
||||
void __user *fpstate = fxbuf;
|
||||
unsigned int magic2;
|
||||
|
||||
if (__copy_from_user(fx_sw, &fxbuf->sw_reserved[0], sizeof(*fx_sw)))
|
||||
return false;
|
||||
|
||||
/* Check for the first magic field and other error scenarios. */
|
||||
if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
|
||||
fx_sw->xstate_size < min_xstate_size ||
|
||||
fx_sw->xstate_size > x86_task_fpu(current)->fpstate->user_size ||
|
||||
fx_sw->xstate_size > fx_sw->extended_size)
|
||||
/* Check for the first magic field */
|
||||
if (fx_sw->magic1 != FP_XSTATE_MAGIC1)
|
||||
goto setfx;
|
||||
|
||||
/*
|
||||
|
|
@ -48,7 +43,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
|
|||
* fpstate layout with out copying the extended state information
|
||||
* in the memory layout.
|
||||
*/
|
||||
if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size)))
|
||||
if (__get_user(magic2, (__u32 __user *)(fpstate + x86_task_fpu(current)->fpstate->user_size)))
|
||||
return false;
|
||||
|
||||
if (likely(magic2 == FP_XSTATE_MAGIC2))
|
||||
|
|
|
|||
|
|
@ -375,13 +375,6 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generated trampoline may contain rIP-relative addressing which
|
||||
* displacement needs to be fixed.
|
||||
*/
|
||||
text_poke_apply_relocation(trampoline, trampoline, size,
|
||||
(void *)start_offset, size);
|
||||
|
||||
/*
|
||||
* The address of the ftrace_ops that is used for this trampoline
|
||||
* is stored at the end of the trampoline. This will be used to
|
||||
|
|
|
|||
|
|
@ -268,10 +268,18 @@ void __init idt_setup_early_pf(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL) && !defined(CONFIG_X86_64)
|
||||
void idt_entry_from_kvm(unsigned int vector)
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||
noinstr void idt_entry_from_kvm(unsigned int vector)
|
||||
{
|
||||
if (vector == NMI_VECTOR)
|
||||
return idt_do_nmi_irqoff();
|
||||
|
||||
/*
|
||||
* Only the NMI path requires noinstr.
|
||||
*/
|
||||
instrumentation_begin();
|
||||
idt_do_interrupt_irqoff(gate_offset(idt_table + vector));
|
||||
instrumentation_end();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -206,35 +206,6 @@ static void avic_activate_vmcb(struct vcpu_svm *svm)
|
|||
|
||||
svm_clr_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
|
||||
/*
|
||||
* Flush the TLB when enabling (x2)AVIC and when transitioning between
|
||||
* xAVIC and x2AVIC, as the CPU may have inserted a TLB entry for the
|
||||
* "wrong" mapping.
|
||||
*
|
||||
* KVM uses a per-VM "scratch" page to back the APIC memslot, because
|
||||
* KVM also uses per-VM page tables *and* maintains the page table (NPT
|
||||
* or shadow page) mappings for said memslot even if one or more vCPUs
|
||||
* have their local APIC hardware-disabled or are in x2APIC mode, i.e.
|
||||
* even if one or more vCPUs' APIC MMIO BAR is effectively disabled.
|
||||
*
|
||||
* If xAVIC is fully enabled, hardware ignores the physical address in
|
||||
* KVM's page tables, i.e. in the leaf SPTE for the APIC memslot, and
|
||||
* instead redirects the access to the AVIC backing page, i.e. to the
|
||||
* vCPU's virtual APIC page. If xAVIC is not enabled (APIC is either
|
||||
* hardware-disabled or in x2APIC mode), then guest accesses will use
|
||||
* the page table mapping verbatim, i.e. will access the per-VM scratch
|
||||
* page, as normal memory.
|
||||
*
|
||||
* In both cases, the CPU is allowed to cache TLB entries for the APIC
|
||||
* base GPA. So, KVM needs to flush the TLB when enabling xAVIC, as
|
||||
* accesses need to be redirected to the virtual APIC page, but the TLB
|
||||
* may contain entries pointing at the scratch page. KVM also needs to
|
||||
* flush the TLB when enabling x2AVIC, as accesses need to go to the
|
||||
* scratch page, but the TLB may contain entries tagged as xAVIC, i.e.
|
||||
* entries pointing to the vCPU's virtual APIC page.
|
||||
*/
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, &svm->vcpu);
|
||||
|
||||
/*
|
||||
* Note: KVM supports hybrid-AVIC mode, where KVM emulates x2APIC MSR
|
||||
* accesses, while interrupt injection to a running vCPU can be
|
||||
|
|
@ -248,6 +219,12 @@ static void avic_activate_vmcb(struct vcpu_svm *svm)
|
|||
/* Disabling MSR intercept for x2APIC registers */
|
||||
avic_set_x2apic_msr_interception(svm, false);
|
||||
} else {
|
||||
/*
|
||||
* Flush the TLB, the guest may have inserted a non-APIC
|
||||
* mapping into the TLB while AVIC was disabled.
|
||||
*/
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, &svm->vcpu);
|
||||
|
||||
/* Enabling MSR intercept for x2APIC registers */
|
||||
avic_set_x2apic_msr_interception(svm, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3313,6 +3313,37 @@ void sev_guest_memory_reclaimed(struct kvm *kvm)
|
|||
sev_writeback_caches(kvm);
|
||||
}
|
||||
|
||||
void sev_free_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm;
|
||||
|
||||
if (!is_sev_es_guest(vcpu))
|
||||
return;
|
||||
|
||||
svm = to_svm(vcpu);
|
||||
|
||||
/*
|
||||
* If it's an SNP guest, then the VMSA was marked in the RMP table as
|
||||
* a guest-owned page. Transition the page to hypervisor state before
|
||||
* releasing it back to the system.
|
||||
*/
|
||||
if (is_sev_snp_guest(vcpu)) {
|
||||
u64 pfn = __pa(svm->sev_es.vmsa) >> PAGE_SHIFT;
|
||||
|
||||
if (kvm_rmp_make_shared(vcpu->kvm, pfn, PG_LEVEL_4K))
|
||||
goto skip_vmsa_free;
|
||||
}
|
||||
|
||||
if (vcpu->arch.guest_state_protected)
|
||||
sev_flush_encrypted_page(vcpu, svm->sev_es.vmsa);
|
||||
|
||||
__free_page(virt_to_page(svm->sev_es.vmsa));
|
||||
|
||||
skip_vmsa_free:
|
||||
if (svm->sev_es.ghcb_sa_free)
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
}
|
||||
|
||||
static void dump_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vmcb_control_area *control = &svm->vmcb->control;
|
||||
|
|
@ -3552,20 +3583,6 @@ vmgexit_err:
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void __sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
if (svm->sev_es.ghcb_sa_free) {
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
svm->sev_es.ghcb_sa = NULL;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
}
|
||||
|
||||
if (svm->sev_es.ghcb) {
|
||||
kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map);
|
||||
svm->sev_es.ghcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
/* Clear any indication that the vCPU is in a type of AP Reset Hold */
|
||||
|
|
@ -3574,51 +3591,31 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
|||
if (!svm->sev_es.ghcb)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If the scratch area lives outside the GHCB, there's a buffer that,
|
||||
* depending on the operation performed, may need to be synced.
|
||||
*/
|
||||
if (svm->sev_es.ghcb_sa_sync) {
|
||||
kvm_write_guest(svm->vcpu.kvm, svm->sev_es.sw_scratch,
|
||||
svm->sev_es.ghcb_sa, svm->sev_es.ghcb_sa_len);
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
if (svm->sev_es.ghcb_sa_free) {
|
||||
/*
|
||||
* The scratch area lives outside the GHCB, so there is a
|
||||
* buffer that, depending on the operation performed, may
|
||||
* need to be synced, then freed.
|
||||
*/
|
||||
if (svm->sev_es.ghcb_sa_sync) {
|
||||
kvm_write_guest(svm->vcpu.kvm,
|
||||
svm->sev_es.sw_scratch,
|
||||
svm->sev_es.ghcb_sa,
|
||||
svm->sev_es.ghcb_sa_len);
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
}
|
||||
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
svm->sev_es.ghcb_sa = NULL;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
}
|
||||
|
||||
trace_kvm_vmgexit_exit(svm->vcpu.vcpu_id, svm->sev_es.ghcb);
|
||||
|
||||
sev_es_sync_to_ghcb(svm);
|
||||
|
||||
__sev_es_unmap_ghcb(svm);
|
||||
}
|
||||
|
||||
void sev_free_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm;
|
||||
|
||||
if (!is_sev_es_guest(vcpu))
|
||||
return;
|
||||
|
||||
svm = to_svm(vcpu);
|
||||
|
||||
/*
|
||||
* If it's an SNP guest, then the VMSA was marked in the RMP table as
|
||||
* a guest-owned page. Transition the page to hypervisor state before
|
||||
* releasing it back to the system.
|
||||
*/
|
||||
if (is_sev_snp_guest(vcpu)) {
|
||||
u64 pfn = __pa(svm->sev_es.vmsa) >> PAGE_SHIFT;
|
||||
|
||||
if (kvm_rmp_make_shared(vcpu->kvm, pfn, PG_LEVEL_4K))
|
||||
goto skip_vmsa_free;
|
||||
}
|
||||
|
||||
if (vcpu->arch.guest_state_protected)
|
||||
sev_flush_encrypted_page(vcpu, svm->sev_es.vmsa);
|
||||
|
||||
__free_page(virt_to_page(svm->sev_es.vmsa));
|
||||
|
||||
skip_vmsa_free:
|
||||
__sev_es_unmap_ghcb(svm);
|
||||
kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map);
|
||||
svm->sev_es.ghcb = NULL;
|
||||
}
|
||||
|
||||
int pre_sev_run(struct vcpu_svm *svm, int cpu)
|
||||
|
|
@ -3665,31 +3662,26 @@ int pre_sev_run(struct vcpu_svm *svm, int cpu)
|
|||
}
|
||||
|
||||
#define GHCB_SCRATCH_AREA_LIMIT (16ULL * PAGE_SIZE)
|
||||
static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len)
|
||||
static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
{
|
||||
struct vmcb_control_area *control = &svm->vmcb->control;
|
||||
u64 ghcb_scratch_beg, ghcb_scratch_end;
|
||||
u64 scratch_gpa_beg, scratch_gpa_end;
|
||||
void *scratch_va;
|
||||
|
||||
if (WARN_ON_ONCE(!min_len))
|
||||
goto e_scratch;
|
||||
|
||||
scratch_gpa_beg = svm->sev_es.sw_scratch;
|
||||
if (!scratch_gpa_beg) {
|
||||
pr_err("vmgexit: scratch gpa not provided\n");
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
scratch_gpa_end = scratch_gpa_beg + min_len;
|
||||
scratch_gpa_end = scratch_gpa_beg + len;
|
||||
if (scratch_gpa_end < scratch_gpa_beg) {
|
||||
pr_err("vmgexit: scratch length (%#llx) not valid for scratch address (%#llx)\n",
|
||||
min_len, scratch_gpa_beg);
|
||||
len, scratch_gpa_beg);
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(svm->sev_es.ghcb_sa_sync || svm->sev_es.ghcb_sa_free);
|
||||
|
||||
if ((scratch_gpa_beg & PAGE_MASK) == control->ghcb_gpa) {
|
||||
/* Scratch area begins within GHCB */
|
||||
ghcb_scratch_beg = control->ghcb_gpa +
|
||||
|
|
@ -3710,29 +3702,21 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len)
|
|||
|
||||
scratch_va = (void *)svm->sev_es.ghcb;
|
||||
scratch_va += (scratch_gpa_beg - control->ghcb_gpa);
|
||||
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
svm->sev_es.ghcb_sa_len = ghcb_scratch_end - scratch_gpa_beg;
|
||||
} else {
|
||||
/* GHCB v2 requires the scratch area to be within the GHCB. */
|
||||
if (to_kvm_sev_info(svm->vcpu.kvm)->ghcb_version >= 2)
|
||||
goto e_scratch;
|
||||
|
||||
/*
|
||||
* The guest memory must be read into a kernel buffer, so
|
||||
* limit the size
|
||||
*/
|
||||
if (min_len > GHCB_SCRATCH_AREA_LIMIT) {
|
||||
if (len > GHCB_SCRATCH_AREA_LIMIT) {
|
||||
pr_err("vmgexit: scratch area exceeds KVM limits (%#llx requested, %#llx limit)\n",
|
||||
min_len, GHCB_SCRATCH_AREA_LIMIT);
|
||||
len, GHCB_SCRATCH_AREA_LIMIT);
|
||||
goto e_scratch;
|
||||
}
|
||||
scratch_va = kvzalloc(min_len, GFP_KERNEL_ACCOUNT);
|
||||
scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT);
|
||||
if (!scratch_va)
|
||||
return -ENOMEM;
|
||||
|
||||
if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, min_len)) {
|
||||
if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) {
|
||||
/* Unable to copy scratch area from guest */
|
||||
pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
|
||||
|
||||
|
|
@ -3748,10 +3732,11 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len)
|
|||
*/
|
||||
svm->sev_es.ghcb_sa_sync = sync;
|
||||
svm->sev_es.ghcb_sa_free = true;
|
||||
svm->sev_es.ghcb_sa_len = min_len;
|
||||
}
|
||||
|
||||
svm->sev_es.ghcb_sa = scratch_va;
|
||||
svm->sev_es.ghcb_sa_len = len;
|
||||
|
||||
return 0;
|
||||
|
||||
e_scratch:
|
||||
|
|
@ -3848,11 +3833,13 @@ struct psc_buffer {
|
|||
struct psc_entry entries[];
|
||||
} __packed;
|
||||
|
||||
static int snp_do_psc(struct vcpu_svm *svm);
|
||||
static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc);
|
||||
|
||||
static void snp_complete_psc(struct vcpu_svm *svm, u64 psc_ret)
|
||||
{
|
||||
memset(&svm->sev_es.psc, 0, sizeof(svm->sev_es.psc));
|
||||
svm->sev_es.psc_inflight = 0;
|
||||
svm->sev_es.psc_idx = 0;
|
||||
svm->sev_es.psc_2m = false;
|
||||
|
||||
/*
|
||||
* PSC requests always get a "no action" response in SW_EXITINFO1, with
|
||||
|
|
@ -3865,8 +3852,9 @@ static void snp_complete_psc(struct vcpu_svm *svm, u64 psc_ret)
|
|||
|
||||
static void __snp_complete_one_psc(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *guest_psc = sev_es->ghcb_sa;
|
||||
struct psc_buffer *psc = svm->sev_es.ghcb_sa;
|
||||
struct psc_entry *entries = psc->entries;
|
||||
struct psc_hdr *hdr = &psc->hdr;
|
||||
__u16 idx;
|
||||
|
||||
/*
|
||||
|
|
@ -3874,20 +3862,20 @@ static void __snp_complete_one_psc(struct vcpu_svm *svm)
|
|||
* corresponding entries in the guest's PSC buffer and zero out the
|
||||
* count of in-flight PSC entries.
|
||||
*/
|
||||
for (idx = sev_es->psc.cur_idx; sev_es->psc.batch_size;
|
||||
sev_es->psc.batch_size--, idx++) {
|
||||
struct psc_entry entry = READ_ONCE(guest_psc->entries[idx]);
|
||||
for (idx = svm->sev_es.psc_idx; svm->sev_es.psc_inflight;
|
||||
svm->sev_es.psc_inflight--, idx++) {
|
||||
struct psc_entry *entry = &entries[idx];
|
||||
|
||||
guest_psc->entries[idx].cur_page = entry.pagesize ? 512 : 1;
|
||||
entry->cur_page = entry->pagesize ? 512 : 1;
|
||||
}
|
||||
|
||||
sev_es->psc.cur_idx = idx;
|
||||
guest_psc->hdr.cur_entry = idx;
|
||||
hdr->cur_entry = idx;
|
||||
}
|
||||
|
||||
static int snp_complete_one_psc(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct psc_buffer *psc = svm->sev_es.ghcb_sa;
|
||||
|
||||
if (vcpu->run->hypercall.ret) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
|
|
@ -3897,30 +3885,48 @@ static int snp_complete_one_psc(struct kvm_vcpu *vcpu)
|
|||
__snp_complete_one_psc(svm);
|
||||
|
||||
/* Handle the next range (if any). */
|
||||
return snp_do_psc(svm);
|
||||
return snp_begin_psc(svm, psc);
|
||||
}
|
||||
|
||||
static int snp_do_psc(struct vcpu_svm *svm)
|
||||
static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc)
|
||||
{
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *guest_psc = sev_es->ghcb_sa;
|
||||
struct psc_entry *entries = psc->entries;
|
||||
struct kvm_vcpu *vcpu = &svm->vcpu;
|
||||
struct psc_hdr *hdr = &psc->hdr;
|
||||
struct psc_entry entry_start;
|
||||
u16 idx, idx_start, idx_end;
|
||||
int npages;
|
||||
bool huge;
|
||||
u64 gfn;
|
||||
u16 idx;
|
||||
|
||||
next_range:
|
||||
/* There should be no other PSCs in-flight at this point. */
|
||||
if (WARN_ON_ONCE(svm->sev_es.psc.batch_size)) {
|
||||
if (!user_exit_on_hypercall(vcpu->kvm, KVM_HC_MAP_GPA_RANGE)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
next_range:
|
||||
/* There should be no other PSCs in-flight at this point. */
|
||||
if (WARN_ON_ONCE(svm->sev_es.psc_inflight)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PSC descriptor buffer can be modified by a misbehaved guest after
|
||||
* validation, so take care to only use validated copies of values used
|
||||
* for things like array indexing.
|
||||
*/
|
||||
idx_start = hdr->cur_entry;
|
||||
idx_end = hdr->end_entry;
|
||||
|
||||
if (idx_end >= VMGEXIT_PSC_MAX_COUNT) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find the start of the next range which needs processing. */
|
||||
for (idx = sev_es->psc.cur_idx; idx <= sev_es->psc.end_idx; idx++) {
|
||||
entry_start = READ_ONCE(guest_psc->entries[idx]);
|
||||
for (idx = idx_start; idx <= idx_end; idx++, hdr->cur_entry++) {
|
||||
entry_start = entries[idx];
|
||||
|
||||
gfn = entry_start.gfn;
|
||||
huge = entry_start.pagesize;
|
||||
|
|
@ -3946,40 +3952,32 @@ next_range:
|
|||
|
||||
if (npages)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Increment the guest-visible index to communicate the current
|
||||
* entry back to the guest, e.g. in case of failure. No need
|
||||
* for READ_ONCE() as KVM doesn't consume the field, i.e. a
|
||||
* misbehaving guest can only break itself.
|
||||
*/
|
||||
guest_psc->hdr.cur_entry++;
|
||||
}
|
||||
|
||||
if (idx > sev_es->psc.end_idx) {
|
||||
if (idx > idx_end) {
|
||||
/* Nothing more to process. */
|
||||
snp_complete_psc(svm, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sev_es->psc.is_2m = huge;
|
||||
sev_es->psc.cur_idx = idx;
|
||||
sev_es->psc.batch_size = 1;
|
||||
svm->sev_es.psc_2m = huge;
|
||||
svm->sev_es.psc_idx = idx;
|
||||
svm->sev_es.psc_inflight = 1;
|
||||
|
||||
/*
|
||||
* Find all subsequent PSC entries that contain adjacent GPA
|
||||
* ranges/operations and can be combined into a single
|
||||
* KVM_HC_MAP_GPA_RANGE exit.
|
||||
*/
|
||||
while (++idx <= sev_es->psc.end_idx) {
|
||||
struct psc_entry entry = READ_ONCE(guest_psc->entries[idx]);
|
||||
while (++idx <= idx_end) {
|
||||
struct psc_entry entry = entries[idx];
|
||||
|
||||
if (entry.operation != entry_start.operation ||
|
||||
entry.gfn != entry_start.gfn + npages ||
|
||||
entry.cur_page || !!entry.pagesize != huge)
|
||||
break;
|
||||
|
||||
sev_es->psc.batch_size++;
|
||||
svm->sev_es.psc_inflight++;
|
||||
npages += huge ? 512 : 1;
|
||||
}
|
||||
|
||||
|
|
@ -4021,46 +4019,6 @@ next_range:
|
|||
BUG();
|
||||
}
|
||||
|
||||
static int snp_begin_psc(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *guest_psc = sev_es->ghcb_sa;
|
||||
u16 max_nr_entries;
|
||||
|
||||
if (!user_exit_on_hypercall(svm->vcpu.kvm, KVM_HC_MAP_GPA_RANGE)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* GHCB v2 requires the scratch area to reside within the GHCB itself,
|
||||
* and PSC requests are only supported for GHCB v2+. Thus it should be
|
||||
* impossible to exceed the max PSC entry count (which is derived from
|
||||
* the size of the shared GHCB buffer).
|
||||
*/
|
||||
max_nr_entries = (sev_es->ghcb_sa_len - sizeof(struct psc_hdr)) /
|
||||
sizeof(struct psc_entry);
|
||||
if (WARN_ON_ONCE(max_nr_entries > VMGEXIT_PSC_MAX_COUNT)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PSC descriptor buffer can be modified by a misbehaved guest after
|
||||
* validation, so take care to only use validated copies of values used
|
||||
* for things like array indexing.
|
||||
*/
|
||||
sev_es->psc.cur_idx = READ_ONCE(guest_psc->hdr.cur_entry);
|
||||
sev_es->psc.end_idx = READ_ONCE(guest_psc->hdr.end_entry);
|
||||
|
||||
if (sev_es->psc.end_idx >= max_nr_entries) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return snp_do_psc(svm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoked as part of svm_vcpu_reset() processing of an init event.
|
||||
*/
|
||||
|
|
@ -4535,22 +4493,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
|||
case SVM_VMGEXIT_MMIO_READ:
|
||||
case SVM_VMGEXIT_MMIO_WRITE: {
|
||||
bool is_write = control->exit_code == SVM_VMGEXIT_MMIO_WRITE;
|
||||
u64 len = control->exit_info_2;
|
||||
|
||||
if (!len)
|
||||
return 1;
|
||||
|
||||
if (to_kvm_sev_info(vcpu->kvm)->ghcb_version >= 2 && len > 8) {
|
||||
svm_vmgexit_bad_input(svm, GHCB_ERR_INVALID_INPUT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = setup_vmgexit_scratch(svm, !is_write, len);
|
||||
ret = setup_vmgexit_scratch(svm, !is_write, control->exit_info_2);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = kvm_sev_es_mmio(vcpu, is_write, control->exit_info_1, len,
|
||||
svm->sev_es.ghcb_sa);
|
||||
ret = kvm_sev_es_mmio(vcpu, is_write, control->exit_info_1,
|
||||
control->exit_info_2, svm->sev_es.ghcb_sa);
|
||||
break;
|
||||
}
|
||||
case SVM_VMGEXIT_NMI_COMPLETE:
|
||||
|
|
@ -4597,11 +4546,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
|||
vcpu->run->system_event.data[0] = control->ghcb_gpa;
|
||||
break;
|
||||
case SVM_VMGEXIT_PSC:
|
||||
ret = setup_vmgexit_scratch(svm, true, sizeof(struct psc_hdr));
|
||||
ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = snp_begin_psc(svm);
|
||||
ret = snp_begin_psc(svm, svm->sev_es.ghcb_sa);
|
||||
break;
|
||||
case SVM_VMGEXIT_AP_CREATION:
|
||||
ret = sev_snp_ap_creation(svm);
|
||||
|
|
@ -4623,11 +4572,6 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
|||
control->exit_info_1, control->exit_info_2);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case SVM_EXIT_IOIO:
|
||||
if (!((control->exit_info_1 & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT))
|
||||
return 1;
|
||||
|
||||
fallthrough;
|
||||
default:
|
||||
ret = svm_invoke_exit_handler(vcpu, control->exit_code);
|
||||
}
|
||||
|
|
@ -4648,9 +4592,6 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
|
|||
if (unlikely(check_mul_overflow(count, size, &bytes)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!bytes)
|
||||
return 1;
|
||||
|
||||
r = setup_vmgexit_scratch(svm, in, bytes);
|
||||
if (r)
|
||||
return r;
|
||||
|
|
|
|||
|
|
@ -257,12 +257,9 @@ struct vcpu_sev_es_state {
|
|||
bool ghcb_sa_free;
|
||||
|
||||
/* SNP Page-State-Change buffer entries currently being processed */
|
||||
struct {
|
||||
u16 cur_idx;
|
||||
u16 end_idx;
|
||||
u16 batch_size;
|
||||
bool is_2m;
|
||||
} psc;
|
||||
u16 psc_idx;
|
||||
u16 psc_inflight;
|
||||
bool psc_2m;
|
||||
|
||||
u64 ghcb_registered_gpa;
|
||||
|
||||
|
|
|
|||
|
|
@ -5227,13 +5227,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|||
* On a host with synchronized TSC, there is no need to update
|
||||
* kvmclock on vcpu->cpu migration
|
||||
*/
|
||||
if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1) {
|
||||
if (__ratelimit(&vcpu->kvm->arch.kvmclock_update_rs))
|
||||
kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
|
||||
else
|
||||
kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
|
||||
}
|
||||
|
||||
if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1)
|
||||
kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
|
||||
if (vcpu->cpu != cpu)
|
||||
kvm_make_request(KVM_REQ_MIGRATE_TIMER, vcpu);
|
||||
vcpu->cpu = cpu;
|
||||
|
|
@ -13371,8 +13366,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||
raw_spin_lock_init(&kvm->arch.tsc_write_lock);
|
||||
mutex_init(&kvm->arch.apic_map_lock);
|
||||
seqcount_raw_spinlock_init(&kvm->arch.pvclock_sc, &kvm->arch.tsc_write_lock);
|
||||
ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10);
|
||||
ratelimit_set_flags(&kvm->arch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEASE);
|
||||
kvm->arch.kvmclock_offset = -get_kvmclock_base_ns();
|
||||
|
||||
raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
|
||||
|
|
@ -14330,7 +14323,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
|
|||
* the RAP (Return Address Predicator).
|
||||
*/
|
||||
if (guest_cpu_cap_has(vcpu, X86_FEATURE_ERAPS))
|
||||
kvm_register_mark_dirty(vcpu, VCPU_EXREG_ERAPS);
|
||||
kvm_register_is_dirty(vcpu, VCPU_EXREG_ERAPS);
|
||||
|
||||
kvm_invalidate_pcid(vcpu, operand.pcid);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
|
|
|
|||
|
|
@ -49,20 +49,7 @@ static void x86_virt_invoke_kvm_emergency_callback(void)
|
|||
{
|
||||
cpu_emergency_virt_cb *kvm_callback;
|
||||
|
||||
/*
|
||||
* RCU may not be watching the crashing CPU here, so rcu_dereference()
|
||||
* triggers a suspicious-RCU-usage splat. In principle, a concurrent
|
||||
* KVM module unload could race with this read; see commit 2baa33a8ddd6
|
||||
* ("KVM: x86: Leave user-return notifier registered on reboot/shutdown")
|
||||
* which notes that nothing prevents module unload during panic/reboot.
|
||||
*
|
||||
* However, taking a lock here would be riskier than the current race:
|
||||
* the system is going down via NMI shootdown, and any lock could be
|
||||
* held by an already-stopped CPU. Use rcu_dereference_raw() to silence
|
||||
* the lockdep splat and accept the comically small remaining race;
|
||||
* panic context inherently cannot guarantee complete correctness.
|
||||
*/
|
||||
kvm_callback = rcu_dereference_raw(kvm_emergency_callback);
|
||||
kvm_callback = rcu_dereference(kvm_emergency_callback);
|
||||
if (kvm_callback)
|
||||
kvm_callback();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3246,7 +3246,7 @@ queue_exit:
|
|||
if (!rq)
|
||||
blk_queue_exit(q);
|
||||
else
|
||||
rq_list_add_head(&plug->cached_rqs, rq);
|
||||
blk_mq_free_request(rq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_MQ_STACKING
|
||||
|
|
|
|||
|
|
@ -511,11 +511,6 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!xdna->group) {
|
||||
XDNA_ERR(xdna, "Running without IOMMU not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL);
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
/* Copyright 2025 Arm, Ltd. */
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/ethosu_accel.h>
|
||||
|
|
@ -164,30 +163,17 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
|
|||
s8 mode = dma_st->mode;
|
||||
u64 len = dma->len;
|
||||
|
||||
if (len == U64_MAX)
|
||||
return U64_MAX;
|
||||
|
||||
if (mode >= 1) {
|
||||
if (dma->stride[0] < 0 && (u64)(-dma->stride[0]) > len)
|
||||
return U64_MAX;
|
||||
len += dma->stride[0];
|
||||
if (check_mul_overflow(len, (u64)dma_st->size0, &len))
|
||||
return U64_MAX;
|
||||
len *= dma_st->size0;
|
||||
}
|
||||
if (mode == 2) {
|
||||
if (dma->stride[1] < 0 && (u64)(-dma->stride[1]) > len)
|
||||
return U64_MAX;
|
||||
len += dma->stride[1];
|
||||
if (check_mul_overflow(len, (u64)dma_st->size1, &len))
|
||||
return U64_MAX;
|
||||
}
|
||||
if (dma->region >= 0) {
|
||||
u64 end;
|
||||
|
||||
if (check_add_overflow(len, dma->offset, &end))
|
||||
return U64_MAX;
|
||||
info->region_size[dma->region] = max(info->region_size[dma->region], end);
|
||||
len *= dma_st->size1;
|
||||
}
|
||||
if (dma->region >= 0)
|
||||
info->region_size[dma->region] = max(info->region_size[dma->region],
|
||||
len + dma->offset);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
@ -401,8 +387,6 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return -EFAULT;
|
||||
|
||||
i++;
|
||||
if (i >= size / 4)
|
||||
return -EINVAL;
|
||||
bocmds[i] = cmds[1];
|
||||
addr = cmd_to_addr(cmds);
|
||||
}
|
||||
|
|
@ -411,8 +395,6 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
case NPU_OP_DMA_START:
|
||||
srclen = dma_length(info, &st.dma, &st.dma.src);
|
||||
dstlen = dma_length(info, &st.dma, &st.dma.dst);
|
||||
if (srclen == U64_MAX || dstlen == U64_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (st.dma.dst.region >= 0)
|
||||
info->output_region[st.dma.dst.region] = true;
|
||||
|
|
@ -449,7 +431,8 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return ret;
|
||||
break;
|
||||
case NPU_OP_RESIZE: // U85 only
|
||||
return -EINVAL;
|
||||
WARN_ON(1); // TODO
|
||||
break;
|
||||
case NPU_SET_KERNEL_WIDTH_M1:
|
||||
st.ifm.width = param;
|
||||
break;
|
||||
|
|
@ -481,7 +464,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
st.ifm.broadcast = param;
|
||||
break;
|
||||
case NPU_SET_IFM_REGION:
|
||||
st.ifm.region = param & 0x7;
|
||||
st.ifm.region = param & 0x7f;
|
||||
break;
|
||||
case NPU_SET_IFM_WIDTH0_M1:
|
||||
st.ifm.width0 = param;
|
||||
|
|
@ -616,7 +599,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
if (ethosu_is_u65(edev))
|
||||
st.scale[1].length = cmds[1];
|
||||
else
|
||||
st.weight[2].length = cmds[1];
|
||||
st.weight[1].length = cmds[1];
|
||||
break;
|
||||
case NPU_SET_WEIGHT3_BASE:
|
||||
st.weight[3].base = addr;
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ priority_bands_fops_write(struct file *file, const char __user *user_buf, size_t
|
|||
u32 band;
|
||||
int ret;
|
||||
|
||||
if (*pos != 0 || size >= sizeof(buf))
|
||||
if (size >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, pos, user_buf, size);
|
||||
|
|
|
|||
|
|
@ -259,22 +259,6 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!PAGE_ALIGNED(runtime_addr)) {
|
||||
ivpu_err(vdev, "Runtime address 0x%llx not page aligned\n", runtime_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!PAGE_ALIGNED(runtime_size)) {
|
||||
ivpu_err(vdev, "Runtime size %llu not page aligned\n", runtime_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (runtime_size < image_size) {
|
||||
ivpu_err(vdev, "Runtime size too small: %llu, image size: %llu\n",
|
||||
runtime_size, image_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!ivpu_is_within_range(image_load_addr, image_size, &vdev->hw->ranges.runtime)) {
|
||||
ivpu_err(vdev, "Invalid firmware load address: 0x%llx and size %llu\n",
|
||||
image_load_addr, image_size);
|
||||
|
|
|
|||
|
|
@ -98,11 +98,6 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
|
|||
u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0;
|
||||
u32 log_end = READ_ONCE(log->write_index);
|
||||
|
||||
if (log_start >= data_size)
|
||||
log_start = 0;
|
||||
if (log_end > data_size)
|
||||
log_end = data_size;
|
||||
|
||||
if (log->wrap_count == log->read_wrap_count) {
|
||||
if (log_end <= log_start) {
|
||||
drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name);
|
||||
|
|
|
|||
|
|
@ -291,13 +291,6 @@ int ivpu_ms_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *
|
|||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (info_size > ivpu_bo_size(bo)) {
|
||||
ivpu_warn_ratelimited(vdev, "MS info overflow: %#llx > %#zx\n",
|
||||
info_size, ivpu_bo_size(bo));
|
||||
ret = -EOVERFLOW;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (args->buffer_size < info_size) {
|
||||
ret = -ENOSPC;
|
||||
goto unlock;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *
|
|||
rkt_obj->size = args->size;
|
||||
rkt_obj->offset = 0;
|
||||
|
||||
ret = drm_gem_handle_create(file, gem_obj, &args->handle);
|
||||
drm_gem_object_put(gem_obj);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
sgt = drm_gem_shmem_get_pages_sgt(shmem_obj);
|
||||
if (IS_ERR(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
|
|
@ -90,8 +95,6 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *
|
|||
rkt_obj->size, PAGE_SIZE,
|
||||
0, 0);
|
||||
mutex_unlock(&rocket_priv->mm_lock);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = iommu_map_sgtable(rocket_priv->domain->domain,
|
||||
rkt_obj->mm.start,
|
||||
|
|
@ -109,18 +112,8 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *
|
|||
args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
|
||||
args->dma_address = rkt_obj->mm.start;
|
||||
|
||||
ret = drm_gem_handle_create(file, gem_obj, &args->handle);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
drm_gem_object_put(gem_obj);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
iommu_unmap(rocket_priv->domain->domain,
|
||||
rkt_obj->mm.start, rkt_obj->size);
|
||||
|
||||
err_remove_node:
|
||||
mutex_lock(&rocket_priv->mm_lock);
|
||||
drm_mm_remove_node(&rkt_obj->mm);
|
||||
|
|
|
|||
|
|
@ -78,22 +78,18 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
|
|||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enable_gpe_cond
|
||||
* FUNCTION: acpi_enable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* dispatch_type - GPE dispatch type to match
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Add a reference to a GPE so long as its dispatch type matches
|
||||
* the supplied one, or it is different from ACPI_GPE_DISPATCH_NONE
|
||||
* if the supplied one is ACPI_GPE_DISPATCH_MASK. On the first
|
||||
* reference, the GPE is hardware-enabled.
|
||||
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
|
||||
* hardware-enabled.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_enable_gpe_cond(acpi_handle gpe_device, u32 gpe_number,
|
||||
u8 dispatch_type)
|
||||
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
|
||||
{
|
||||
acpi_status status = AE_BAD_PARAMETER;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
|
@ -104,18 +100,14 @@ acpi_status acpi_enable_gpe_cond(acpi_handle gpe_device, u32 gpe_number,
|
|||
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
|
||||
|
||||
/*
|
||||
* Ensure that we have a valid GPE number and that the dispatch type of
|
||||
* the GPE matches the supplied one (or it is not ACPI_GPE_DISPATCH_NONE
|
||||
* if the supplied one is ACPI_GPE_DISPATCH_MASK).
|
||||
* Ensure that we have a valid GPE number and that there is some way
|
||||
* of handling the GPE (handler or a GPE method). In other words, we
|
||||
* won't allow a valid GPE to be enabled if there is no way to handle it.
|
||||
*/
|
||||
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
|
||||
if (gpe_event_info) {
|
||||
if (dispatch_type == ACPI_GPE_DISPATCH_MASK)
|
||||
dispatch_type = ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags);
|
||||
else if (dispatch_type != ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags))
|
||||
dispatch_type = ACPI_GPE_DISPATCH_NONE;
|
||||
|
||||
if (dispatch_type != ACPI_GPE_DISPATCH_NONE) {
|
||||
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
|
||||
ACPI_GPE_DISPATCH_NONE) {
|
||||
status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE);
|
||||
if (ACPI_SUCCESS(status) &&
|
||||
ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
|
||||
|
|
@ -136,30 +128,6 @@ acpi_status acpi_enable_gpe_cond(acpi_handle gpe_device, u32 gpe_number,
|
|||
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
ACPI_EXPORT_SYMBOL(acpi_enable_gpe_cond)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
|
||||
* gpe_number - GPE level within the GPE block
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
|
||||
* hardware-enabled.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
|
||||
{
|
||||
/*
|
||||
* Ensure that there is some way of handling the GPE (handler or a GPE
|
||||
* method). In other words, we won't allow a valid GPE to be enabled if
|
||||
* there is no way to handle it.
|
||||
*/
|
||||
return acpi_enable_gpe_cond(gpe_device, gpe_number, ACPI_GPE_DISPATCH_MASK);
|
||||
}
|
||||
ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ struct acpi_button {
|
|||
ktime_t last_time;
|
||||
bool suspended;
|
||||
bool lid_state_initialized;
|
||||
bool gpe_enabled;
|
||||
};
|
||||
|
||||
static struct acpi_device *lid_device;
|
||||
|
|
@ -647,21 +646,6 @@ static int acpi_button_probe(struct platform_device *pdev)
|
|||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY, handler,
|
||||
button);
|
||||
if (ACPI_SUCCESS(status) && device->wakeup.flags.valid) {
|
||||
acpi_status st;
|
||||
|
||||
/*
|
||||
* If the wakeup GPE has a handler method, enable it in
|
||||
* case it is also used for signaling runtime events.
|
||||
*/
|
||||
st = acpi_enable_gpe_cond(device->wakeup.gpe_device,
|
||||
device->wakeup.gpe_number,
|
||||
ACPI_GPE_DISPATCH_METHOD);
|
||||
button->gpe_enabled = ACPI_SUCCESS(st);
|
||||
if (button->gpe_enabled)
|
||||
dev_dbg(button->dev, "Enabled ACPI GPE%02llx\n",
|
||||
device->wakeup.gpe_number);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
|
@ -687,7 +671,6 @@ err_remove_fs:
|
|||
acpi_button_remove_fs(button);
|
||||
err_free_button:
|
||||
kfree(button);
|
||||
memset(acpi_device_class(device), 0, sizeof(acpi_device_class));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -706,13 +689,7 @@ static void acpi_button_remove(struct platform_device *pdev)
|
|||
acpi_button_event);
|
||||
break;
|
||||
default:
|
||||
if (button->gpe_enabled) {
|
||||
dev_dbg(button->dev, "Disabling ACPI GPE%02llx\n",
|
||||
adev->wakeup.gpe_number);
|
||||
acpi_disable_gpe(adev->wakeup.gpe_device,
|
||||
adev->wakeup.gpe_number);
|
||||
}
|
||||
acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
|
||||
acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
|
||||
button->type == ACPI_BUTTON_TYPE_LID ?
|
||||
acpi_lid_notify :
|
||||
acpi_button_notify);
|
||||
|
|
|
|||
|
|
@ -157,14 +157,6 @@ impl Allocation {
|
|||
self.get_or_init_info().target_node = Some(target_node);
|
||||
}
|
||||
|
||||
pub(crate) fn take_oneway_node(&mut self) -> Option<DArc<Node>> {
|
||||
if let Some(info) = self.allocation_info.as_mut() {
|
||||
info.oneway_node.take()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Reserve enough space to push at least `num_fds` fds.
|
||||
pub(crate) fn info_add_fd_reserve(&mut self, num_fds: usize) -> Result {
|
||||
self.get_or_init_info()
|
||||
|
|
|
|||
|
|
@ -1402,12 +1402,7 @@ impl Process {
|
|||
// Clear delivered_deaths list.
|
||||
//
|
||||
// Scope ensures that MutexGuard is dropped while executing the body.
|
||||
while let Some(delivered_death) = {
|
||||
// Explicitly bind to avoid tail expression lifetime extension of the lockguard
|
||||
// Can be removed when the kernel moves to edition 2024
|
||||
let maybe_death = self.inner.lock().delivered_deaths.pop_front();
|
||||
maybe_death
|
||||
} {
|
||||
while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } {
|
||||
drop(delivered_death);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,8 +270,7 @@ impl Transaction {
|
|||
/// Not used for replies.
|
||||
pub(crate) fn submit(self: DLArc<Self>, info: &mut TransactionInfo) -> BinderResult {
|
||||
// Defined before `process_inner` so that the destructor runs after releasing the lock.
|
||||
let _t_outdated;
|
||||
let _oneway_node;
|
||||
let mut _t_outdated;
|
||||
|
||||
let oneway = self.flags & TF_ONE_WAY != 0;
|
||||
let process = self.to.clone();
|
||||
|
|
@ -288,14 +287,6 @@ impl Transaction {
|
|||
if let Some(t_outdated) =
|
||||
target_node.take_outdated_transaction(&self, &mut process_inner)
|
||||
{
|
||||
let mut alloc_guard = t_outdated.allocation.lock();
|
||||
if let Some(alloc) = (*alloc_guard).as_mut() {
|
||||
// Take the oneway node to prevent `Allocation::drop` from calling
|
||||
// `pending_oneway_finished()`, which would be incorrect as this
|
||||
// transaction is not being submitted.
|
||||
_oneway_node = alloc.take_oneway_node();
|
||||
}
|
||||
drop(alloc_guard);
|
||||
// Save the transaction to be dropped after locks are released.
|
||||
_t_outdated = t_outdated;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ config PANEL_CHANGE_MESSAGE
|
|||
say 'N' and keep the default message with the version.
|
||||
|
||||
config PANEL_BOOT_MESSAGE
|
||||
depends on PANEL_CHANGE_MESSAGE
|
||||
depends on PANEL_CHANGE_MESSAGE="y"
|
||||
string "New initialization message"
|
||||
default ""
|
||||
help
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ static int linedisp_display(struct linedisp *linedisp, const char *msg,
|
|||
count = strlen(msg);
|
||||
|
||||
/* if the string ends with a newline, trim it */
|
||||
if (count && msg[count - 1] == '\n')
|
||||
if (msg[count - 1] == '\n')
|
||||
count--;
|
||||
|
||||
if (!count) {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,10 @@ static const struct linedisp_ops max6959_linedisp_ops = {
|
|||
|
||||
static int max6959_enable(struct max6959_priv *priv, bool enable)
|
||||
{
|
||||
return regmap_assign_bits(priv->regmap, REG_CONFIGURATION, REG_CONFIGURATION_S_BIT, enable);
|
||||
u8 mask = REG_CONFIGURATION_S_BIT;
|
||||
u8 value = enable ? mask : 0;
|
||||
|
||||
return regmap_update_bits(priv->regmap, REG_CONFIGURATION, mask, value);
|
||||
}
|
||||
|
||||
static void max6959_power_off(void *priv)
|
||||
|
|
|
|||
|
|
@ -3257,9 +3257,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
|||
*change = false;
|
||||
|
||||
if (regmap_volatile(map, reg) && map->reg_update_bits) {
|
||||
if (map->cache_only)
|
||||
return -EBUSY;
|
||||
|
||||
reg = regmap_reg_addr(map, reg);
|
||||
ret = map->reg_update_bits(map->bus_context, reg, mask, val);
|
||||
if (ret == 0 && change)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/part_stat.h>
|
||||
#include <linux/kernel_read_file.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include "zram_drv.h"
|
||||
|
||||
|
|
@ -505,7 +504,6 @@ struct zram_wb_ctl {
|
|||
wait_queue_head_t done_wait;
|
||||
spinlock_t done_lock;
|
||||
atomic_t num_inflight;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
struct zram_wb_req {
|
||||
|
|
@ -849,7 +847,7 @@ static void release_wb_ctl(struct zram_wb_ctl *wb_ctl)
|
|||
release_wb_req(req);
|
||||
}
|
||||
|
||||
kfree_rcu(wb_ctl, rcu);
|
||||
kfree(wb_ctl);
|
||||
}
|
||||
|
||||
static struct zram_wb_ctl *init_wb_ctl(struct zram *zram)
|
||||
|
|
@ -966,13 +964,11 @@ static void zram_writeback_endio(struct bio *bio)
|
|||
struct zram_wb_ctl *wb_ctl = bio->bi_private;
|
||||
unsigned long flags;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_irqsave(&wb_ctl->done_lock, flags);
|
||||
list_add(&req->entry, &wb_ctl->done_reqs);
|
||||
spin_unlock_irqrestore(&wb_ctl->done_lock, flags);
|
||||
|
||||
wake_up(&wb_ctl->done_wait);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void zram_submit_wb_request(struct zram *zram,
|
||||
|
|
|
|||
|
|
@ -3540,13 +3540,7 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
|
|||
"firmware rome 0x%x build 0x%x",
|
||||
rver_rom, rver_patch, ver_rom, ver_patch);
|
||||
|
||||
/* Allow rampatch when the patch version equals the firmware version.
|
||||
* A firmware download may be aborted by a transient USB error (e.g.
|
||||
* disconnect) after the controller updates version info but before
|
||||
* completion.
|
||||
* Allowing equal versions enables re-flashing during recovery.
|
||||
*/
|
||||
if (rver_rom != ver_rom || rver_patch < ver_patch) {
|
||||
if (rver_rom != ver_rom || rver_patch <= ver_patch) {
|
||||
bt_dev_err(hdev, "rampatch file version did not match with firmware");
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -1680,8 +1680,8 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
|
|||
mod_timer(&qca->tx_idle_timer, jiffies +
|
||||
msecs_to_jiffies(qca->tx_idle_delay));
|
||||
|
||||
/* Wait for the controller to load the rampatch and NVM. */
|
||||
msleep(100);
|
||||
/* Controller reset completion time is 50ms */
|
||||
msleep(50);
|
||||
|
||||
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
|
||||
clear_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
|
|
|
|||
|
|
@ -274,7 +274,6 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
|
|||
/* Step 2a : make sure trigger sources are unique */
|
||||
|
||||
err |= comedi_check_trigger_is_unique(cmd->convert_src);
|
||||
err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
|
||||
err |= comedi_check_trigger_is_unique(cmd->stop_src);
|
||||
|
||||
/* Step 2b : and mutually compatible */
|
||||
|
|
@ -325,10 +324,10 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
|
|||
arg = min(arg,
|
||||
rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC));
|
||||
arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC);
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
if (cmd->scan_begin_arg == TRIG_TIMER) {
|
||||
/* limit convert_arg to keep scan_begin_arg in range */
|
||||
limit = UINT_MAX / cmd->scan_end_arg;
|
||||
limit = rounddown(limit, (unsigned int)NSEC_PER_USEC);
|
||||
limit = rounddown(limit, (unsigned int)NSEC_PER_SEC);
|
||||
arg = min(arg, limit);
|
||||
}
|
||||
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
|
|
|
|||
|
|
@ -124,8 +124,7 @@ struct counter_device *counter_alloc(size_t sizeof_priv)
|
|||
|
||||
err_dev_set_name:
|
||||
|
||||
put_device(dev);
|
||||
return NULL;
|
||||
counter_chrdev_remove(counter);
|
||||
err_chrdev_add:
|
||||
|
||||
ida_free(&counter_ida, dev->id);
|
||||
|
|
|
|||
|
|
@ -302,6 +302,12 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
cpufreq_cpu_put(policy);
|
||||
policy = NULL;
|
||||
|
||||
/* disable dynamic EPP before running test */
|
||||
if (cpudata->dynamic_epp) {
|
||||
pr_debug("Dynamic EPP is enabled, disabling it\n");
|
||||
amd_pstate_clear_dynamic_epp(policy);
|
||||
}
|
||||
|
||||
buf = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
|
@ -321,16 +327,6 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
orig_policy = cpudata->policy;
|
||||
cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
|
||||
/*
|
||||
* Disable dynamic EPP before running test. If "orig_dynamic_epp" is
|
||||
* true, the driver will do a redundant switch at the end and there
|
||||
* is no need for enabling it again at the end of the test.
|
||||
*/
|
||||
if (cpudata->dynamic_epp) {
|
||||
pr_debug("Dynamic EPP is enabled, disabling it\n");
|
||||
amd_pstate_clear_dynamic_epp(policy);
|
||||
}
|
||||
|
||||
for (epp = 0; epp <= U8_MAX; epp++) {
|
||||
u8 val;
|
||||
|
||||
|
|
|
|||
|
|
@ -792,13 +792,9 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags)
|
|||
if (!dmabuf || !dmabuf->file)
|
||||
return -EINVAL;
|
||||
|
||||
fd = get_unused_fd_flags(flags);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
fd = FD_ADD(flags, dmabuf->file);
|
||||
DMA_BUF_TRACE(trace_dma_buf_fd, dmabuf, fd);
|
||||
|
||||
fd_install(fd, dmabuf->file);
|
||||
return fd;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF");
|
||||
|
|
|
|||
|
|
@ -829,21 +829,12 @@ int dpll_device_delete_ntf(struct dpll_device *dpll)
|
|||
return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll);
|
||||
}
|
||||
|
||||
/**
|
||||
* __dpll_device_change_ntf - notify that the dpll device has been changed
|
||||
* @dpll: registered dpll pointer
|
||||
*
|
||||
* Context: caller must hold dpll_lock. Suitable for use inside device
|
||||
* callbacks which are already invoked under dpll_lock.
|
||||
* Return: 0 if succeeds, error code otherwise.
|
||||
*/
|
||||
int __dpll_device_change_ntf(struct dpll_device *dpll)
|
||||
static int
|
||||
__dpll_device_change_ntf(struct dpll_device *dpll)
|
||||
{
|
||||
lockdep_assert_held(&dpll_lock);
|
||||
dpll_device_notify(dpll, DPLL_DEVICE_CHANGED);
|
||||
return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dpll_device_change_ntf);
|
||||
|
||||
/**
|
||||
* dpll_device_change_ntf - notify that the dpll device has been changed
|
||||
|
|
|
|||
|
|
@ -762,15 +762,18 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
|
|||
dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
|
||||
/* Update measured input reference frequencies if frequency
|
||||
* monitoring is enabled.
|
||||
/* Update measured input reference frequencies if any DPLL has
|
||||
* frequency monitoring enabled.
|
||||
*/
|
||||
if (zldev->freq_monitor) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to update measured frequencies: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
list_for_each_entry(zldpll, &zldev->dplls, list) {
|
||||
if (zldpll->freq_monitor) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to update measured frequencies: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update references' fractional frequency offsets */
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ struct zl3073x_chip_info {
|
|||
* @work: periodic work
|
||||
* @clock_id: clock id of the device
|
||||
* @phase_avg_factor: phase offset measurement averaging factor
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
*/
|
||||
struct zl3073x_dev {
|
||||
struct device *dev;
|
||||
|
|
@ -78,10 +77,9 @@ struct zl3073x_dev {
|
|||
struct kthread_worker *kworker;
|
||||
struct kthread_delayed_work work;
|
||||
|
||||
/* Per-chip parameters */
|
||||
/* Devlink parameters */
|
||||
u64 clock_id;
|
||||
u8 phase_avg_factor;
|
||||
bool freq_monitor;
|
||||
};
|
||||
|
||||
extern const struct regmap_config zl3073x_regmap_config;
|
||||
|
|
|
|||
|
|
@ -1079,6 +1079,15 @@ zl3073x_dpll_phase_offset_avg_factor_get(const struct dpll_device *dpll,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
zl3073x_dpll_change_work(struct work_struct *work)
|
||||
{
|
||||
struct zl3073x_dpll *zldpll;
|
||||
|
||||
zldpll = container_of(work, struct zl3073x_dpll, change_work);
|
||||
dpll_device_change_ntf(zldpll->dpll_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
|
||||
void *dpll_priv, u32 factor,
|
||||
|
|
@ -1104,10 +1113,8 @@ zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
|
|||
* we have to send a notification for other DPLL devices.
|
||||
*/
|
||||
list_for_each_entry(item, &zldpll->dev->dplls, list) {
|
||||
struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);
|
||||
|
||||
if (item != zldpll && dpll_dev)
|
||||
__dpll_device_change_ntf(dpll_dev);
|
||||
if (item != zldpll)
|
||||
schedule_work(&item->change_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1212,7 +1219,7 @@ zl3073x_dpll_freq_monitor_get(const struct dpll_device *dpll,
|
|||
{
|
||||
struct zl3073x_dpll *zldpll = dpll_priv;
|
||||
|
||||
if (zldpll->dev->freq_monitor)
|
||||
if (zldpll->freq_monitor)
|
||||
*state = DPLL_FEATURE_STATE_ENABLE;
|
||||
else
|
||||
*state = DPLL_FEATURE_STATE_DISABLE;
|
||||
|
|
@ -1226,19 +1233,9 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
|
|||
enum dpll_feature_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_dpll *item, *zldpll = dpll_priv;
|
||||
struct zl3073x_dpll *zldpll = dpll_priv;
|
||||
|
||||
zldpll->dev->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
|
||||
|
||||
/* The frequency monitoring is common for all DPLL channels so after
|
||||
* change we have to send a notification for other DPLL devices.
|
||||
*/
|
||||
list_for_each_entry(item, &zldpll->dev->dplls, list) {
|
||||
struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);
|
||||
|
||||
if (item != zldpll && dpll_dev)
|
||||
__dpll_device_change_ntf(dpll_dev);
|
||||
}
|
||||
zldpll->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1630,13 +1627,13 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll)
|
|||
static void
|
||||
zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll)
|
||||
{
|
||||
struct dpll_device *dpll_dev = READ_ONCE(zldpll->dpll_dev);
|
||||
WARN(!zldpll->dpll_dev, "DPLL device is not registered\n");
|
||||
|
||||
WARN(!dpll_dev, "DPLL device is not registered\n");
|
||||
cancel_work_sync(&zldpll->change_work);
|
||||
|
||||
WRITE_ONCE(zldpll->dpll_dev, NULL);
|
||||
dpll_device_unregister(dpll_dev, &zldpll->ops, zldpll);
|
||||
dpll_device_put(dpll_dev, &zldpll->tracker);
|
||||
dpll_device_unregister(zldpll->dpll_dev, &zldpll->ops, zldpll);
|
||||
dpll_device_put(zldpll->dpll_dev, &zldpll->tracker);
|
||||
zldpll->dpll_dev = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1755,7 +1752,7 @@ zl3073x_dpll_pin_measured_freq_check(struct zl3073x_dpll_pin *pin)
|
|||
u8 ref_id;
|
||||
u32 freq;
|
||||
|
||||
if (!zldpll->dev->freq_monitor)
|
||||
if (!zldpll->freq_monitor)
|
||||
return false;
|
||||
|
||||
ref_id = zl3073x_input_pin_ref_get(pin->id);
|
||||
|
|
@ -1788,8 +1785,10 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
|
|||
struct zl3073x_dev *zldev = zldpll->dev;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct device *dev = zldev->dev;
|
||||
const struct zl3073x_chan *chan;
|
||||
struct zl3073x_dpll_pin *pin;
|
||||
int rc;
|
||||
u8 mode;
|
||||
|
||||
zldpll->check_count++;
|
||||
|
||||
|
|
@ -1808,6 +1807,15 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
|
|||
dpll_device_change_ntf(zldpll->dpll_dev);
|
||||
}
|
||||
|
||||
/* Input pin monitoring does make sense only in automatic
|
||||
* or forced reference modes.
|
||||
*/
|
||||
chan = zl3073x_chan_state_get(zldev, zldpll->id);
|
||||
mode = zl3073x_chan_mode_get(chan);
|
||||
if (mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
|
||||
mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK)
|
||||
return;
|
||||
|
||||
/* Update phase offset latch registers for this DPLL if the phase
|
||||
* offset monitor feature is enabled.
|
||||
*/
|
||||
|
|
@ -1918,6 +1926,7 @@ zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch)
|
|||
zldpll->dev = zldev;
|
||||
zldpll->id = ch;
|
||||
INIT_LIST_HEAD(&zldpll->pins);
|
||||
INIT_WORK(&zldpll->change_work, zl3073x_dpll_change_work);
|
||||
|
||||
return zldpll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@
|
|||
* @id: DPLL index
|
||||
* @check_count: periodic check counter
|
||||
* @phase_monitor: is phase offset monitor enabled
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
* @ops: DPLL device operations for this instance
|
||||
* @dpll_dev: pointer to registered DPLL device
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @lock_status: last saved DPLL lock status
|
||||
* @pins: list of pins
|
||||
* @change_work: device change notification work
|
||||
*/
|
||||
struct zl3073x_dpll {
|
||||
struct list_head list;
|
||||
|
|
@ -27,11 +29,13 @@ struct zl3073x_dpll {
|
|||
u8 id;
|
||||
u8 check_count;
|
||||
bool phase_monitor;
|
||||
bool freq_monitor;
|
||||
struct dpll_device_ops ops;
|
||||
struct dpll_device *dpll_dev;
|
||||
dpll_tracker tracker;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct list_head pins;
|
||||
struct work_struct change_work;
|
||||
};
|
||||
|
||||
struct zl3073x_dpll *zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch);
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ static void acpm_dvfs_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
|
|||
if (response) {
|
||||
xfer->rxcnt = cmdlen;
|
||||
xfer->rxd = cmd;
|
||||
} else {
|
||||
xfer->rxcnt = 0;
|
||||
xfer->rxd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,11 @@
|
|||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/find.h>
|
||||
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
|
@ -105,15 +104,12 @@ struct acpm_queue {
|
|||
*
|
||||
* @cmd: pointer to where the data shall be saved.
|
||||
* @n_cmd: number of 32-bit commands.
|
||||
* @rxcnt: expected length of the response in 32-bit words.
|
||||
* @completed: flag indicating if the firmware response has been fully
|
||||
* processed.
|
||||
* @response: true if the client expects the RX data.
|
||||
*/
|
||||
struct acpm_rx_data {
|
||||
u32 *cmd;
|
||||
size_t n_cmd;
|
||||
size_t rxcnt;
|
||||
bool completed;
|
||||
bool response;
|
||||
};
|
||||
|
||||
#define ACPM_SEQNUM_MAX 64
|
||||
|
|
@ -203,33 +199,31 @@ static void acpm_get_saved_rx(struct acpm_chan *achan,
|
|||
const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];
|
||||
u32 rx_seqnum;
|
||||
|
||||
if (!rx_data->rxcnt)
|
||||
if (!rx_data->response)
|
||||
return;
|
||||
|
||||
rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
|
||||
|
||||
if (rx_seqnum == tx_seqnum)
|
||||
if (rx_seqnum == tx_seqnum) {
|
||||
memcpy(xfer->rxd, rx_data->cmd, xfer->rxcnt * sizeof(*xfer->rxd));
|
||||
clear_bit(rx_seqnum - 1, achan->bitmap_seqnum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acpm_get_rx() - get response from RX queue.
|
||||
* @achan: ACPM channel info.
|
||||
* @xfer: reference to the transfer to get response for.
|
||||
* @native_match: pointer to a boolean set to true if the thread natively
|
||||
* processed its own sequence number during this call.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
|
||||
bool *native_match)
|
||||
static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
|
||||
{
|
||||
u32 rx_front, rx_seqnum, tx_seqnum, seqnum;
|
||||
const void __iomem *base, *addr;
|
||||
struct acpm_rx_data *rx_data;
|
||||
u32 i, val, mlen;
|
||||
|
||||
*native_match = false;
|
||||
bool rx_set = false;
|
||||
|
||||
guard(mutex)(&achan->rx_lock);
|
||||
|
||||
|
|
@ -238,8 +232,10 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
|
|||
|
||||
tx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);
|
||||
|
||||
if (i == rx_front)
|
||||
if (i == rx_front) {
|
||||
acpm_get_saved_rx(achan, xfer, tx_seqnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
base = achan->rx.base;
|
||||
mlen = achan->mlen;
|
||||
|
|
@ -260,16 +256,11 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
|
|||
seqnum = rx_seqnum - 1;
|
||||
rx_data = &achan->rx_data[seqnum];
|
||||
|
||||
if (rx_data->rxcnt) {
|
||||
if (rx_data->response) {
|
||||
if (rx_seqnum == tx_seqnum) {
|
||||
__ioread32_copy(xfer->rxd, addr, xfer->rxcnt);
|
||||
/*
|
||||
* Signal completion to the polling thread.
|
||||
* Pairs with smp_load_acquire() in polling
|
||||
* loop.
|
||||
*/
|
||||
smp_store_release(&rx_data->completed, true);
|
||||
*native_match = true;
|
||||
rx_set = true;
|
||||
clear_bit(seqnum, achan->bitmap_seqnum);
|
||||
} else {
|
||||
/*
|
||||
* The RX data corresponds to another request.
|
||||
|
|
@ -277,23 +268,10 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
|
|||
* clear yet the bitmap. It will be cleared
|
||||
* after the response is copied to the request.
|
||||
*/
|
||||
__ioread32_copy(rx_data->cmd, addr,
|
||||
rx_data->rxcnt);
|
||||
/*
|
||||
* Signal completion to the polling thread.
|
||||
* Pairs with smp_load_acquire() in polling
|
||||
* loop.
|
||||
*/
|
||||
smp_store_release(&rx_data->completed, true);
|
||||
__ioread32_copy(rx_data->cmd, addr, xfer->rxcnt);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Signal completion to the polling thread.
|
||||
* Pairs with smp_load_acquire() in polling loop.
|
||||
*/
|
||||
smp_store_release(&rx_data->completed, true);
|
||||
if (rx_seqnum == tx_seqnum)
|
||||
*native_match = true;
|
||||
clear_bit(seqnum, achan->bitmap_seqnum);
|
||||
}
|
||||
|
||||
i = (i + 1) % achan->qlen;
|
||||
|
|
@ -302,6 +280,13 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
|
|||
/* We saved all responses, mark RX empty. */
|
||||
writel(rx_front, achan->rx.rear);
|
||||
|
||||
/*
|
||||
* If the response was not in this iteration of the queue, check if the
|
||||
* RX data was previously saved.
|
||||
*/
|
||||
if (!rx_set)
|
||||
acpm_get_saved_rx(achan, xfer, tx_seqnum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +301,6 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
|
|||
const struct acpm_xfer *xfer)
|
||||
{
|
||||
struct device *dev = achan->acpm->dev;
|
||||
bool native_match;
|
||||
ktime_t timeout;
|
||||
u32 seqnum;
|
||||
int ret;
|
||||
|
|
@ -325,25 +309,12 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
|
|||
|
||||
timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);
|
||||
do {
|
||||
ret = acpm_get_rx(achan, xfer, &native_match);
|
||||
ret = acpm_get_rx(achan, xfer);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Safely check if our specific transaction has been processed.
|
||||
* smp_load_acquire prevents the CPU from speculatively
|
||||
* executing subsequent instructions before the transaction is
|
||||
* synchronized.
|
||||
*/
|
||||
if (smp_load_acquire(&achan->rx_data[seqnum - 1].completed)) {
|
||||
/* Retrieve payload if another thread cached it for us */
|
||||
if (!native_match)
|
||||
acpm_get_saved_rx(achan, xfer, seqnum);
|
||||
|
||||
/* Relinquish ownership of the sequence slot */
|
||||
clear_bit_unlock(seqnum - 1, achan->bitmap_seqnum);
|
||||
if (!test_bit(seqnum - 1, achan->bitmap_seqnum))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determined experimentally. */
|
||||
udelay(20);
|
||||
|
|
@ -391,48 +362,29 @@ static int acpm_wait_for_queue_slots(struct acpm_chan *achan, u32 next_tx_front)
|
|||
* TX queue.
|
||||
* @achan: ACPM channel info.
|
||||
* @xfer: reference to the transfer being prepared.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int acpm_prepare_xfer(struct acpm_chan *achan,
|
||||
const struct acpm_xfer *xfer)
|
||||
static void acpm_prepare_xfer(struct acpm_chan *achan,
|
||||
const struct acpm_xfer *xfer)
|
||||
{
|
||||
struct acpm_rx_data *rx_data;
|
||||
u32 *txd = (u32 *)xfer->txd;
|
||||
unsigned long size = ACPM_SEQNUM_MAX - 1;
|
||||
unsigned long bit = achan->seqnum;
|
||||
|
||||
bit = find_next_zero_bit(achan->bitmap_seqnum, size, bit);
|
||||
if (bit >= size) {
|
||||
bit = find_first_zero_bit(achan->bitmap_seqnum, size);
|
||||
if (bit >= size) {
|
||||
dev_err_ratelimited(achan->acpm->dev,
|
||||
"ACPM sequence number pool exhausted\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
/* Prevent chan->seqnum from being re-used */
|
||||
do {
|
||||
if (++achan->seqnum == ACPM_SEQNUM_MAX)
|
||||
achan->seqnum = 1;
|
||||
} while (test_bit(achan->seqnum - 1, achan->bitmap_seqnum));
|
||||
|
||||
/*
|
||||
* Execute the atomic set to formally claim the bit and establish
|
||||
* LKMM Acquire semantics against the RX thread's clear_bit_unlock().
|
||||
* A loop is unnecessary because allocations are strictly serialized
|
||||
* by tx_lock.
|
||||
*/
|
||||
if (WARN_ON_ONCE(test_and_set_bit_lock(bit, achan->bitmap_seqnum)))
|
||||
return -EIO;
|
||||
|
||||
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
|
||||
achan->seqnum = bit + 1;
|
||||
txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum);
|
||||
|
||||
/* Clear data for upcoming responses */
|
||||
rx_data = &achan->rx_data[bit];
|
||||
rx_data->completed = false;
|
||||
rx_data = &achan->rx_data[achan->seqnum - 1];
|
||||
memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);
|
||||
/* zero means no response expected */
|
||||
rx_data->rxcnt = xfer->rxcnt;
|
||||
if (xfer->rxd)
|
||||
rx_data->response = true;
|
||||
|
||||
return 0;
|
||||
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
|
||||
set_bit(achan->seqnum - 1, achan->bitmap_seqnum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -492,9 +444,7 @@ int acpm_do_xfer(struct acpm_handle *handle, const struct acpm_xfer *xfer)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = acpm_prepare_xfer(achan, xfer);
|
||||
if (ret)
|
||||
return ret;
|
||||
acpm_prepare_xfer(achan, xfer);
|
||||
|
||||
/* Write TX command. */
|
||||
__iowrite32_copy(achan->tx.base + achan->mlen * tx_front,
|
||||
|
|
@ -576,11 +526,10 @@ static int acpm_achan_alloc_cmds(struct acpm_chan *achan)
|
|||
|
||||
/**
|
||||
* acpm_free_mbox_chans() - free mailbox channels.
|
||||
* @data: pointer to driver data.
|
||||
* @acpm: pointer to driver data.
|
||||
*/
|
||||
static void acpm_free_mbox_chans(void *data)
|
||||
static void acpm_free_mbox_chans(struct acpm_info *acpm)
|
||||
{
|
||||
struct acpm_info *acpm = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < acpm->num_chans; i++)
|
||||
|
|
@ -608,10 +557,6 @@ static int acpm_channels_init(struct acpm_info *acpm)
|
|||
if (!acpm->chans)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, acpm_free_mbox_chans, acpm);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to add mbox free action.\n");
|
||||
|
||||
chans_shmem = acpm->sram_base + readl(&shmem->chans);
|
||||
|
||||
for (i = 0; i < acpm->num_chans; i++) {
|
||||
|
|
@ -633,8 +578,10 @@ static int acpm_channels_init(struct acpm_info *acpm)
|
|||
cl->dev = dev;
|
||||
|
||||
achan->chan = mbox_request_channel(cl, 0);
|
||||
if (IS_ERR(achan->chan))
|
||||
if (IS_ERR(achan->chan)) {
|
||||
acpm_free_mbox_chans(acpm);
|
||||
return PTR_ERR(achan->chan);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue