Compare commits

..

No commits in common. "master" and "v7.1-rc5" have entirely different histories.

652 changed files with 3649 additions and 7701 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,7 +25,6 @@ properties:
- items:
- enum:
- qcom,ipq5018-snand
- qcom,ipq5210-snand
- qcom,ipq5332-snand
- qcom,ipq5424-snand
- const: qcom,ipq9574-snand

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -146,7 +146,7 @@
partitions {
compatible = "redboot-fis";
/* Eraseblock at 0xfe0000 */
fis-index-block = <0x7f>;
fis-index-block = <0x1fc>;
};
};

View File

@ -134,7 +134,7 @@
partitions {
compatible = "redboot-fis";
/* Eraseblock at 0xfe0000 */
fis-index-block = <0x7f>;
fis-index-block = <0x1fc>;
};
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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