summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Zimmermann <tzimmermann@suse.de>2026-08-31 14:43:36 +0200
committerThomas Zimmermann <tzimmermann@suse.de>2026-08-31 14:43:36 +0200
commitbe150d35864ccd8d1005a12953da145013219d35 (patch)
tree3af39f4f7a7e3d24eb4537eff7f2c7867767991d
parentc8329cb590df4a8b3a4e878d289d4b17824db8d1 (diff)
parent8d3ae59288f1e7d58d76558a6ee96d533bc5019f (diff)
downloadlinux-be150d35864ccd8d1005a12953da145013219d35.tar.gz
linux-be150d35864ccd8d1005a12953da145013219d35.zip
Merge drm/drm-fixes into drm-misc-fixes
Updating drm-misc-fixes to the state of v7.2. Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
-rw-r--r--.mailmap4
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt4
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml2
-rw-r--r--Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml11
-rw-r--r--Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml5
-rw-r--r--Makefile2
-rw-r--r--arch/arm64/boot/dts/apple/t8122.dtsi30
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra194.dtsi2
-rw-r--r--arch/m68k/Kconfig.cpu4
-rw-r--r--arch/openrisc/include/asm/processor.h2
-rw-r--r--arch/openrisc/kernel/signal.c5
-rw-r--r--arch/riscv/kernel/ftrace.c5
-rw-r--r--arch/riscv/kernel/unaligned_access_speed.c8
-rw-r--r--arch/riscv/lib/strnlen.S10
-rw-r--r--arch/x86/kernel/cpu/common.c10
-rw-r--r--crypto/algif_skcipher.c8
-rw-r--r--crypto/ccm.c2
-rw-r--r--drivers/base/regmap/regcache.c27
-rw-r--r--drivers/base/regmap/regmap-sdw-mbq.c4
-rw-r--r--drivers/block/drbd/drbd_nl.c39
-rw-r--r--drivers/clk/qcom/clk-regmap-phy-mux.c52
-rw-r--r--drivers/clk/qcom/dispcc-eliza.c2
-rw-r--r--drivers/clk/rockchip/clk-rk3588.c8
-rw-r--r--drivers/clk/spacemit/ccu-k3.c4
-rw-r--r--drivers/clocksource/arm_arch_timer.c24
-rw-r--r--drivers/crypto/qce/core.c2
-rw-r--r--drivers/crypto/starfive/jh7110-aes.c2
-rw-r--r--drivers/crypto/tegra/tegra-se-aes.c22
-rw-r--r--drivers/dibs/dibs_loopback.c1
-rw-r--r--drivers/dibs/dibs_main.c14
-rw-r--r--drivers/firewire/ohci.c4
-rw-r--r--drivers/gpio/gpio-ml-ioh.c71
-rw-r--r--drivers/gpio/gpio-sloppy-logic-analyzer.c2
-rw-r--r--drivers/gpio/gpiolib.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c50
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c85
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c26
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_transform.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c1
-rw-r--r--drivers/gpu/drm/xe/display/xe_fb_pin.c33
-rw-r--r--drivers/gpu/drm/xe/xe_bo.h14
-rw-r--r--drivers/gpu/drm/xe/xe_device.c6
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ads.c93
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ads_types.h5
-rw-r--r--drivers/gpu/drm/xe/xe_guc_pc.c13
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.c29
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.h7
-rw-r--r--drivers/gpu/drm/xe/xe_oa.c13
-rw-r--r--drivers/gpu/drm/xe/xe_pxp.c162
-rw-r--r--drivers/gpu/drm/xe/xe_pxp_types.h27
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c80
-rw-r--r--drivers/input/touchscreen/sur40.c23
-rw-r--r--drivers/mmc/host/atmel-mci.c2
-rw-r--r--drivers/mmc/host/loongson2-mmc.c8
-rw-r--r--drivers/mmc/host/omap_hsmmc.c2
-rw-r--r--drivers/mmc/host/sdhci.c16
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c131
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h3
-rw-r--r--drivers/net/ethernet/google/gve/gve_ptp.c6
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx_dqo.c5
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c2
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_main.c4
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c4
-rw-r--r--drivers/net/macvlan.c4
-rw-r--r--drivers/net/ntb_netdev.c15
-rw-r--r--drivers/net/ovpn/crypto.c26
-rw-r--r--drivers/net/ovpn/crypto.h4
-rw-r--r--drivers/net/ovpn/crypto_aead.c19
-rw-r--r--drivers/net/ovpn/crypto_aead.h1
-rw-r--r--drivers/net/ovpn/io.c10
-rw-r--r--drivers/net/ovpn/main.c19
-rw-r--r--drivers/net/ovpn/ovpnpriv.h4
-rw-r--r--drivers/net/ovpn/peer.c8
-rw-r--r--drivers/net/ovpn/tcp.c9
-rw-r--r--drivers/net/phy/realtek/realtek_main.c2
-rw-r--r--drivers/net/tap.c3
-rw-r--r--drivers/net/veth.c24
-rw-r--r--drivers/net/vxlan/vxlan_core.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/regd.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/regd.h2
-rw-r--r--drivers/pmdomain/arm/scmi_perf_domain.c2
-rw-r--r--drivers/pmdomain/mediatek/mt8183-pm-domains.h7
-rw-r--r--drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c2
-rw-r--r--drivers/pmdomain/mediatek/mtk-pm-domains.c30
-rw-r--r--drivers/pmdomain/qcom/rpmhpd.c4
-rw-r--r--drivers/regulator/fp9931.c54
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c9
-rw-r--r--drivers/scsi/scsi_debug.c4
-rw-r--r--drivers/scsi/scsi_error.c8
-rw-r--r--drivers/spi/spi-dw.h1
-rw-r--r--drivers/spi/spi-virtio.c2
-rw-r--r--drivers/tee/optee/ffa_abi.c3
-rw-r--r--drivers/ufs/core/ufshcd.c4
-rw-r--r--fs/binfmt_misc.c3
-rw-r--r--fs/ceph/ioctl.c4
-rw-r--r--fs/ceph/mdsmap.c2
-rw-r--r--fs/erofs/Kconfig3
-rw-r--r--fs/overlayfs/super.c3
-rw-r--r--include/linux/rseq_entry.h1
-rw-r--r--include/linux/tick.h2
-rw-r--r--include/net/act_api.h19
-rw-r--r--include/net/ip_vs.h29
-rw-r--r--include/net/route.h2
-rw-r--r--include/net/sctp/auth.h3
-rw-r--r--include/scsi/scsi_host.h6
-rw-r--r--include/uapi/linux/ip_vs.h6
-rw-r--r--io_uring/rsrc.c8
-rw-r--r--kernel/events/core.c75
-rw-r--r--kernel/pid.c6
-rw-r--r--kernel/sched/fair.c2
-rw-r--r--kernel/trace/trace_events.c4
-rw-r--r--lib/rhashtable.c2
-rw-r--r--net/bridge/netfilter/nf_conntrack_bridge.c1
-rw-r--r--net/ceph/cls_lock_client.c13
-rw-r--r--net/ceph/decode.c18
-rw-r--r--net/ceph/osd_client.c5
-rw-r--r--net/ceph/osdmap.c5
-rw-r--r--net/core/dev.c10
-rw-r--r--net/core/netdev_queues.c2
-rw-r--r--net/ipv4/fib_semantics.c34
-rw-r--r--net/ipv4/route.c29
-rw-r--r--net/ipv4/tcp_input.c6
-rw-r--r--net/ipv4/tcp_timer.c4
-rw-r--r--net/l2tp/l2tp_debugfs.c4
-rw-r--r--net/l2tp/l2tp_ppp.c56
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_gen.h2
-rw-r--r--net/netfilter/ipset/ip_set_core.c19
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c10
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c45
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c18
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c81
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_lc.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c7
-rw-r--r--net/netfilter/nf_conntrack_proto.c6
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c12
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c132
-rw-r--r--net/netfilter/nf_flow_table_core.c7
-rw-r--r--net/netfilter/nf_log_syslog.c4
-rw-r--r--net/netfilter/nf_tables_offload.c2
-rw-r--r--net/netfilter/nfnetlink_log.c13
-rw-r--r--net/packet/af_packet.c7
-rw-r--r--net/sched/act_api.c10
-rw-r--r--net/sched/act_ct.c29
-rw-r--r--net/sched/act_gact.c5
-rw-r--r--net/sched/act_police.c6
-rw-r--r--net/sched/cls_bpf.c18
-rw-r--r--net/sched/cls_u32.c3
-rw-r--r--net/sctp/associola.c7
-rw-r--r--net/sctp/auth.c75
-rw-r--r--net/sctp/sm_make_chunk.c3
-rw-r--r--net/sctp/sm_statefuns.c6
-rw-r--r--net/tipc/node.c15
-rw-r--r--net/tls/tls_sw.c5
-rw-r--r--net/unix/garbage.c1
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c7
-rw-r--r--sound/soc/codecs/Kconfig1
-rw-r--r--sound/soc/codecs/rt1320-sdw.c2
-rw-r--r--sound/soc/codecs/rt5645.c4
-rw-r--r--sound/soc/codecs/tas2781-i2c.c18
-rw-r--r--sound/soc/intel/boards/sof_es8336.c10
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c7
-rw-r--r--sound/soc/intel/boards/sof_ssp_amp.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-nvl-match.c25
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c10
-rw-r--r--sound/usb/midi2.c9
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/filesystems/fscontext_ns/Makefile10
-rw-r--r--tools/testing/selftests/filesystems/fscontext_ns/fscontext_ns_test.c239
-rw-r--r--tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc27
-rw-r--r--tools/testing/selftests/net/tls.c75
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/ct.json40
192 files changed, 2157 insertions, 980 deletions
diff --git a/.mailmap b/.mailmap
index 8079e9560748..48d1c92dde19 100644
--- a/.mailmap
+++ b/.mailmap
@@ -212,6 +212,10 @@ Christophe Ricard <christophe.ricard@gmail.com>
Christopher Obbard <christopher.obbard@linaro.org> <chris.obbard@collabora.com>
Christoph Hellwig <hch@lst.de>
Christoph Manszewski <c.manszewski@gmail.com> <christoph.manszewski@intel.com>
+Christoph Paasch <cpaasch@openai.com> <christoph.paasch@gmail.com>
+Christoph Paasch <cpaasch@openai.com> <christoph.paasch@student.uclouvain.be>
+Christoph Paasch <cpaasch@openai.com> <christoph.paasch@uclouvain.be>
+Christoph Paasch <cpaasch@openai.com> <cpaasch@apple.com>
Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
Chuck Lever <cel@kernel.org> <cel@netapp.com>
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 3d35270dddef..e8ff36982d97 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7568,6 +7568,10 @@ Kernel parameters
See Documentation/admin-guide/mm/transhuge.rst for more
details.
+ tlbi= [X86-64]
+ Format: {ipi}
+ ipi: switch to IPI-based TLB flushing
+
topology= [S390,EARLY]
Format: {off | on}
Specify if the kernel should make use of the cpu
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
index ced3118c8580..bbc38b7a018a 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
@@ -7,8 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Global Clock & Reset Controller on MSM8937, MSM8940, MSM8953 and SDM439
maintainers:
- - Adam Skladowski <a_skl39@protonmail.com>
- - Sireesh Kodali <sireeshkodali@protonmail.com>
- Barnabas Czeman <barnabas.czeman@mainlining.org>
description: |
diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
index 27ae9938febc..03fe290476be 100644
--- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
@@ -8,7 +8,6 @@ title: Qualcomm Global Clock & Reset Controller on IPQ9574
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- - Anusha Rao <quic_anusha@quicinc.com>
description: |
Qualcomm global clock control module provides the clocks, resets and power
diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml
index 7ff4ff3587ca..a35bbc7b1924 100644
--- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml
@@ -8,7 +8,6 @@ title: Qualcomm Networking Sub System Clock & Reset Controller on IPQ9574 and IP
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- - Anusha Rao <quic_anusha@quicinc.com>
description: |
Qualcomm networking sub system clock control module provides the clocks,
diff --git a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
index 32f39e543b36..21e307d59775 100644
--- a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung Exynos Auto v9 SoC clock controller
maintainers:
- - Chanho Park <chanho61.park@samsung.com>
+ - Alim Akhtar <alim.akhtar@samsung.com>
- Chanwoo Choi <cw00.choi@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
- Sylwester Nawrocki <s.nawrocki@samsung.com>
diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
index d93594304651..eed2ce7fa861 100644
--- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
@@ -47,6 +47,7 @@ description: |
For PM8150, smps1 - smps10, ldo1 - ldo18
For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb
For PM8350, smps1 - smps12, ldo1 - ldo10
+ For PM8350B, ldo1
For PM8350C, smps1 - smps10, ldo1 - ldo13, bob
For PM8450, smps1 - smps6, ldo1 - ldo4
For PM8550, smps1 - smps6, ldo1 - ldo17, bob1 - bob2
@@ -82,6 +83,7 @@ properties:
- qcom,pm8150-rpmh-regulators
- qcom,pm8150l-rpmh-regulators
- qcom,pm8350-rpmh-regulators
+ - qcom,pm8350b-rpmh-regulators
- qcom,pm8350c-rpmh-regulators
- qcom,pm8450-rpmh-regulators
- qcom,pm8550-rpmh-regulators
@@ -341,6 +343,15 @@ allOf:
properties:
compatible:
enum:
+ - qcom,pm8350b-rpmh-regulators
+ then:
+ properties:
+ vdd-l1-supply: true
+
+ - if:
+ properties:
+ compatible:
+ enum:
- qcom,pm8350c-rpmh-regulators
then:
properties:
diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
index 95a5bd894e93..7f698195cc43 100644
--- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
+++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
@@ -53,6 +53,11 @@ properties:
- sophgo,sg2042-spi
- thead,th1520-spi
- const: snps,dw-apb-ssi
+ - description: Vendor controllers compatible with v1.01a
+ items:
+ - enum:
+ - axiado,ax3005-spi
+ - const: snps,dwc-ssi-1.01a
- description: Vendor controllers which use snps,dwc-ssi-2.00a as fallback
items:
- enum:
diff --git a/Makefile b/Makefile
index 0e6fc0803775..ddcc6dca1ece 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 2
SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
NAME = Baby Opossum Posse
# *DOCUMENTATION*
diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi
index c6196225e96e..1ee61c5b3409 100644
--- a/arch/arm64/boot/dts/apple/t8122.dtsi
+++ b/arch/arm64/boot/dts/apple/t8122.dtsi
@@ -186,12 +186,12 @@
/* Required to get >32-bit DMA via DARTs */
dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>;
- i2c0: i2c@235010000 {
+ i2c0: i2c@2a1010000 {
compatible = "apple,t8122-i2c", "apple,t8103-i2c";
- reg = <0x2 0x35010000 0x0 0x4000>;
+ reg = <0x2 0xa1010000 0x0 0x4000>;
clocks = <&clkref>;
interrupt-parent = <&aic>;
- interrupts = <AIC_IRQ 761 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <AIC_IRQ 780 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-0 = <&i2c0_pins>;
pinctrl-names = "default";
#address-cells = <0x1>;
@@ -200,12 +200,12 @@
status = "disabled";
};
- i2c1: i2c@235014000 {
+ i2c1: i2c@2a1014000 {
compatible = "apple,t8122-i2c", "apple,t8103-i2c";
- reg = <0x2 0x35014000 0x0 0x4000>;
+ reg = <0x2 0xa1014000 0x0 0x4000>;
clocks = <&clkref>;
interrupt-parent = <&aic>;
- interrupts = <AIC_IRQ 762 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <AIC_IRQ 781 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-0 = <&i2c1_pins>;
pinctrl-names = "default";
#address-cells = <0x1>;
@@ -214,12 +214,12 @@
status = "disabled";
};
- i2c2: i2c@235018000 {
+ i2c2: i2c@2a1018000 {
compatible = "apple,t8122-i2c", "apple,t8103-i2c";
- reg = <0x2 0x35018000 0x0 0x4000>;
+ reg = <0x2 0xa1018000 0x0 0x4000>;
clocks = <&clkref>;
interrupt-parent = <&aic>;
- interrupts = <AIC_IRQ 763 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <AIC_IRQ 782 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-0 = <&i2c2_pins>;
pinctrl-names = "default";
#address-cells = <0x1>;
@@ -228,12 +228,12 @@
status = "disabled";
};
- i2c3: i2c@23501c000 {
+ i2c3: i2c@2a101c000 {
compatible = "apple,t8122-i2c", "apple,t8103-i2c";
- reg = <0x2 0x3501c000 0x0 0x4000>;
+ reg = <0x2 0xa101c000 0x0 0x4000>;
clocks = <&clkref>;
interrupt-parent = <&aic>;
- interrupts = <AIC_IRQ 764 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <AIC_IRQ 783 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-0 = <&i2c3_pins>;
pinctrl-names = "default";
#address-cells = <0x1>;
@@ -242,12 +242,12 @@
status = "disabled";
};
- i2c4: i2c@235020000 {
+ i2c4: i2c@2a1020000 {
compatible = "apple,t8122-i2c", "apple,t8103-i2c";
- reg = <0x2 0x35020000 0x0 0x4000>;
+ reg = <0x2 0xa1020000 0x0 0x4000>;
clocks = <&clkref>;
interrupt-parent = <&aic>;
- interrupts = <AIC_IRQ 765 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <AIC_IRQ 784 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-0 = <&i2c4_pins>;
pinctrl-names = "default";
#address-cells = <0x1>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index eb7e3c666df6..5e510f77b538 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -3176,6 +3176,8 @@
<GIC_PPI 11
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 15
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&gic>;
always-on;
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index 148f8a79d206..5a58cc13229e 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -549,6 +549,10 @@ config CACHE_COPYBACK
endchoice
endif # HAVE_CACHE_CB
+config NR_CPUS
+ int
+ default "1"
+
# Coldfire cores that do not have a data cache configured can do coherent DMA.
config COLDFIRE_COHERENT_DMA
bool
diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h
index 3ff893a67c13..ae43fe79b2b5 100644
--- a/arch/openrisc/include/asm/processor.h
+++ b/arch/openrisc/include/asm/processor.h
@@ -26,6 +26,8 @@
| SPR_SR_DCE | SPR_SR_SM)
#define USER_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \
| SPR_SR_DCE | SPR_SR_IEE | SPR_SR_TEE)
+/* SR bits user space may change via sigreturn, the rest stay kernel owned */
+#define SPR_SR_USER_MASK (SPR_SR_F | SPR_SR_CY | SPR_SR_OV)
/*
* User space process size. This is hardcoded into a few places,
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index f70a13ee0593..2be5af3b9832 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -74,6 +74,7 @@ static long save_fp_state(struct sigcontext __user *sc)
static int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc)
{
+ unsigned long old_sr = regs->sr;
int err = 0;
/* Always make any pending restarted system calls return -EINTR */
@@ -89,8 +90,8 @@ static int restore_sigcontext(struct pt_regs *regs,
err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
err |= restore_fp_state(sc);
- /* make sure the SM-bit is cleared so user-mode cannot fool us */
- regs->sr &= ~SPR_SR_SM;
+ /* keep the privileged SR bits kernel owned, restore only user flags */
+ regs->sr = (old_sr & ~SPR_SR_USER_MASK) | (regs->sr & SPR_SR_USER_MASK);
regs->orig_gpr11 = -1; /* Avoid syscall restart checks */
diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
index b430edfb83f4..be8b68514417 100644
--- a/arch/riscv/kernel/ftrace.c
+++ b/arch/riscv/kernel/ftrace.c
@@ -12,6 +12,7 @@
#include <linux/stop_machine.h>
#include <asm/cacheflush.h>
#include <asm/text-patching.h>
+#include <asm/insn.h>
#ifdef CONFIG_DYNAMIC_FTRACE
void ftrace_arch_code_modify_prepare(void)
@@ -63,7 +64,9 @@ static int __ftrace_modify_call(unsigned long source, unsigned long target, bool
if (copy_from_kernel_nofault(replaced, (void *)source, 2 * MCOUNT_INSN_SIZE))
return -EFAULT;
- if (replaced[0] != call[0]) {
+ /* Bypass the check if the auipc insn is a kprobe breakpoint */
+ if (replaced[0] != call[0] &&
+ !(riscv_insn_is_ebreak(replaced[0]) || riscv_insn_is_c_ebreak(replaced[0]))) {
pr_err("%p: expected (%08x) but got (%08x)\n",
(void *)source, call[0], replaced[0]);
return -EINVAL;
diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c
index 5a5aa22124e7..36201613d2ca 100644
--- a/arch/riscv/kernel/unaligned_access_speed.c
+++ b/arch/riscv/kernel/unaligned_access_speed.c
@@ -411,4 +411,10 @@ static int __init check_unaligned_access_all_cpus(void)
return 0;
}
-late_initcall(check_unaligned_access_all_cpus);
+/*
+ * Run after clocksource_done_booting() so measure_cycles() uses a stable
+ * clocksource, but before rootfs_initcall() enables usermode helpers. Those
+ * helpers can reach hwprobe and populate the vDSO cache, so async hwprobe
+ * probes must be registered first.
+ */
+fs_initcall_sync(check_unaligned_access_all_cpus);
diff --git a/arch/riscv/lib/strnlen.S b/arch/riscv/lib/strnlen.S
index 53afa7b5b314..a8911605c248 100644
--- a/arch/riscv/lib/strnlen.S
+++ b/arch/riscv/lib/strnlen.S
@@ -83,8 +83,13 @@ strnlen_zbb:
sub t3, t3, t2
slli t2, t2, 3
- /* Aligned boundary. */
+ /*
+ * Aligned boundary. Use the address of the last valid byte
+ * (s + count - 1) to avoid loading a word past the count
+ * boundary in the loop below. count == 0 is handled above.
+ */
add t4, a0, a1
+ addi t4, t4, -1
andi t4, t4, -SZREG
/* Get the first word. */
@@ -120,6 +125,9 @@ strnlen_zbb:
bgtu t3, a0, 2f
+ /* All remaining bytes are in the first word, no loop needed. */
+ bgeu t0, t4, 2f
+
/* Prepare for the word comparison loop. */
addi t2, t0, SZREG
li t3, -1
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a3df21d26460..a3caddd411ec 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2664,3 +2664,13 @@ void __init arch_cpu_finalize_init(void)
*/
mem_encrypt_init();
}
+
+/* Control TLB flushing methods */
+static int __init tlbi_setup(char *str)
+{
+ if (!strcmp(str, "ipi"))
+ setup_clear_cpu_cap(X86_FEATURE_INVLPGB);
+
+ return 1;
+}
+__setup("tlbi=", tlbi_setup);
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index df20bdfe1f1f..035fed7db81f 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -32,6 +32,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/net.h>
+#include <linux/string.h>
#include <net/sock.h>
static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
@@ -309,7 +310,12 @@ static struct proto_ops algif_skcipher_ops_nokey = {
static void *skcipher_bind(const char *name)
{
- return crypto_alloc_skcipher(name, 0, AF_ALG_CRYPTOAPI_MASK);
+ u32 mask = AF_ALG_CRYPTOAPI_MASK;
+
+ if (strcmp(name, "cbc(paes)") == 0)
+ mask = 0;
+
+ return crypto_alloc_skcipher(name, 0, mask);
}
static void skcipher_release(void *private)
diff --git a/crypto/ccm.c b/crypto/ccm.c
index 2ae929ffdef8..916441e4f2b8 100644
--- a/crypto/ccm.c
+++ b/crypto/ccm.c
@@ -747,7 +747,7 @@ static int crypto_rfc4309_create(struct crypto_template *tmpl,
inst->alg.ivsize = 8;
inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
- inst->alg.maxauthsize = 16;
+ inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index aa8f2efed779..623db7a1f3bd 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -123,6 +123,8 @@ static void regcache_hw_exit(struct regmap *map)
int regcache_init(struct regmap *map, const struct regmap_config *config)
{
+ bool sort_defaults = false;
+ unsigned int reg_prev = 0;
int count = 0;
int ret;
int i;
@@ -149,10 +151,16 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
return -EINVAL;
}
- for (i = 0; i < config->num_reg_defaults; i++)
+ for (i = 0; i < config->num_reg_defaults; i++) {
if (config->reg_defaults[i].reg % map->reg_stride)
return -EINVAL;
+ if (reg_prev > config->reg_defaults[i].reg)
+ sort_defaults = true;
+
+ reg_prev = config->reg_defaults[i].reg;
+ }
+
for (i = 0; i < ARRAY_SIZE(cache_types); i++)
if (cache_types[i]->type == map->cache_type)
break;
@@ -186,6 +194,13 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
sizeof(*map->reg_defaults), GFP_KERNEL);
if (!tmp_buf)
return -ENOMEM;
+
+ /* regcache_lookup_reg() bsearch()es this array */
+ if (sort_defaults) {
+ dev_warn(map->dev,
+ "Driver needs fixing: Unsorted reg_defaults, sorting the copy\n");
+ regcache_sort_defaults(tmp_buf, map->num_reg_defaults);
+ }
map->reg_defaults = tmp_buf;
} else if (map->num_reg_defaults_raw) {
count = regcache_count_cacheable_registers(map);
@@ -727,14 +742,6 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
return -1;
}
-static int regcache_default_cmp(const void *a, const void *b)
-{
- const struct reg_default *_a = a;
- const struct reg_default *_b = b;
-
- return _a->reg - _b->reg;
-}
-
int regcache_lookup_reg(struct regmap *map, unsigned int reg)
{
struct reg_default key;
@@ -744,7 +751,7 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
key.def = 0;
r = bsearch(&key, map->reg_defaults, map->num_reg_defaults,
- sizeof(struct reg_default), regcache_default_cmp);
+ sizeof(struct reg_default), regcache_defaults_cmp);
if (r)
return r - map->reg_defaults;
diff --git a/drivers/base/regmap/regmap-sdw-mbq.c b/drivers/base/regmap/regmap-sdw-mbq.c
index 2585933d4946..b0312f57c980 100644
--- a/drivers/base/regmap/regmap-sdw-mbq.c
+++ b/drivers/base/regmap/regmap-sdw-mbq.c
@@ -56,10 +56,10 @@ static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
reg = SDW_SDCA_CTL(SDW_SDCA_CTL_FUNC(reg), 0,
SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0);
- if (ctx->readable_reg(dev, reg)) {
+ if (!ctx->readable_reg || ctx->readable_reg(dev, reg)) {
ret = read_poll_timeout(sdw_read_no_pm, val,
val < 0 || !(val & SDCA_CTL_ENTITY_0_FUNCTION_BUSY),
- ctx->cfg.timeout_us, ctx->cfg.retry_us,
+ ctx->cfg.retry_us, ctx->cfg.timeout_us,
false, slave, reg);
if (val < 0)
return val;
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index f9ffcd67607b..b77f901fc3ef 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -3307,6 +3307,26 @@ nla_put_failure:
}
/*
+ * net_conf_to_skb() serializes the shared secret verbatim. Any path that can
+ * answer a request from an unprivileged process must pass exclude_sensitive,
+ * so the secret is blanked in a private copy before it reaches the skb.
+ */
+static int net_conf_to_skb_sanitized(struct sk_buff *skb, struct net_conf *nc,
+ bool exclude_sensitive)
+{
+ struct net_conf nc_clean;
+
+ if (!exclude_sensitive)
+ return net_conf_to_skb(skb, nc);
+
+ nc_clean = *nc;
+ memset(nc_clean.shared_secret, 0, sizeof(nc_clean.shared_secret));
+ nc_clean.shared_secret_len = 0;
+
+ return net_conf_to_skb(skb, &nc_clean);
+}
+
+/*
* The generic netlink dump callbacks are called outside the genl_lock(), so
* they cannot use the simple attribute parsing code which uses global
* attribute tables.
@@ -3621,7 +3641,8 @@ put_result:
goto out;
net_conf = rcu_dereference(connection->net_conf);
if (net_conf) {
- err = net_conf_to_skb(skb, net_conf);
+ err = net_conf_to_skb_sanitized(skb, net_conf,
+ !capable(CAP_SYS_ADMIN));
if (err)
goto out;
}
@@ -3842,18 +3863,8 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
struct net_conf *nc;
nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
- if (nc) {
- if (exclude_sensitive) {
- struct net_conf nc_clean = *nc;
-
- memset(nc_clean.shared_secret, 0,
- sizeof(nc_clean.shared_secret));
- nc_clean.shared_secret_len = 0;
- err = net_conf_to_skb(skb, &nc_clean);
- } else {
- err = net_conf_to_skb(skb, nc);
- }
- }
+ if (nc)
+ err = net_conf_to_skb_sanitized(skb, nc, exclude_sensitive);
}
rcu_read_unlock();
if (err)
@@ -4058,7 +4069,7 @@ next_resource:
struct net_conf *nc;
nc = rcu_dereference(connection->net_conf);
- if (nc && net_conf_to_skb(skb, nc) != 0)
+ if (nc && net_conf_to_skb_sanitized(skb, nc, true) != 0)
goto cancel;
}
goto done;
diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
index b7d1c69d62f7..7b7243b7107d 100644
--- a/drivers/clk/qcom/clk-regmap-phy-mux.c
+++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
@@ -15,66 +15,48 @@
#define PHY_MUX_PHY_SRC 0
#define PHY_MUX_REF_SRC 2
-#define XO_RATE 19200000UL
-
static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr)
{
return container_of(clkr, struct clk_regmap_phy_mux, clkr);
}
-static unsigned long phy_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+static int phy_mux_is_enabled(struct clk_hw *hw)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- u32 val;
+ unsigned int val;
regmap_read(clkr->regmap, phy_mux->reg, &val);
+ val = FIELD_GET(PHY_MUX_MASK, val);
+
+ WARN_ON(val != PHY_MUX_PHY_SRC && val != PHY_MUX_REF_SRC);
- switch (FIELD_GET(PHY_MUX_MASK, val)) {
- case PHY_MUX_PHY_SRC:
- return ULONG_MAX;
- case PHY_MUX_REF_SRC:
- return XO_RATE;
- default:
- return 0;
- }
+ return val == PHY_MUX_PHY_SRC;
}
-static int phy_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+static int phy_mux_enable(struct clk_hw *hw)
{
- if (req->rate == XO_RATE || req->rate == ULONG_MAX)
- return 0;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- return -EINVAL;
+ return regmap_update_bits(clkr->regmap, phy_mux->reg,
+ PHY_MUX_MASK,
+ FIELD_PREP(PHY_MUX_MASK, PHY_MUX_PHY_SRC));
}
-static int phy_mux_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+static void phy_mux_disable(struct clk_hw *hw)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- u32 val;
-
- switch (rate) {
- case XO_RATE:
- val = PHY_MUX_REF_SRC;
- break;
- case ULONG_MAX:
- val = PHY_MUX_PHY_SRC;
- break;
- default:
- return -EINVAL;
- }
regmap_update_bits(clkr->regmap, phy_mux->reg,
PHY_MUX_MASK,
- FIELD_PREP(PHY_MUX_MASK, val));
-
- return 0;
+ FIELD_PREP(PHY_MUX_MASK, PHY_MUX_REF_SRC));
}
const struct clk_ops clk_regmap_phy_mux_ops = {
- .recalc_rate = phy_mux_recalc_rate,
- .determine_rate = phy_mux_determine_rate,
- .set_rate = phy_mux_set_rate,
+ .enable = phy_mux_enable,
+ .disable = phy_mux_disable,
+ .is_enabled = phy_mux_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
diff --git a/drivers/clk/qcom/dispcc-eliza.c b/drivers/clk/qcom/dispcc-eliza.c
index 760881cb1077..290018d1abe1 100644
--- a/drivers/clk/qcom/dispcc-eliza.c
+++ b/drivers/clk/qcom/dispcc-eliza.c
@@ -756,7 +756,7 @@ static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
.parent_data = disp_cc_parent_data_11,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_11),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_shared_ops,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
},
};
diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
index 2ba9976654cf..86953f9ffee3 100644
--- a/drivers/clk/rockchip/clk-rk3588.c
+++ b/drivers/clk/rockchip/clk-rk3588.c
@@ -895,7 +895,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
MUX(I2S2_2CH_MCLKOUT, "i2s2_2ch_mclkout", i2s2_2ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(30), 2, 1, MFLAGS),
GATE_GRF(I2S2_2CH_MCLKOUT_TO_IO, "i2s2_2ch_mclkout_to_io", "i2s2_2ch_mclkout",
- 0, RK3588_SYSGRF_SOC_CON6, 2, GFLAGS, grf_type_sys),
+ CLK_IGNORE_UNUSED, RK3588_SYSGRF_SOC_CON6, 2, GFLAGS, grf_type_sys),
COMPOSITE(CLK_I2S3_2CH_SRC, "clk_i2s3_2ch_src", gpll_aupll_p, 0,
RK3588_CLKSEL_CON(30), 8, 1, MFLAGS, 3, 5, DFLAGS,
@@ -912,7 +912,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
MUX(I2S3_2CH_MCLKOUT, "i2s3_2ch_mclkout", i2s3_2ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(32), 2, 1, MFLAGS),
GATE_GRF(I2S3_2CH_MCLKOUT_TO_IO, "i2s3_2ch_mclkout_to_io", "i2s3_2ch_mclkout",
- 0, RK3588_SYSGRF_SOC_CON6, 7, GFLAGS, grf_type_sys),
+ CLK_IGNORE_UNUSED, RK3588_SYSGRF_SOC_CON6, 7, GFLAGS, grf_type_sys),
GATE(PCLK_ACDCDIG, "pclk_acdcdig", "pclk_audio_root", 0,
RK3588_CLKGATE_CON(7), 11, GFLAGS),
GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_audio_root", 0,
@@ -942,7 +942,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
MUX(I2S0_8CH_MCLKOUT, "i2s0_8ch_mclkout", i2s0_8ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(28), 2, 2, MFLAGS),
GATE_GRF(I2S0_8CH_MCLKOUT_TO_IO, "i2s0_8ch_mclkout_to_io", "i2s0_8ch_mclkout",
- 0, RK3588_SYSGRF_SOC_CON6, 0, GFLAGS, grf_type_sys),
+ CLK_IGNORE_UNUSED, RK3588_SYSGRF_SOC_CON6, 0, GFLAGS, grf_type_sys),
GATE(HCLK_PDM1, "hclk_pdm1", "hclk_audio_root", 0,
RK3588_CLKGATE_CON(9), 6, GFLAGS),
@@ -2229,7 +2229,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
MUX(I2S1_8CH_MCLKOUT, "i2s1_8ch_mclkout", i2s1_8ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_PMU_CLKSEL_CON(9), 2, 2, MFLAGS),
GATE_GRF(I2S1_8CH_MCLKOUT_TO_IO, "i2s1_8ch_mclkout_to_io", "i2s1_8ch_mclkout",
- 0, RK3588_SYSGRF_SOC_CON6, 1, GFLAGS, grf_type_sys),
+ CLK_IGNORE_UNUSED, RK3588_SYSGRF_SOC_CON6, 1, GFLAGS, grf_type_sys),
GATE(PCLK_PMU1, "pclk_pmu1", "pclk_pmu0_root", CLK_IS_CRITICAL,
RK3588_PMU_CLKGATE_CON(1), 0, GFLAGS),
GATE(CLK_DDR_FAIL_SAFE, "clk_ddr_fail_safe", "clk_pmu0", CLK_IGNORE_UNUSED,
diff --git a/drivers/clk/spacemit/ccu-k3.c b/drivers/clk/spacemit/ccu-k3.c
index cb0c4277f72a..764426359540 100644
--- a/drivers/clk/spacemit/ccu-k3.c
+++ b/drivers/clk/spacemit/ccu-k3.c
@@ -777,7 +777,7 @@ static const struct clk_parent_data sdh2_parents[] = {
CCU_MUX_DIV_GATE_FC_DEFINE(sdh2_clk, sdh2_parents, APMU_SDH2_CLK_RES_CTRL, 8, 3,
BIT(11), 5, 3, BIT(4), 0);
-CCU_GATE_DEFINE(usb2_bus_clk, CCU_PARENT_HW(axi_clk), APMU_USB_CLK_RES_CTRL, BIT(0), 0);
+CCU_GATE_DEFINE(usb2_bus_clk, CCU_PARENT_HW(axi_clk), APMU_USB_CLK_RES_CTRL, BIT(1), 0);
CCU_GATE_DEFINE(usb3_porta_bus_clk, CCU_PARENT_HW(axi_clk), APMU_USB_CLK_RES_CTRL, BIT(4), 0);
CCU_GATE_DEFINE(usb3_portb_bus_clk, CCU_PARENT_HW(axi_clk), APMU_USB_CLK_RES_CTRL, BIT(8), 0);
CCU_GATE_DEFINE(usb3_portc_bus_clk, CCU_PARENT_HW(axi_clk), APMU_USB_CLK_RES_CTRL, BIT(12), 0);
@@ -1026,7 +1026,7 @@ CCU_MUX_DIV_GATE_DEFINE(isim_vclk_out3, isim_vclk_parents, APMU_SNR_ISIM_VCLK_CT
/* APMU clocks end */
/* DCIU clocks start */
-CCU_GATE_DEFINE(hdma_clk, CCU_PARENT_HW(axi_clk), DCIU_DMASYS_CLK_EN, BIT(0), 0);
+CCU_GATE_DEFINE(hdma_clk, CCU_PARENT_HW(axi_clk), DCIU_DMASYS_CLK_EN, BIT(0), CLK_IS_CRITICAL);
CCU_GATE_DEFINE(dma350_clk, CCU_PARENT_HW(axi_clk), DCIU_DMASYS_SDMA_CLK_EN, BIT(0), 0);
CCU_GATE_DEFINE(c2_tcm_pipe_clk, CCU_PARENT_HW(axi_clk), DCIU_C2_TCM_PIPE_CLK, BIT(0), 0);
CCU_GATE_DEFINE(c3_tcm_pipe_clk, CCU_PARENT_HW(axi_clk), DCIU_C3_TCM_PIPE_CLK, BIT(0), 0);
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 4adf756423de..7b4a98df6962 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1090,6 +1090,27 @@ static int __init arch_timer_common_init(void)
return arch_timer_arch_init();
}
+static bool __init has_broken_el2_vtimer(void)
+{
+ /*
+ * SoCs described here have been found to be broken, though no
+ * explanation has been volunteered by the vendor. Let the user know
+ * we're papering over the vendor's lack of communication.
+ */
+ static const char * const broken_el2_vtimer[] __initconst = {
+ "brcm,bcm2712",
+ NULL
+ };
+
+ if (of_machine_compatible_match(broken_el2_vtimer)) {
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+ pr_warn_once(HW_ERR "Known broken EL2 virtual timer, ignoring it\n");
+ return true;
+ }
+
+ return false;
+}
+
/**
* arch_timer_select_ppi() - Select suitable PPI for the current system.
*
@@ -1115,7 +1136,8 @@ static int __init arch_timer_common_init(void)
static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
{
if (is_kernel_in_hyp_mode()) {
- if (arch_timer_ppi[ARCH_TIMER_HYP_VIRT_PPI])
+ if (arch_timer_ppi[ARCH_TIMER_HYP_VIRT_PPI] &&
+ !has_broken_el2_vtimer())
return ARCH_TIMER_HYP_VIRT_PPI;
pr_warn_once(FW_BUG "VHE-capable CPU without EL2 virtual timer interrupt\n");
diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index ac74f69914d6..ea5b9689ce68 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -58,7 +58,7 @@ static int devm_qce_register_algs(struct qce_device *qce)
ret = ops->register_algs(qce);
if (ret) {
for (j = i - 1; j >= 0; j--)
- ops->unregister_algs(qce);
+ qce_ops[j]->unregister_algs(qce);
return ret;
}
}
diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c
index a0713aa21250..f59adb2a5651 100644
--- a/drivers/crypto/starfive/jh7110-aes.c
+++ b/drivers/crypto/starfive/jh7110-aes.c
@@ -677,7 +677,7 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq
if (cryp->total_in)
sg_zero_buffer(rctx->in_sg, sg_nents(rctx->in_sg),
- sg_dma_len(rctx->in_sg) - cryp->total_in,
+ rctx->in_sg->length - cryp->total_in,
cryp->total_in);
ctx->rctx = rctx;
diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c
index 9094c03e991f..0fd1d7035899 100644
--- a/drivers/crypto/tegra/tegra-se-aes.c
+++ b/drivers/crypto/tegra/tegra-se-aes.c
@@ -45,7 +45,6 @@ struct tegra_aes_reqctx {
struct tegra_aead_ctx {
struct tegra_se *se;
- unsigned int authsize;
u32 alg;
u32 key_id;
u32 keylen;
@@ -1290,7 +1289,7 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
if (rctx->encrypt)
rctx->cryptlen = req->cryptlen;
else
- rctx->cryptlen = req->cryptlen - ctx->authsize;
+ rctx->cryptlen = req->cryptlen - rctx->authsize;
memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);
rctx->iv[3] = (1 << 24);
@@ -1394,8 +1393,6 @@ static int tegra_aead_cra_init(struct crypto_aead *tfm)
static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
- struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm);
-
switch (authsize) {
case 4:
case 6:
@@ -1404,28 +1401,15 @@ static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize
case 12:
case 14:
case 16:
- break;
+ return 0;
default:
return -EINVAL;
}
-
- ctx->authsize = authsize;
-
- return 0;
}
static int tegra_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
- struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm);
- int ret;
-
- ret = crypto_gcm_check_authsize(authsize);
- if (ret)
- return ret;
-
- ctx->authsize = authsize;
-
- return 0;
+ return crypto_gcm_check_authsize(authsize);
}
static void tegra_aead_cra_exit(struct crypto_aead *tfm)
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index fd5caf1e19a8..649e4e375be3 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -335,7 +335,6 @@ static int dibs_lo_dev_probe(void)
return 0;
err_reg:
- kfree(dibs->dmb_clientid_arr);
/* pairs with dibs_dev_alloc() */
put_device(&dibs->dev);
kfree(ldev);
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index 4c26fd06973f..2b53a9d277dc 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -128,6 +128,7 @@ static void dibs_dev_release(struct device *dev)
dibs = container_of(dev, struct dibs_dev, dev);
+ kfree(dibs->dmb_clientid_arr);
kfree(dibs);
}
@@ -194,12 +195,13 @@ int dibs_dev_add(struct dibs_dev *dibs)
ret = device_add(&dibs->dev);
if (ret)
- goto free_client_arr;
+ return ret;
ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
if (ret) {
dev_err(&dibs->dev, "sysfs_create_group failed for dibs_dev\n");
- goto err_device_del;
+ device_del(&dibs->dev);
+ return ret;
}
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
@@ -214,13 +216,6 @@ int dibs_dev_add(struct dibs_dev *dibs)
mutex_unlock(&dibs_dev_list.mutex);
return 0;
-
-err_device_del:
- device_del(&dibs->dev);
-free_client_arr:
- kfree(dibs->dmb_clientid_arr);
- return ret;
-
}
EXPORT_SYMBOL_GPL(dibs_dev_add);
@@ -247,7 +242,6 @@ void dibs_dev_del(struct dibs_dev *dibs)
mutex_unlock(&dibs_dev_list.mutex);
device_del(&dibs->dev);
- kfree(dibs->dmb_clientid_arr);
}
EXPORT_SYMBOL_GPL(dibs_dev_del);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 8153d62c58f0..e947227e01ac 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -540,11 +540,13 @@ static void ar_context_link_page(struct ar_context *ctx, unsigned int index)
static void ar_context_release(struct ar_context *ctx)
{
- struct device *dev = ctx->ohci->card.device;
+ struct device *dev;
if (!ctx->buffer)
return;
+ dev = ctx->ohci->card.device;
+
for (int i = 0; i < AR_BUFFERS; ++i) {
dma_addr_t dma_addr = ctx->dma_addrs[i];
if (dma_addr)
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 6576e5dcb0ee..391188c0f2c2 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -73,7 +73,7 @@ struct ioh_gpio_reg_data {
* @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM
* @ch: Indicate GPIO channel
* @irq_base: Save base of IRQ number for interrupt
- * @spinlock: Used for register access protection
+ * @spinlock: Shared register access lock
*/
struct ioh_gpio {
void __iomem *base;
@@ -84,7 +84,12 @@ struct ioh_gpio {
u32 gpio_use_sel;
int ch;
int irq_base;
- spinlock_t spinlock;
+ raw_spinlock_t *spinlock;
+};
+
+struct ioh_gpio_device {
+ raw_spinlock_t spinlock;
+ struct ioh_gpio chip[8];
};
static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
@@ -95,7 +100,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
struct ioh_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
reg_val = ioread32(&chip->reg->regs[chip->ch].po);
if (val)
reg_val |= BIT(nr);
@@ -103,7 +108,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
return 0;
}
@@ -123,7 +128,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
u32 reg_val;
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
pm = ioread32(&chip->reg->regs[chip->ch].pm);
pm &= BIT(num_ports[chip->ch]) - 1;
pm |= BIT(nr);
@@ -136,7 +141,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
return 0;
}
@@ -147,12 +152,12 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
u32 pm;
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
pm = ioread32(&chip->reg->regs[chip->ch].pm);
pm &= BIT(num_ports[chip->ch]) - 1;
pm &= ~BIT(nr);
iowrite32(pm, &chip->reg->regs[chip->ch].pm);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
return 0;
}
@@ -256,7 +261,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
__func__, irq, type, ch, im_pos, type);
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -296,7 +301,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
ien = ioread32(&chip->reg->regs[chip->ch].ien);
iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
end:
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
return 0;
}
@@ -326,11 +331,11 @@ static void ioh_irq_disable(struct irq_data *d)
unsigned long flags;
u32 ien;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
ien = ioread32(&chip->reg->regs[chip->ch].ien);
ien &= ~BIT(d->irq - chip->irq_base);
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
}
static void ioh_irq_enable(struct irq_data *d)
@@ -340,11 +345,11 @@ static void ioh_irq_enable(struct irq_data *d)
unsigned long flags;
u32 ien;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
ien = ioread32(&chip->reg->regs[chip->ch].ien);
ien |= BIT(d->irq - chip->irq_base);
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
}
static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
@@ -407,8 +412,8 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
int ret;
int i, j;
struct ioh_gpio *chip;
+ struct ioh_gpio_device *priv;
void __iomem *base;
- void *chip_save;
int irq_base;
ret = pcim_enable_device(pdev);
@@ -429,18 +434,18 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return -ENOMEM;
}
- chip_save = devm_kcalloc(dev, 8, sizeof(*chip), GFP_KERNEL);
- if (chip_save == NULL) {
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }
- chip = chip_save;
+ raw_spin_lock_init(&priv->spinlock);
+ chip = priv->chip;
for (i = 0; i < 8; i++, chip++) {
chip->dev = dev;
chip->base = base;
chip->reg = chip->base;
chip->ch = i;
- spin_lock_init(&chip->spinlock);
+ chip->spinlock = &priv->spinlock;
ioh_gpio_setup(chip, num_ports[i]);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
if (ret) {
@@ -449,7 +454,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
}
}
- chip = chip_save;
+ chip = priv->chip;
for (j = 0; j < 8; j++, chip++) {
irq_base = devm_irq_alloc_descs(dev, -1, IOH_IRQ_BASE,
num_ports[j], NUMA_NO_NODE);
@@ -466,7 +471,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return ret;
}
- chip = chip_save;
+ chip = priv->chip;
ret = devm_request_irq(dev, pdev->irq, ioh_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret != 0) {
@@ -474,33 +479,33 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return ret;
}
- pci_set_drvdata(pdev, chip);
+ pci_set_drvdata(pdev, priv);
return 0;
}
static int ioh_gpio_suspend(struct device *dev)
{
- struct ioh_gpio *chip = dev_get_drvdata(dev);
+ struct ioh_gpio_device *priv = dev_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
- ioh_gpio_save_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&priv->spinlock, flags);
+ ioh_gpio_save_reg_conf(priv->chip);
+ raw_spin_unlock_irqrestore(&priv->spinlock, flags);
return 0;
}
static int ioh_gpio_resume(struct device *dev)
{
- struct ioh_gpio *chip = dev_get_drvdata(dev);
+ struct ioh_gpio_device *priv = dev_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
- iowrite32(0x01, &chip->reg->srst);
- iowrite32(0x00, &chip->reg->srst);
- ioh_gpio_restore_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&priv->spinlock, flags);
+ iowrite32(0x01, &priv->chip->reg->srst);
+ iowrite32(0x00, &priv->chip->reg->srst);
+ ioh_gpio_restore_reg_conf(priv->chip);
+ raw_spin_unlock_irqrestore(&priv->spinlock, flags);
return 0;
}
diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c
index aa23b5779802..2f9a1f0384ad 100644
--- a/drivers/gpio/gpio-sloppy-logic-analyzer.c
+++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c
@@ -300,7 +300,7 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
debugfs_create_ulong("delay_ns_acquisition", 0400, priv->debug_dir, &priv->acq_delay);
debugfs_create_file_unsafe("buf_size", 0600, priv->debug_dir, priv, &fops_buf_size);
debugfs_create_file_unsafe("capture", 0200, priv->debug_dir, priv, &fops_capture);
- debugfs_create_file_unsafe("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
+ debugfs_create_file("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
return 0;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c433a095907f..ef8ccaf17c9c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -5420,7 +5420,8 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *gc)
flags = READ_ONCE(desc->flags);
is_irq = test_bit(GPIOD_FLAG_USED_AS_IRQ, &flags);
if (is_irq || test_bit(GPIOD_FLAG_REQUESTED, &flags)) {
- gpiod_get_direction(desc);
+ if (gc->get_direction)
+ gpiod_get_direction(desc);
is_out = test_bit(GPIOD_FLAG_IS_OUT, &flags);
value = gpio_chip_get_value(gc, desc);
active_low = test_bit(GPIOD_FLAG_ACTIVE_LOW, &flags);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 5e23bf11f046..35d76cfbc88a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -248,6 +248,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
if (size < sizeof(struct drm_amdgpu_cs_chunk_fence))
goto free_partial_kdata;
+ /* Only a single user fence is allowed to simplify handling. */
+ if (p->uf_bo)
+ goto free_partial_kdata;
+
ret = amdgpu_cs_p1_user_fence(p, p->chunks[i].kdata,
&uf_offset);
if (ret)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index e43024ad4feb..e84b75c03c6f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1370,6 +1370,31 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
#endif
}
+/*
+ * Some dGPUs expose their display endpoint below an internal PCIe switch.
+ * Use the switch upstream port to query the host-facing link.
+ */
+static struct pci_dev *amdgpu_device_get_aspm_pdev(struct amdgpu_device *adev)
+{
+ struct pci_dev *swds, *swus;
+
+ swds = pci_upstream_bridge(adev->pdev);
+ if (!swds ||
+ (swds->vendor != PCI_VENDOR_ID_ATI &&
+ swds->vendor != PCI_VENDOR_ID_AMD) ||
+ pci_pcie_type(swds) != PCI_EXP_TYPE_DOWNSTREAM)
+ return adev->pdev;
+
+ swus = pci_upstream_bridge(swds);
+ if (!swus ||
+ (swus->vendor != PCI_VENDOR_ID_ATI &&
+ swus->vendor != PCI_VENDOR_ID_AMD) ||
+ pci_pcie_type(swus) != PCI_EXP_TYPE_UPSTREAM)
+ return adev->pdev;
+
+ return swus;
+}
+
/**
* amdgpu_device_should_use_aspm - check if the device should program ASPM
*
@@ -1382,6 +1407,9 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
*/
bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
{
+ struct pci_dev *aspm_pdev, *parent;
+ bool enabled;
+
switch (amdgpu_aspm) {
case -1:
break;
@@ -1396,7 +1424,27 @@ bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
return false;
if (amdgpu_device_aspm_support_quirk(adev))
return false;
- return pcie_aspm_enabled(adev->pdev);
+
+ /*
+ * pcie_aspm_enabled() checks the link between its argument and
+ * the immediate upstream bridge. Use SWUS for dGPUs with an
+ * internal switch so that this is the host-facing link.
+ */
+ aspm_pdev = amdgpu_device_get_aspm_pdev(adev);
+ parent = pci_upstream_bridge(aspm_pdev);
+ if (!parent) {
+ dev_dbg(adev->dev, "ASPM: no upstream PCIe link for %s\n",
+ pci_name(aspm_pdev));
+ return false;
+ }
+
+ enabled = pcie_aspm_enabled(aspm_pdev);
+ /* Report the exact link used for the automatic ASPM decision. */
+ dev_dbg(adev->dev, "ASPM: link %s <-> %s is %s\n",
+ pci_name(parent), pci_name(aspm_pdev),
+ enabled ? "enabled" : "disabled");
+
+ return enabled;
}
/* if we get transitioned to only one device, take VGA back */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 5e83edbd313b..47e0680ed7b1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -311,6 +311,19 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev,
goto out;
}
} else {
+ if (adev->discovery.offset) {
+ u32 signature;
+
+ /* If VRAM holds a valid discovery signature at the default
+ * discovery offset, use it as-is.
+ */
+ amdgpu_device_vram_access(adev, adev->discovery.offset,
+ &signature, sizeof(signature),
+ false);
+ if (le32_to_cpu(signature) == BINARY_SIGNATURE)
+ goto out;
+ }
+
tmr_size = RREG32(mmDRIVER_SCRATCH_2);
if (tmr_size) {
/* It's preferred to transition to PSP mailbox reg interface
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 6a0699746fbc..f754a4a3a1c2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -397,6 +397,25 @@ const struct drm_gem_object_funcs amdgpu_gem_object_funcs = {
.vm_ops = &amdgpu_gem_vm_ops,
};
+static bool amdgpu_gem_are_domains_valid(u32 domains)
+{
+ u32 normal = AMDGPU_GEM_DOMAIN_CPU |
+ AMDGPU_GEM_DOMAIN_GTT |
+ AMDGPU_GEM_DOMAIN_VRAM;
+ /* Treat all non CPU/GTT/VRAM domains as special domains. */
+ u32 special = AMDGPU_GEM_DOMAIN_MASK & ~normal;
+ u32 normal_mask = domains & normal;
+ u32 special_mask = domains & special;
+
+ if (!special_mask)
+ return true;
+
+ if (normal_mask)
+ return false;
+
+ return !(special_mask & (special_mask - 1));
+}
+
/*
* GEM ioctls.
*/
@@ -421,6 +440,8 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
/* reject invalid gem domains */
if (args->in.domains & ~AMDGPU_GEM_DOMAIN_MASK)
return -EINVAL;
+ if (!amdgpu_gem_are_domains_valid(args->in.domains))
+ return -EINVAL;
if (!amdgpu_is_tmz(adev) && (flags & AMDGPU_GEM_CREATE_ENCRYPTED)) {
DRM_NOTE_ONCE("Cannot allocate secure buffer since TMZ is disabled\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index 23383ac5323f..de3dbc95e376 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -646,17 +646,15 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
unsigned int height = msg[7];
unsigned int dpb_size = msg[9];
unsigned int pitch = msg[28];
- unsigned int level = msg[57];
unsigned int width_in_mb = width / 16;
unsigned int height_in_mb = ALIGN(height / 16, 2);
- unsigned int fs_in_mb = width_in_mb * height_in_mb;
unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;
unsigned int min_ctx_size = ~0;
- /* Reject invalid dimensions to prevent division by zero */
- if (width < 16 || height < 16) {
+ /* Reject invalid dimensions */
+ if (width < 16 || height < 16 || width > 4096 || height > 4096) {
dev_WARN_ONCE(adev->dev, 1,
"Invalid UVD decoding dimensions (%dx%d)!\n",
width, height);
@@ -669,35 +667,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
switch (stream_type) {
case 0: /* H264 */
- switch (level) {
- case 30:
- num_dpb_buffer = 8100 / fs_in_mb;
- break;
- case 31:
- num_dpb_buffer = 18000 / fs_in_mb;
- break;
- case 32:
- num_dpb_buffer = 20480 / fs_in_mb;
- break;
- case 41:
- num_dpb_buffer = 32768 / fs_in_mb;
- break;
- case 42:
- num_dpb_buffer = 34816 / fs_in_mb;
- break;
- case 50:
- num_dpb_buffer = 110400 / fs_in_mb;
- break;
- case 51:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- default:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- }
- num_dpb_buffer++;
+ num_dpb_buffer = ((msg[61] >> 16) & 0xff) + 1;
if (num_dpb_buffer > 17)
- num_dpb_buffer = 17;
+ return -EINVAL;
/* reference picture buffer */
min_dpb_size = image_size * num_dpb_buffer;
@@ -747,35 +719,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
break;
case 7: /* H264 Perf */
- switch (level) {
- case 30:
- num_dpb_buffer = 8100 / fs_in_mb;
- break;
- case 31:
- num_dpb_buffer = 18000 / fs_in_mb;
- break;
- case 32:
- num_dpb_buffer = 20480 / fs_in_mb;
- break;
- case 41:
- num_dpb_buffer = 32768 / fs_in_mb;
- break;
- case 42:
- num_dpb_buffer = 34816 / fs_in_mb;
- break;
- case 50:
- num_dpb_buffer = 110400 / fs_in_mb;
- break;
- case 51:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- default:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- }
- num_dpb_buffer++;
+ num_dpb_buffer = ((msg[61] >> 16) & 0xff) + 1;
if (num_dpb_buffer > 17)
- num_dpb_buffer = 17;
+ return -EINVAL;
/* reference picture buffer */
min_dpb_size = image_size * num_dpb_buffer;
@@ -803,6 +749,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
image_size = ALIGN(image_size, 256);
num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
+ if (num_dpb_buffer > 17)
+ return -EINVAL;
+
min_dpb_size = image_size * num_dpb_buffer;
min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16)
* 16 * num_dpb_buffer + 52 * 1024;
@@ -813,7 +762,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
return -EINVAL;
}
- if (width > pitch) {
+ if (width > pitch || pitch > 4096) {
DRM_ERROR("Invalid UVD decoding target pitch!\n");
return -EINVAL;
}
@@ -825,7 +774,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
}
buf_sizes[0x1] = dpb_size;
- buf_sizes[0x2] = image_size;
+ buf_sizes[0x2] = (pitch * height) * 3 / 2;
buf_sizes[0x4] = min_ctx_size;
/* store image width to adjust nb memory pstate */
adev->uvd.decode_image_width = width;
@@ -972,15 +921,16 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
ctx->buf_sizes[cmd]);
return -EINVAL;
}
+ } else if (cmd == 0x204 || cmd == 0x206) {
+ unsigned int min_size = ctx->buf_sizes[cmd == 0x204 ? 5 : 4];
- } else if (cmd == 0x206) {
- if ((end - start) < ctx->buf_sizes[4]) {
+ if ((end - start) < min_size) {
DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
(unsigned int)(end - start),
- ctx->buf_sizes[4]);
+ min_size);
return -EINVAL;
}
- } else if ((cmd != 0x100) && (cmd != 0x204)) {
+ } else if ((cmd != 0x100)) {
DRM_ERROR("invalid UVD command %X!\n", cmd);
return -EINVAL;
}
@@ -1110,11 +1060,12 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser,
{
struct amdgpu_uvd_cs_ctx ctx = {};
unsigned int buf_sizes[] = {
- [0x00000000] = 2048,
+ [0x00000000] = 3556,
[0x00000001] = 0xFFFFFFFF,
[0x00000002] = 0xFFFFFFFF,
[0x00000003] = 2048,
[0x00000004] = 0xFFFFFFFF,
+ [0x00000005] = 992,
};
int r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index dc6a9d7dd0b2..1baad7624f1f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -800,6 +800,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
mutex_unlock(&id_mgr->lock);
gds_switch_needed &= !!ring->funcs->emit_gds_switch;
+ spm_update_needed &= !!adev->gfx.rlc.funcs->update_spm_vmid;
vm_flush_needed &= !!ring->funcs->emit_vm_flush &&
job->vm_pd_addr != AMDGPU_BO_INVALID_OFFSET;
pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping &&
@@ -811,7 +812,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
&job->base.s_fence->scheduled == isolation->spearhead;
if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync &&
- !cleaner_shader_needed)
+ !cleaner_shader_needed && !spm_update_needed)
return;
amdgpu_ring_ib_begin(ring);
diff --git a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
index 000516b5845a..61eb0513dc97 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
@@ -500,7 +500,6 @@ static u32 nbif_v6_3_1_get_rom_offset(struct amdgpu_device *adev)
static void nbif_v6_3_1_program_ltr(struct amdgpu_device *adev)
{
uint32_t def, data;
- u16 devctl2;
def = RREG32_SOC15(NBIO, 0, regRCC_EP_DEV0_0_EP_PCIE_TX_LTR_CNTL);
data = 0x35EB;
@@ -514,15 +513,8 @@ static void nbif_v6_3_1_program_ltr(struct amdgpu_device *adev)
if (def != data)
WREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP2, data);
- pcie_capability_read_word(adev->pdev, PCI_EXP_DEVCTL2, &devctl2);
-
- if (adev->pdev->ltr_path == (devctl2 & PCI_EXP_DEVCTL2_LTR_EN))
- return;
-
- if (adev->pdev->ltr_path)
- pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
- else
- pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
+ pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
}
#endif
@@ -530,7 +522,7 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
{
#ifdef CONFIG_PCIEASPM
uint32_t def, data;
- u16 devctl2, ltr;
+ u16 ltr;
def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL);
data &= ~PCIE_LC_CNTL__LC_L1_INACTIVITY_MASK;
@@ -560,11 +552,8 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
if (def != data)
WREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP5, data);
- pcie_capability_read_word(adev->pdev, PCI_EXP_DEVCTL2, &devctl2);
- data = def = devctl2;
- data &= ~PCI_EXP_DEVCTL2_LTR_EN;
- if (def != data)
- pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, (u16)data);
+ pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
ltr = pci_find_ext_capability(adev->pdev, PCI_EXT_CAP_ID_LTR);
@@ -572,15 +561,13 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
pci_write_config_dword(adev->pdev, ltr + PCI_LTR_MAX_SNOOP_LAT, 0x10011001);
}
-#if 0
- /* regPSWUSP0_PCIE_LC_CNTL2 should be replace by PCIE_LC_CNTL2 or someone else ? */
- def = data = RREG32_SOC15(NBIO, 0, regPSWUSP0_PCIE_LC_CNTL2);
- data |= PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK |
- PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK;
- data &= ~PSWUSP0_PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK;
+ def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL2);
+ data |= PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK |
+ PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK;
+ data &= ~PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK;
if (def != data)
- WREG32_SOC15(NBIO, 0, regPSWUSP0_PCIE_LC_CNTL2, data);
-#endif
+ WREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL2, data);
+
def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL4);
data |= PCIE_LC_CNTL4__LC_L1_POWERDOWN_MASK;
if (def != data)
@@ -591,7 +578,12 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
if (def != data)
WREG32_SOC15(PCIE, 0, regPCIE_LC_RXRECOVER_RXSTANDBY_CNTL, data);
- nbif_v6_3_1_program_ltr(adev);
+ /*
+ * Do not enable endpoint LTR unless the Root Complex and every
+ * upstream switch support it.
+ */
+ if (adev->pdev->ltr_path)
+ nbif_v6_3_1_program_ltr(adev);
def = data = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP3);
data |= 0x5DE0 << RCC_STRAP0_RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT;
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index c69f7d82060f..a3eae7d4b57e 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -875,6 +875,23 @@ static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, ib->length_dw);
}
+static void vce_v3_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+ u64 seq, unsigned flags)
+{
+ WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+
+ amdgpu_ring_write(ring, VCE_CMD_FENCE);
+ amdgpu_ring_write(ring, addr);
+ amdgpu_ring_write(ring, upper_32_bits(addr));
+ amdgpu_ring_write(ring, seq);
+ amdgpu_ring_write(ring, VCE_CMD_TRAP);
+}
+
+static void vce_v3_0_ring_insert_end(struct amdgpu_ring *ring)
+{
+ amdgpu_ring_write(ring, VCE_CMD_END);
+}
+
static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
unsigned int vmid, uint64_t pd_addr)
{
@@ -884,7 +901,6 @@ static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB);
amdgpu_ring_write(ring, vmid);
- amdgpu_ring_write(ring, VCE_CMD_END);
}
static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring)
@@ -953,17 +969,19 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
.set_wptr = vce_v3_0_ring_set_wptr,
.patch_cs_in_place = amdgpu_vce_ring_parse_cs_vm,
.emit_frame_size =
- 6 + /* vce_v3_0_emit_vm_flush */
+ 5 + /* vce_v3_0_emit_vm_flush */
4 + /* vce_v3_0_emit_pipeline_sync */
- 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */
+ 5 + 5 + /* vce_v3_0_ring_emit_fence x2 vm fence */
+ 1, /* vce_v3_0_ring_insert_end */
.emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */
.emit_ib = vce_v3_0_ring_emit_ib,
.emit_vm_flush = vce_v3_0_emit_vm_flush,
.emit_pipeline_sync = vce_v3_0_emit_pipeline_sync,
- .emit_fence = amdgpu_vce_ring_emit_fence,
+ .emit_fence = vce_v3_0_ring_emit_fence,
.test_ring = amdgpu_vce_ring_test_ring,
.test_ib = amdgpu_vce_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
+ .insert_end = vce_v3_0_ring_insert_end,
.pad_ib = amdgpu_ring_generic_pad_ib,
.begin_use = amdgpu_vce_ring_begin_use,
.end_use = amdgpu_vce_ring_end_use,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 06598273d481..56bf907f1f6c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -257,7 +257,7 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id);
- if (enable) {
+ if (enable && acrtc_state->stream) {
struct dc *dc = adev->dm.dc;
struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
struct psr_settings *psr = &acrtc_state->stream->link->psr_settings;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index 88446817a71f..7f362c3926c6 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -58,7 +58,8 @@ enum dc_color_space_type {
COLOR_SPACE_RGB_LIMITED_TYPE,
COLOR_SPACE_YCBCR601_TYPE,
COLOR_SPACE_YCBCR709_TYPE,
- COLOR_SPACE_YCBCR2020_TYPE,
+ COLOR_SPACE_YCBCR2020_LIMITED_TYPE,
+ COLOR_SPACE_YCBCR2020_FULL_TYPE,
COLOR_SPACE_YCBCR601_LIMITED_TYPE,
COLOR_SPACE_YCBCR709_LIMITED_TYPE,
COLOR_SPACE_YCBCR709_BLACK_TYPE,
@@ -110,9 +111,15 @@ static const struct out_csc_color_matrix_type output_csc_matrix[] = {
{ 0xE00, 0xF349, 0xFEB7, 0x1000,
0x6CE, 0x16E3, 0x24F, 0x200,
0xFCCB, 0xF535, 0xE00, 0x1000} },
- { COLOR_SPACE_YCBCR2020_TYPE,
+ /* Corrected. Not included in the TODO above. */
+ { COLOR_SPACE_YCBCR2020_LIMITED_TYPE,
+ { 0x0E04, 0xF31D, 0xFEDF, 0x1004,
+ 0x0733, 0x1294, 0x01A0, 0x0201,
+ 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
+ /* Corrected. Not included in the TODO above. */
+ { COLOR_SPACE_YCBCR2020_FULL_TYPE,
{ 0x1000, 0xF149, 0xFEB7, 0x1004,
- 0x0868, 0x15B2, 0x01E6, 0x201,
+ 0x0868, 0x15B2, 0x01E6, 0,
0xFB88, 0xF478, 0x1000, 0x1004} },
{ COLOR_SPACE_YCBCR709_BLACK_TYPE,
{ 0x0000, 0x0000, 0x0000, 0x1000,
@@ -179,14 +186,14 @@ static bool is_ycbcr709_type(
return ret;
}
-static bool is_ycbcr2020_type(
- enum dc_color_space color_space)
+static bool is_ycbcr2020_limited_type(enum dc_color_space color_space)
{
- bool ret = false;
+ return color_space == COLOR_SPACE_2020_YCBCR_LIMITED;
+}
- if (color_space == COLOR_SPACE_2020_YCBCR_LIMITED || color_space == COLOR_SPACE_2020_YCBCR_FULL)
- ret = true;
- return ret;
+static bool is_ycbcr2020_full_type(enum dc_color_space color_space)
+{
+ return color_space == COLOR_SPACE_2020_YCBCR_FULL;
}
static bool is_ycbcr709_limited_type(
@@ -215,8 +222,10 @@ static enum dc_color_space_type get_color_space_type(enum dc_color_space color_s
type = COLOR_SPACE_YCBCR601_LIMITED_TYPE;
else if (is_ycbcr709_limited_type(color_space))
type = COLOR_SPACE_YCBCR709_LIMITED_TYPE;
- else if (is_ycbcr2020_type(color_space))
- type = COLOR_SPACE_YCBCR2020_TYPE;
+ else if (is_ycbcr2020_limited_type(color_space))
+ type = COLOR_SPACE_YCBCR2020_LIMITED_TYPE;
+ else if (is_ycbcr2020_full_type(color_space))
+ type = COLOR_SPACE_YCBCR2020_FULL_TYPE;
else if (color_space == COLOR_SPACE_YCBCR709)
type = COLOR_SPACE_YCBCR709_BLACK_TYPE;
else if (color_space == COLOR_SPACE_YCBCR709_BLACK)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
index 12c85c3afd6a..a51c9b282055 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
@@ -115,10 +115,11 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
-{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
- 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
+/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */
+{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733,
+ 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
- 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
+ 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} }
};
static bool setup_scaling_configuration(
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
index 1ed018aaa4bb..f5f8cd2d47a5 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
@@ -93,10 +93,11 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
-{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
- 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
+/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */
+{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733,
+ 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
- 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
+ 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} }
};
enum csc_color_mode {
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index dc43fd790a9c..4a99c09f4164 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -71,6 +71,7 @@ void radeon_driver_unload_kms(struct drm_device *dev)
if (radeon_is_px(dev)) {
pm_runtime_get_sync(dev->dev);
pm_runtime_forbid(dev->dev);
+ pm_runtime_dont_use_autosuspend(dev->dev);
}
radeon_acpi_fini(rdev);
diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c
index 5f4a0cd8deca..73469ea5f333 100644
--- a/drivers/gpu/drm/xe/display/xe_fb_pin.c
+++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
@@ -164,31 +164,14 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
dpt_size = ALIGN(intel_rotation_info_size(&view->rotated) * 8,
XE_PAGE_SIZE);
- if (IS_DGFX(xe))
- dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
- dpt_size, ~0ull,
- ttm_bo_type_kernel,
- XE_BO_FLAG_VRAM0 |
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_PAGETABLE,
- pin_params->alignment, false);
- else
- dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
- dpt_size, ~0ull,
- ttm_bo_type_kernel,
- XE_BO_FLAG_STOLEN |
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_PAGETABLE,
- pin_params->alignment, false);
- if (IS_ERR(dpt))
- dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
- dpt_size, ~0ull,
- ttm_bo_type_kernel,
- XE_BO_FLAG_SYSTEM |
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_PAGETABLE |
- XE_BO_FLAG_FORCE_WC,
- pin_params->alignment, false);
+ dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+ dpt_size, ~0ull,
+ ttm_bo_type_kernel,
+ XE_BO_FLAG_VRAM_IF_DGFX(tile0) |
+ XE_BO_FLAG_GGTT |
+ XE_BO_FLAG_PAGETABLE |
+ XE_BO_FLAG_FORCE_WC,
+ pin_params->alignment, false);
if (IS_ERR(dpt))
return PTR_ERR(dpt);
diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
index 7ae1d9ac0574..57039cf42ea7 100644
--- a/drivers/gpu/drm/xe/xe_bo.h
+++ b/drivers/gpu/drm/xe/xe_bo.h
@@ -6,6 +6,7 @@
#ifndef _XE_BO_H_
#define _XE_BO_H_
+#include <drm/drm_prime.h>
#include <drm/ttm/ttm_tt.h>
#include "xe_bo_types.h"
@@ -548,6 +549,19 @@ void xe_bo_dev_fini(struct xe_bo_dev *bo_device);
struct sg_table *xe_bo_sg(struct xe_bo *bo);
+/**
+ * xe_bo_sg_is_contiguous() - Check if a BO's DMA address space is contiguous.
+ * @bo: the BO to check (must have a valid sg table, i.e. !xe_bo_is_vram())
+ * @len: required contiguous length in bytes
+ *
+ * Returns true if the first @len bytes of the BO are mapped to a contiguous
+ * DMA address range.
+ */
+static inline bool xe_bo_sg_is_contiguous(struct xe_bo *bo, size_t len)
+{
+ return drm_prime_get_contiguous_size(xe_bo_sg(bo)) >= len;
+}
+
/*
* xe_sg_segment_size() - Provides upper limit for sg segment size.
* @dev: device pointer
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index dcb48caa485d..a2b076b1dc60 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -1102,7 +1102,11 @@ int xe_device_probe(struct xe_device *xe)
if (err)
goto err_unregister_display;
- return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
+ err = devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
+ if (err)
+ goto err_unregister_display;
+
+ return 0;
err_unregister_display:
xe_display_unregister(xe);
diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c
index c98454545a85..886bafd31f45 100644
--- a/drivers/gpu/drm/xe/xe_guc_ads.c
+++ b/drivers/gpu/drm/xe/xe_guc_ads.c
@@ -63,10 +63,14 @@ ads_to_map(struct xe_guc_ads *ads)
/*
* The Additional Data Struct (ADS) has pointers for different buffers used by
- * the GuC. One single gem object contains the ADS struct itself (guc_ads) and
- * all the extra buffers indirectly linked via the ADS struct's entries.
+ * the GuC. One gem object (ads->bo) contains the ADS struct itself (guc_ads)
+ * and most of the extra buffers linked via the ADS struct's entries. The UM
+ * fault queues (PAGE_FAULT, PAGE_FAULT_RESPONSE, ACCESS_COUNTER rings) are
+ * kept in a separate BO (ads->um_queue_bo) so that the full memset of ads->bo
+ * performed on every GT reset does not discard fault descriptors already
+ * written into the rings by the GPU.
*
- * Layout of the ADS blob allocated for the GuC:
+ * Layout of the ADS blob (ads->bo):
*
* +---------------------------------------+ <== base
* | guc_ads |
@@ -98,10 +102,6 @@ ads_to_map(struct xe_guc_ads *ads)
* +---------------------------------------+
* | padding |
* +---------------------------------------+ <== 4K aligned
- * | UM queues |
- * +---------------------------------------+
- * | padding |
- * +---------------------------------------+ <== 4K aligned
* | private data |
* +---------------------------------------+
* | padding |
@@ -155,16 +155,6 @@ static size_t guc_ads_capture_size(struct xe_guc_ads *ads)
return PAGE_ALIGN(ads->capture_size);
}
-static size_t guc_ads_um_queues_size(struct xe_guc_ads *ads)
-{
- struct xe_device *xe = ads_to_xe(ads);
-
- if (!xe->info.has_usm)
- return 0;
-
- return GUC_UM_QUEUE_SIZE * GUC_UM_HW_QUEUE_MAX;
-}
-
static size_t guc_ads_private_data_size(struct xe_guc_ads *ads)
{
return PAGE_ALIGN(ads_to_guc(ads)->fw.private_data_size);
@@ -205,22 +195,12 @@ static size_t guc_ads_capture_offset(struct xe_guc_ads *ads)
return PAGE_ALIGN(offset);
}
-static size_t guc_ads_um_queues_offset(struct xe_guc_ads *ads)
-{
- u32 offset;
-
- offset = guc_ads_capture_offset(ads) +
- guc_ads_capture_size(ads);
-
- return PAGE_ALIGN(offset);
-}
-
static size_t guc_ads_private_data_offset(struct xe_guc_ads *ads)
{
size_t offset;
- offset = guc_ads_um_queues_offset(ads) +
- guc_ads_um_queues_size(ads);
+ offset = guc_ads_capture_offset(ads) +
+ guc_ads_capture_size(ads);
return PAGE_ALIGN(offset);
}
@@ -409,6 +389,49 @@ int xe_guc_ads_init(struct xe_guc_ads *ads)
ads->bo = bo;
+ if (xe->info.has_usm) {
+ /*
+ * Allocate a separate BO for the HW fault ring (UM queues).
+ *
+ * Round the size up to the next power of two so that on iGPU
+ * (system memory, no IOMMU) the TTM pool issues a single
+ * alloc_pages(order=N) call, maximising the chance of getting
+ * a physically contiguous block. GuC requires contiguous DPA.
+ */
+ size_t um_size = IS_DGFX(xe) ?
+ GUC_UM_QUEUE_SIZE * GUC_UM_HW_QUEUE_MAX :
+ roundup_pow_of_two(GUC_UM_QUEUE_SIZE *
+ GUC_UM_HW_QUEUE_MAX);
+
+ u32 um_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile) |
+ XE_BO_FLAG_GGTT |
+ XE_BO_FLAG_GGTT_INVALIDATE |
+ XE_BO_FLAG_PINNED_NORESTORE |
+ XE_BO_FLAG_NEEDS_UC;
+
+ bo = xe_managed_bo_create_pin_map(xe, tile, um_size, um_flags);
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
+
+ /*
+ * On pre-Xe3p platforms, GAM (not GuC) accesses the UM queue
+ * ring via base_dpa, which must be a contiguous DMA address
+ * range. Verify that the allocated pages are contiguous in
+ * DMA address space.
+ */
+ if (!xe_bo_is_vram(bo) &&
+ !xe_guc_using_main_gamctrl_queues(ads_to_guc(ads)) &&
+ unlikely(!xe_bo_sg_is_contiguous(bo,
+ GUC_UM_QUEUE_SIZE *
+ GUC_UM_HW_QUEUE_MAX))) {
+ drm_err(&xe->drm,
+ "UM fault queue memory is not contiguous in DMA address space; GAM requires contiguous DPA\n");
+ return -ENOMEM;
+ }
+
+ ads->um_queue_bo = bo;
+ }
+
return 0;
}
ALLOW_ERROR_INJECTION(xe_guc_ads_init, ERRNO); /* See xe_pci_probe() */
@@ -820,7 +843,7 @@ static void guc_mmio_reg_state_init(struct xe_guc_ads *ads)
static void guc_um_init_params(struct xe_guc_ads *ads)
{
- u32 um_queue_offset = guc_ads_um_queues_offset(ads);
+ struct xe_bo *um_bo = ads->um_queue_bo;
struct xe_guc *guc = ads_to_guc(ads);
struct xe_device *xe = ads_to_xe(ads);
u64 base_dpa;
@@ -830,8 +853,14 @@ static void guc_um_init_params(struct xe_guc_ads *ads)
with_dpa = !xe_guc_using_main_gamctrl_queues(guc);
- base_ggtt = xe_bo_ggtt_addr(ads->bo) + um_queue_offset;
- base_dpa = xe_bo_main_addr(ads->bo, PAGE_SIZE) + um_queue_offset;
+ if (um_bo) {
+ /* All USM platforms: UM queues in dedicated um_queue_bo */
+ base_ggtt = xe_bo_ggtt_addr(um_bo);
+ base_dpa = xe_bo_main_addr(um_bo, PAGE_SIZE);
+ } else {
+ /* Platform does not support USM: no UM queues, nothing to do */
+ return;
+ }
for (i = 0; i < GUC_UM_HW_QUEUE_MAX; ++i) {
/*
diff --git a/drivers/gpu/drm/xe/xe_guc_ads_types.h b/drivers/gpu/drm/xe/xe_guc_ads_types.h
index 48a8e092023f..845c1fbd93a4 100644
--- a/drivers/gpu/drm/xe/xe_guc_ads_types.h
+++ b/drivers/gpu/drm/xe/xe_guc_ads_types.h
@@ -16,6 +16,11 @@ struct xe_bo;
struct xe_guc_ads {
/** @bo: Xe BO for GuC ads blob */
struct xe_bo *bo;
+ /**
+ * @um_queue_bo: Dedicated BO for the HW fault ring (UM queues).
+ * NULL if the platform does not support USM.
+ */
+ struct xe_bo *um_queue_bo;
/** @golden_lrc_size: golden LRC size */
size_t golden_lrc_size;
/** @regset_size: size of register set passed to GuC for save/restore */
diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c
index 59f2fa79ad42..7cf8f4858598 100644
--- a/drivers/gpu/drm/xe/xe_guc_pc.c
+++ b/drivers/gpu/drm/xe/xe_guc_pc.c
@@ -911,6 +911,7 @@ static bool pc_needs_min_freq_change(struct xe_guc_pc *pc)
static int pc_adjust_freq_bounds(struct xe_guc_pc *pc)
{
int ret;
+ u32 min_freq;
lockdep_assert_held(&pc->freq_lock);
@@ -933,8 +934,14 @@ static int pc_adjust_freq_bounds(struct xe_guc_pc *pc)
* Same thing happens for Server platforms where min is listed as
* RPMax
*/
- if (pc_get_min_freq(pc) > pc->rp0_freq)
+ min_freq = pc_get_min_freq(pc);
+ if (min_freq > pc->rp0_freq) {
ret = pc_set_min_freq(pc, pc->rp0_freq);
+ if (ret)
+ goto out;
+
+ min_freq = pc->rp0_freq;
+ }
/*
* Setting GT RP min frequency to 1.2GHz by default for
@@ -947,8 +954,8 @@ static int pc_adjust_freq_bounds(struct xe_guc_pc *pc)
* we aren't expecting high power output across board
*
*/
- if (pc_needs_min_freq_change(pc))
- ret = pc_set_min_freq(pc, max(BMG_MIN_FREQ, pc_get_min_freq(pc)));
+ if (pc_needs_min_freq_change(pc) && min_freq < BMG_MIN_FREQ)
+ ret = pc_set_min_freq(pc, BMG_MIN_FREQ);
out:
return ret;
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index a4292a11391d..9f8217ff1904 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -1096,7 +1096,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
* on until it is scheduled, we also read the ENGINE_ID MMIO in the WA BB and
* store it in the PPHSWP.
*/
-#define CONTEXT_ACTIVE 1ULL
+#define CONTEXT_ACTIVE XE_LRC_CTX_TIMESTAMP_ACTIVE
static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
struct xe_hw_engine *hwe,
u32 *batch,
@@ -1849,6 +1849,13 @@ void xe_lrc_write_ring(struct xe_lrc *lrc, const void *data, size_t size)
__xe_lrc_write_ring(lrc, ring, &noop, sizeof(noop));
}
+
+ /*
+ * The ring and the LRC context image are both WC, so the ring tail
+ * update which publishes these writes can become visible to the device
+ * first. Ensure the ring contents are visible before returning.
+ */
+ xe_device_wmb(xe);
}
u64 xe_lrc_descriptor(struct xe_lrc *lrc)
@@ -2720,21 +2727,27 @@ static u64 xe_lrc_update_multi_queue_timestamp(struct xe_lrc *lrc, u64 *old_ts)
static u64 xe_lrc_context_timestamp(struct xe_lrc *lrc)
{
u64 reg_ts, new_ts = lrc->ctx_timestamp;
+ u64 stored;
/* CTX_TIMESTAMP mmio read is invalid on VF, so return the LRC value */
if (IS_SRIOV_VF(lrc_to_xe(lrc)))
return xe_lrc_ctx_timestamp(lrc);
- if (context_active(lrc) &&
- !get_ctx_timestamp(lrc, xe_lrc_engine_id(lrc), &reg_ts))
+ /* Safely read CTX_TIMESTAMP: Avoid TOCTOU on LRC-stored CONTEXT_ACTIVE sentinel */
+ stored = xe_lrc_ctx_timestamp(lrc);
+ if (stored != CONTEXT_ACTIVE)
+ return stored;
+
+ /* Context is active: read the live timestamp from the engine's MMIO register */
+ if (!get_ctx_timestamp(lrc, xe_lrc_engine_id(lrc), &reg_ts))
new_ts = reg_ts;
- /*
- * If context swicthed out while we were here, just return the latest
- * LRC CTX TIMESTAMP value.
+ /* If the context switched out prefer using the value
+ * from context-save over the stale MMIO read.
*/
- if (!context_active(lrc))
- return xe_lrc_ctx_timestamp(lrc);
+ stored = xe_lrc_ctx_timestamp(lrc);
+ if (stored != CONTEXT_ACTIVE)
+ return stored;
return new_ts;
}
diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
index 0a3a611391ee..7be5e3da8bc8 100644
--- a/drivers/gpu/drm/xe/xe_lrc.h
+++ b/drivers/gpu/drm/xe/xe_lrc.h
@@ -9,6 +9,13 @@
#include "xe_lrc_types.h"
+/*
+ * Sentinel value stored in lrc->ctx_timestamp while a context is starting.
+ * The hardware hasn't yet written the real CTX_TIMESTAMP, so this is not a
+ * valid elapsed-time sample and must not be used as one.
+ */
+#define XE_LRC_CTX_TIMESTAMP_ACTIVE 1ULL
+
struct drm_printer;
struct xe_bb;
struct xe_device;
diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
index 2dce6a47202c..18d990c5d4ec 100644
--- a/drivers/gpu/drm/xe/xe_oa.c
+++ b/drivers/gpu/drm/xe/xe_oa.c
@@ -1594,6 +1594,10 @@ static long xe_oa_config_locked(struct xe_oa_stream *stream, u64 arg)
config = xchg(&stream->oa_config, config);
drm_dbg(&stream->oa->xe->drm, "changed to oa config uuid=%s\n",
stream->oa_config->uuid);
+ } else {
+ while (param.num_syncs--)
+ xe_sync_entry_cleanup(&param.syncs[param.num_syncs]);
+ kfree(param.syncs);
}
err_config_put:
@@ -2713,9 +2717,7 @@ static int xe_oa_init_gt(struct xe_gt *gt)
__xe_oa_init_oa_units(gt);
- drmm_mutex_init(&gt_to_xe(gt)->drm, &gt->oa.gt_lock);
-
- return 0;
+ return drmm_mutex_init(&gt_to_xe(gt)->drm, &gt->oa.gt_lock);
}
static void xe_oa_print_gt_oa_units(struct xe_gt *gt)
@@ -2855,7 +2857,10 @@ int xe_oa_init(struct xe_device *xe)
oa->xe = xe;
oa->oa_formats = oa_formats;
- drmm_mutex_init(&oa->xe->drm, &oa->metrics_lock);
+ ret = drmm_mutex_init(&oa->xe->drm, &oa->metrics_lock);
+ if (ret)
+ goto exit;
+
idr_init_base(&oa->metrics_idr, 1);
ret = xe_oa_init_oa_units(oa);
diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c
index 968b7e70b3f9..d17ab6e59df5 100644
--- a/drivers/gpu/drm/xe/xe_pxp.c
+++ b/drivers/gpu/drm/xe/xe_pxp.c
@@ -8,6 +8,8 @@
#include <drm/drm_managed.h>
#include <uapi/drm/xe_drm.h>
+#include <linux/device.h>
+
#include "xe_bo.h"
#include "xe_bo_types.h"
#include "xe_device_types.h"
@@ -164,16 +166,9 @@ static void mark_termination_in_progress(struct xe_pxp *pxp)
pxp->status = XE_PXP_TERMINATION_IN_PROGRESS;
}
-static void pxp_terminate(struct xe_pxp *pxp)
+static bool pxp_prep_for_termination(struct xe_pxp *pxp)
{
- int ret = 0;
- struct xe_device *xe = pxp->xe;
-
- if (!wait_for_completion_timeout(&pxp->activation,
- msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS)))
- drm_err(&xe->drm, "failed to wait for PXP start before termination\n");
-
- mutex_lock(&pxp->mutex);
+ lockdep_assert_held(&pxp->mutex);
if (pxp->status == XE_PXP_ACTIVE)
pxp->key_instance++;
@@ -182,10 +177,8 @@ static void pxp_terminate(struct xe_pxp *pxp)
* we'll mark the status as needing termination on resume, so no need to
* emit a termination now.
*/
- if (pxp->status == XE_PXP_SUSPENDED) {
- mutex_unlock(&pxp->mutex);
- return;
- }
+ if (pxp->status == XE_PXP_SUSPENDED)
+ return false;
/*
* If we have a termination already in progress, we need to wait for
@@ -195,15 +188,44 @@ static void pxp_terminate(struct xe_pxp *pxp)
*/
if (pxp->status == XE_PXP_TERMINATION_IN_PROGRESS) {
pxp->status = XE_PXP_NEEDS_ADDITIONAL_TERMINATION;
- mutex_unlock(&pxp->mutex);
- return;
+ return false;
}
mark_termination_in_progress(pxp);
- mutex_unlock(&pxp->mutex);
+ return true;
+}
+
+static void pxp_terminate(struct xe_pxp *pxp, bool hw_only)
+{
+ struct xe_device *xe = pxp->xe;
+ int ret = 0;
- pxp_invalidate_queues(pxp);
+ if (!wait_for_completion_timeout(&pxp->activation,
+ msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS)))
+ drm_err(&xe->drm, "failed to wait for PXP start before termination\n");
+
+ if (!hw_only) {
+ bool prep_ok;
+
+ mutex_lock(&pxp->mutex);
+
+ prep_ok = pxp_prep_for_termination(pxp);
+
+ mutex_unlock(&pxp->mutex);
+
+ if (!prep_ok)
+ return;
+
+ pxp_invalidate_queues(pxp);
+ } else {
+ /*
+ * The caller of the HW-only termination should have already
+ * called pxp_prep_for_termination and marked the termination as
+ * in progress.
+ */
+ xe_assert(xe, !completion_done(&pxp->termination));
+ }
ret = pxp_terminate_hw(pxp);
if (ret) {
@@ -249,33 +271,46 @@ static void pxp_terminate_complete(struct xe_pxp *pxp)
mutex_unlock(&pxp->mutex);
}
-static void pxp_irq_work(struct work_struct *work)
+static void pxp_events_work(struct work_struct *work)
{
- struct xe_pxp *pxp = container_of(work, typeof(*pxp), irq.work);
+ struct xe_pxp *pxp = container_of(work, typeof(*pxp), events.work);
struct xe_device *xe = pxp->xe;
+ bool hw_only = false;
u32 events = 0;
- spin_lock_irq(&xe->irq.lock);
- events = pxp->irq.events;
- pxp->irq.events = 0;
- spin_unlock_irq(&xe->irq.lock);
+ events = atomic_xchg(&pxp->events.pending, 0);
if (!events)
return;
/*
- * If we're processing a termination irq while suspending then don't
- * bother, we're going to re-init everything on resume anyway.
+ * If the termination request comes from an irq while we're suspending,
+ * then we can defer it to the resume path instead of waking the device
+ * up.
+ * In the case of the termination on resume the pm reference is taken
+ * in xe_pxp_pm_resume() and released here.
+ * Note that we do not expect both events to be set at the same time,
+ * but if it does happen due to a spurious interrupt we want to behave
+ * as if the only request we got was the one from the resume path; this
+ * is because the termination prep has already been done in
+ * xe_pxp_pm_resume() and it is impossible for any PXP operations to
+ * occur between the prep and the termination completion, so there is no
+ * need for a new SW prep.
*/
- if ((events & PXP_TERMINATION_REQUEST) && !xe_pm_runtime_get_if_active(xe))
+ if (events & PXP_TERMINATION_REQUEST_ON_RESUME) {
+ events &= ~PXP_TERMINATION_REQUEST_IRQ;
+ hw_only = true;
+ }
+
+ if ((events & PXP_TERMINATION_REQUEST_IRQ) && !xe_pm_runtime_get_if_active(xe))
return;
if (events & PXP_TERMINATION_REQUEST) {
- events &= ~PXP_TERMINATION_COMPLETE;
- pxp_terminate(pxp);
+ events &= ~PXP_TERMINATION_COMPLETE_IRQ;
+ pxp_terminate(pxp, hw_only);
}
- if (events & PXP_TERMINATION_COMPLETE)
+ if (events & PXP_TERMINATION_COMPLETE_IRQ)
pxp_terminate_complete(pxp);
if (events & PXP_TERMINATION_REQUEST)
@@ -296,20 +331,18 @@ void xe_pxp_irq_handler(struct xe_device *xe, u16 iir)
return;
}
- lockdep_assert_held(&xe->irq.lock);
-
if (unlikely(!iir))
return;
if (iir & (KCR_PXP_STATE_TERMINATED_INTERRUPT |
KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT))
- pxp->irq.events |= PXP_TERMINATION_REQUEST;
+ atomic_or(PXP_TERMINATION_REQUEST_IRQ, &pxp->events.pending);
if (iir & KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT)
- pxp->irq.events |= PXP_TERMINATION_COMPLETE;
+ atomic_or(PXP_TERMINATION_COMPLETE_IRQ, &pxp->events.pending);
- if (pxp->irq.events)
- queue_work(pxp->irq.wq, &pxp->irq.work);
+ if (atomic_read(&pxp->events.pending))
+ queue_work(pxp->events.wq, &pxp->events.work);
}
static int kcr_pxp_set_status(const struct xe_pxp *pxp, bool enable)
@@ -340,7 +373,7 @@ static void pxp_fini(void *arg)
{
struct xe_pxp *pxp = arg;
- destroy_workqueue(pxp->irq.wq);
+ destroy_workqueue(pxp->events.wq);
xe_pxp_destroy_execution_resources(pxp);
/* no need to explicitly disable KCR since we're going to do an FLR */
@@ -402,7 +435,7 @@ int xe_pxp_init(struct xe_device *xe)
INIT_LIST_HEAD(&pxp->queues.list);
spin_lock_init(&pxp->queues.lock);
- INIT_WORK(&pxp->irq.work, pxp_irq_work);
+ INIT_WORK(&pxp->events.work, pxp_events_work);
pxp->xe = xe;
pxp->gt = gt;
@@ -421,8 +454,8 @@ int xe_pxp_init(struct xe_device *xe)
mutex_init(&pxp->mutex);
- pxp->irq.wq = alloc_ordered_workqueue("pxp-wq", 0);
- if (!pxp->irq.wq) {
+ pxp->events.wq = alloc_ordered_workqueue("pxp-wq", 0);
+ if (!pxp->events.wq) {
err = -ENOMEM;
goto out_free;
}
@@ -442,7 +475,7 @@ int xe_pxp_init(struct xe_device *xe)
out_kcr_disable:
kcr_pxp_disable(pxp);
out_wq:
- destroy_workqueue(pxp->irq.wq);
+ destroy_workqueue(pxp->events.wq);
out_free:
drmm_kfree(&xe->drm, pxp);
out:
@@ -889,6 +922,7 @@ wait_for_activation:
fallthrough;
case XE_PXP_ACTIVE:
pxp->key_instance++;
+ pxp->needs_termination_on_resume = true;
needs_queue_inval = true;
break;
}
@@ -924,6 +958,7 @@ wait_for_activation:
*/
void xe_pxp_pm_resume(struct xe_pxp *pxp)
{
+ bool has_pm = false;
int err;
if (!xe_pxp_is_enabled(pxp))
@@ -931,14 +966,57 @@ void xe_pxp_pm_resume(struct xe_pxp *pxp)
err = kcr_pxp_enable(pxp);
+ /*
+ * We want to avoid the device runtime suspending before we're done with
+ * the termination queued below, so we need a runtime PM reference; we
+ * can't call the rpm functions from within the PXP lock, so we take the
+ * ref here. Note that we don't want the rpm resume code to actually run
+ * here as that would call back into this function, but as long as we
+ * don't enable DPM_FLAG_SMART_SUSPEND (which we currently do not) we're
+ * guaranteed to not be runtime suspended at this point, so we can
+ * safely use the get_noresume variant.
+ */
+ if (pxp->needs_termination_on_resume) {
+ has_pm = true;
+
+ xe_assert(pxp->xe, !dev_pm_smart_suspend(pxp->xe->drm.dev));
+ xe_pm_runtime_get_noresume(pxp->xe);
+ }
+
mutex_lock(&pxp->mutex);
xe_assert(pxp->xe, pxp->status == XE_PXP_SUSPENDED);
- if (err)
+ if (err) {
pxp->status = XE_PXP_ERROR;
- else
+ } else {
pxp->status = XE_PXP_NEEDS_TERMINATION;
+ if (pxp->needs_termination_on_resume) {
+ pxp->needs_termination_on_resume = false;
+
+ /*
+ * We can't call pxp_terminate_hw directly from here
+ * because we're not allowed to do allocations within
+ * the rpm resume call, so we defer the termination to
+ * the worker that we use for the termination irqs.
+ * However, we do not want any PXP ops to go through
+ * between the suspend completing and the worker
+ * starting, so we need to do the termination prep
+ * immediately, which will mark the termination as in
+ * progress and stall PXP ops.
+ */
+ if (pxp_prep_for_termination(pxp)) {
+ has_pm = false; /* move PM ref ownership to worker */
+
+ atomic_or(PXP_TERMINATION_REQUEST_ON_RESUME, &pxp->events.pending);
+ queue_work(pxp->events.wq, &pxp->events.work);
+ }
+ }
+ }
+
mutex_unlock(&pxp->mutex);
+
+ if (has_pm)
+ xe_pm_runtime_put(pxp->xe);
}
diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h
index ec86306e16f4..8132a9750b6e 100644
--- a/drivers/gpu/drm/xe/xe_pxp_types.h
+++ b/drivers/gpu/drm/xe/xe_pxp_types.h
@@ -85,17 +85,20 @@ struct xe_pxp {
/** @gsc_res: kernel-owned objects for PXP submissions to the GSCCS */
struct xe_pxp_gsc_client_resources gsc_res;
- /** @irq: wrapper for the worker and queue used for PXP irq support */
+ /** @events: wrapper for the worker and queue used for PXP event handling */
struct {
- /** @irq.work: worker that manages irq events. */
+ /** @events.work: worker that manages termination events. */
struct work_struct work;
- /** @irq.wq: workqueue on which to queue the irq work. */
+ /** @events.wq: workqueue on which to queue the work. */
struct workqueue_struct *wq;
- /** @irq.events: pending events, protected with xe->irq.lock. */
- u32 events;
-#define PXP_TERMINATION_REQUEST BIT(0)
-#define PXP_TERMINATION_COMPLETE BIT(1)
- } irq;
+ /** @events.pending: pending events */
+ atomic_t pending;
+#define PXP_TERMINATION_REQUEST_IRQ BIT(0)
+#define PXP_TERMINATION_REQUEST_ON_RESUME BIT(1)
+#define PXP_TERMINATION_REQUEST (PXP_TERMINATION_REQUEST_IRQ | \
+ PXP_TERMINATION_REQUEST_ON_RESUME)
+#define PXP_TERMINATION_COMPLETE_IRQ BIT(2)
+ } events;
/** @mutex: protects the pxp status and the queue list */
struct mutex mutex;
@@ -130,6 +133,14 @@ struct xe_pxp {
* suspend cycles.
*/
u32 last_suspend_key_instance;
+ /**
+ * @needs_termination_on_resume: indicates if PXP termination is needed
+ * on resume. This is set if PXP was active when we suspend and it is
+ * cleared when we queue the termination on resume. Since the suspend
+ * and resume calls cannot execute at the same time, this variable does
+ * not need to be protected by the PXP lock.
+ */
+ bool needs_termination_on_resume;
};
#endif /* _XE_PXP_TYPES_H_ */
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index c8a203fff4d1..6d6e81242f74 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -8,14 +8,12 @@
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*/
-#include <linux/acpi.h>
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -132,80 +130,6 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return 0;
}
-#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
-/*
- * Check whether an ACPI GpioInt resource's referenced GPIO controller
- * has finished probing. Resources with no named controller (resource
- * source string) are skipped, since they can't be resolved to a
- * struct device.
- */
-static int check_gpioint_resource(struct acpi_resource *ares, void *data)
-{
- struct acpi_resource_gpio *agpio;
- struct acpi_device *gpio_adev;
- struct device *gpio_dev;
- acpi_handle handle;
- acpi_status status;
-
- if (!acpi_gpio_get_irq_resource(ares, &agpio))
- return 1; /* not a GpioInt resource, skip */
-
- if (!agpio->resource_source.string_length)
- return 1; /* no named controller, skip */
-
- status = acpi_get_handle(NULL, agpio->resource_source.string_ptr, &handle);
- if (ACPI_FAILURE(status))
- return 1;
-
- gpio_adev = acpi_fetch_acpi_dev(handle);
- if (!gpio_adev)
- return 1;
-
- struct gpio_device *gdev __free(gpio_device_put) =
- gpio_device_find_by_fwnode(acpi_fwnode_handle(gpio_adev));
- if (!gdev)
- return -EPROBE_DEFER; /* controller not registered yet: abort walk */
-
- gpio_dev = gpio_device_to_device(gdev)->parent;
-
- guard(device)(gpio_dev);
- if (!device_is_bound(gpio_dev))
- return -EPROBE_DEFER; /* controller not bound yet: abort walk */
-
- return 1; /* bound, skip adding to resource list, continue walk */
-}
-
-static int check_child_gpioint(struct acpi_device *adev, void *data)
-{
- LIST_HEAD(res_list);
- int ret;
-
- ret = acpi_dev_get_resources(adev, &res_list, check_gpioint_resource, NULL);
- if (ret < 0)
- return ret;
-
- acpi_dev_free_resource_list(&res_list);
-
- return 0;
-}
-
-static int i2c_dw_check_gpio_dependencies(struct device *dev)
-{
- struct acpi_device *adev;
-
- adev = ACPI_COMPANION(dev);
- if (!adev)
- return 0;
-
- return acpi_dev_for_each_child(adev, check_child_gpioint, NULL);
-}
-#else
-static int i2c_dw_check_gpio_dependencies(struct device *dev)
-{
- return 0;
-}
-#endif /* CONFIG_ACPI && CONFIG_GPIOLIB */
-
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
u32 flags = (uintptr_t)device_get_match_data(&pdev->dev);
@@ -214,10 +138,6 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
struct dw_i2c_dev *dev;
int irq, ret;
- ret = i2c_dw_check_gpio_dependencies(device);
- if (ret)
- return ret;
-
irq = platform_get_irq_optional(pdev, 0);
if (irq == -ENXIO)
flags |= ACCESS_POLLING;
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index fe63d53d56db..e9089b0c3e2f 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -725,21 +725,13 @@ static int sur40_probe(struct usb_interface *interface,
goto err_free_input;
}
- /* register the polled input device */
- error = input_register_device(input);
- if (error) {
- dev_err(&interface->dev,
- "Unable to register polled input device.");
- goto err_free_buffer;
- }
-
/* register the video master device */
snprintf(sur40->v4l2.name, sizeof(sur40->v4l2.name), "%s", DRIVER_LONG);
error = v4l2_device_register(sur40->dev, &sur40->v4l2);
if (error) {
dev_err(&interface->dev,
"Unable to register video master device.");
- goto err_unreg_v4l2;
+ goto err_free_buffer;
}
/* initialize the lock and subdevice */
@@ -795,6 +787,14 @@ static int sur40_probe(struct usb_interface *interface,
if (error) {
dev_err(&interface->dev,
"Unable to register video subdevice.");
+ goto err_free_ctrl;
+ }
+
+ /* register the polled input device */
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&interface->dev,
+ "Unable to register polled input device.");
goto err_unreg_video;
}
@@ -806,6 +806,8 @@ static int sur40_probe(struct usb_interface *interface,
err_unreg_video:
video_unregister_device(&sur40->vdev);
+err_free_ctrl:
+ v4l2_ctrl_handler_free(&sur40->hdl);
err_unreg_v4l2:
v4l2_device_unregister(&sur40->v4l2);
err_free_buffer:
@@ -823,11 +825,12 @@ static void sur40_disconnect(struct usb_interface *interface)
{
struct sur40_state *sur40 = usb_get_intfdata(interface);
+ input_unregister_device(sur40->input);
+
v4l2_ctrl_handler_free(&sur40->hdl);
video_unregister_device(&sur40->vdev);
v4l2_device_unregister(&sur40->v4l2);
- input_unregister_device(sur40->input);
kfree(sur40->bulk_in_buffer);
kfree(sur40);
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 3b4928f5b9b2..8f4df250a77a 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -2610,6 +2610,8 @@ static void atmci_remove(struct platform_device *pdev)
free_irq(platform_get_irq(pdev, 0), host);
+ cancel_work_sync(&host->bh_work);
+
clk_disable_unprepare(host->mck);
pm_runtime_disable(dev);
diff --git a/drivers/mmc/host/loongson2-mmc.c b/drivers/mmc/host/loongson2-mmc.c
index f553e92fd9e5..118eccbaf8cd 100644
--- a/drivers/mmc/host/loongson2-mmc.c
+++ b/drivers/mmc/host/loongson2-mmc.c
@@ -641,8 +641,8 @@ static void ls2k0500_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
return;
for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
- data = sg_virt(&sg[i]);
- for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
+ data = sg_virt(sg);
+ for (j = 0; j < (sg_dma_len(sg) / 4); j++)
if (cmd->opcode == SD_SWITCH)
data[j] = bitrev8x4(data[j]);
else
@@ -758,8 +758,8 @@ static void ls2k2000_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
return;
for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
- data = sg_virt(&sg[i]);
- for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
+ data = sg_virt(sg);
+ for (j = 0; j < (sg_dma_len(sg) / 4); j++)
data[j] = bitrev8x4(data[j]);
}
}
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 58c881f2725b..3356ac5a1fa0 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1357,7 +1357,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
if (req->data == NULL) {
OMAP_HSMMC_WRITE(host->base, BLK, 0);
if (req->cmd->flags & MMC_RSP_BUSY) {
- timeout = req->cmd->busy_timeout * NSEC_PER_MSEC;
+ timeout = (u64)req->cmd->busy_timeout * NSEC_PER_MSEC;
/*
* Set an arbitrary 100ms data timeout for commands with
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e3bf901b10aa..efb4c7742fe2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4187,6 +4187,14 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
}
EXPORT_SYMBOL_GPL(__sdhci_read_caps);
+static void sdhci_unmap_bounce_buffer(void *data)
+{
+ struct sdhci_host *host = data;
+
+ dma_unmap_single(mmc_dev(host->mmc), host->bounce_addr,
+ host->bounce_buffer_size, DMA_BIDIRECTIONAL);
+}
+
static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
@@ -4247,6 +4255,14 @@ static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
}
host->bounce_buffer_size = bounce_size;
+ ret = devm_add_action_or_reset(mmc_dev(mmc),
+ sdhci_unmap_bounce_buffer, host);
+ if (ret) {
+ devm_kfree(mmc_dev(mmc), host->bounce_buffer);
+ host->bounce_buffer = NULL;
+ host->bounce_buffer_size = 0;
+ return;
+ }
out:
/* Lie about this since we're bouncing */
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b6a571d866fa..f0fd81409a86 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -659,7 +659,7 @@ struct sdhci_host {
unsigned int tuning_count; /* Timer count for re-tuning */
unsigned int tuning_mode; /* Re-tuning mode supported by host */
- unsigned int tuning_err; /* Error code for re-tuning */
+ int tuning_err; /* Error code for re-tuning */
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 25099077fe4f..bc7b37cb74a7 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -11789,10 +11789,21 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,
{
struct bnxt_irq *irq;
u16 tag;
- int err;
irq = container_of(notify, struct bnxt_irq, affinity_notify);
+#ifdef CONFIG_RFS_ACCEL
+ if (irq->bp->dev->rx_cpu_rmap && irq->ring_nr < irq->bp->rx_nr_rings) {
+ int err;
+
+ err = cpu_rmap_update(irq->bp->dev->rx_cpu_rmap, irq->ring_nr,
+ mask);
+ if (err)
+ netdev_warn(irq->bp->dev,
+ "aRFS rmap update failed: %d\n", err);
+ }
+#endif
+
if (!irq->bp->tph_mode)
return;
@@ -11802,20 +11813,11 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,
return;
if (pcie_tph_get_cpu_st(irq->bp->pdev, TPH_MEM_TYPE_VM,
- cpumask_first(irq->cpu_mask), &tag))
+ cpumask_first(mask), &tag))
return;
- if (pcie_tph_set_st_entry(irq->bp->pdev, irq->msix_nr, tag))
- return;
-
- netdev_lock(irq->bp->dev);
- if (netif_running(irq->bp->dev)) {
- err = netdev_rx_queue_restart(irq->bp->dev, irq->ring_nr);
- if (err)
- netdev_err(irq->bp->dev,
- "RX queue restart failed: err=%d\n", err);
- }
- netdev_unlock(irq->bp->dev);
+ WRITE_ONCE(irq->new_tag, tag);
+ bnxt_queue_sp_work(irq->bp, BNXT_TPH_UPDATE_SP_EVENT);
}
static void bnxt_irq_affinity_release(struct kref *ref)
@@ -11866,10 +11868,6 @@ static void bnxt_free_irq(struct bnxt *bp)
struct bnxt_irq *irq;
int i;
-#ifdef CONFIG_RFS_ACCEL
- free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
- bp->dev->rx_cpu_rmap = NULL;
-#endif
if (!bp->irq_tbl || !bp->bnapi)
return;
@@ -11878,27 +11876,35 @@ static void bnxt_free_irq(struct bnxt *bp)
irq = &bp->irq_tbl[map_idx];
if (irq->requested) {
+ bnxt_release_irq_notifier(irq);
+
if (irq->have_cpumask) {
irq_update_affinity_hint(irq->vector, NULL);
free_cpumask_var(irq->cpu_mask);
irq->have_cpumask = 0;
}
- bnxt_release_irq_notifier(irq);
-
free_irq(irq->vector, bp->bnapi[i]);
}
irq->requested = 0;
+ irq->tag = 0;
+ irq->new_tag = 0;
}
/* Disable TPH support */
pcie_disable_tph(bp->pdev);
bp->tph_mode = 0;
+
+#ifdef CONFIG_RFS_ACCEL
+ free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
+ bp->dev->rx_cpu_rmap = NULL;
+#endif
}
static int bnxt_request_irq(struct bnxt *bp)
{
+ const int numa_node = dev_to_node(&bp->pdev->dev);
struct cpu_rmap *rmap = NULL;
int i, j, rc = 0;
unsigned long flags = 0;
@@ -11921,6 +11927,8 @@ static int bnxt_request_irq(struct bnxt *bp)
for (i = 0, j = 0; i < bp->cp_nr_rings; i++) {
int map_idx = bnxt_cp_num_to_irq_num(bp, i);
struct bnxt_irq *irq = &bp->irq_tbl[map_idx];
+ unsigned int cpu_num;
+ u16 tag;
if (IS_ENABLED(CONFIG_RFS_ACCEL) &&
rmap && bp->bnapi[i]->rx_ring) {
@@ -11939,32 +11947,31 @@ static int bnxt_request_irq(struct bnxt *bp)
netif_napi_set_irq_locked(&bp->bnapi[i]->napi, irq->vector);
irq->requested = 1;
- if (zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL)) {
- int numa_node = dev_to_node(&bp->pdev->dev);
- u16 tag;
-
- irq->have_cpumask = 1;
- irq->msix_nr = map_idx;
- irq->ring_nr = i;
- cpumask_set_cpu(cpumask_local_spread(i, numa_node),
- irq->cpu_mask);
- rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
- if (rc) {
- netdev_warn(bp->dev,
- "Update affinity hint failed, IRQ = %d\n",
- irq->vector);
- break;
- }
+ if (!zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL))
+ continue;
- bnxt_register_irq_notifier(bp, irq);
+ irq->have_cpumask = 1;
+ irq->msix_nr = map_idx;
+ irq->ring_nr = i;
+ cpu_num = cpumask_local_spread(i, numa_node);
+ cpumask_set_cpu(cpu_num, irq->cpu_mask);
+
+ /* Init ST table entry if we can get the mapping */
+ if (!pcie_tph_get_cpu_st(bp->pdev, TPH_MEM_TYPE_VM,
+ cpu_num, &tag)) {
+ pcie_tph_set_st_entry(bp->pdev, irq->msix_nr, tag);
+ irq->tag = tag;
+ irq->new_tag = tag;
+ }
- /* Init ST table entry */
- if (pcie_tph_get_cpu_st(irq->bp->pdev, TPH_MEM_TYPE_VM,
- cpumask_first(irq->cpu_mask),
- &tag))
- continue;
+ bnxt_register_irq_notifier(bp, irq);
- pcie_tph_set_st_entry(irq->bp->pdev, irq->msix_nr, tag);
+ rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
+ if (rc) {
+ netdev_warn(bp->dev,
+ "Update affinity hint failed, IRQ = %d\n",
+ irq->vector);
+ break;
}
}
return rc;
@@ -14468,6 +14475,43 @@ static void bnxt_rtnl_unlock_sp(struct bnxt *bp)
rtnl_unlock();
}
+static void bnxt_tph_update(struct bnxt *bp)
+{
+ struct net_device *dev = bp->dev;
+ int i;
+
+ bnxt_lock_sp(bp);
+ if (!test_bit(BNXT_STATE_OPEN, &bp->state))
+ goto unlock;
+
+ for (i = 0; i < bp->rx_nr_rings; i++) {
+ struct bnxt_irq *irq;
+ int map_idx, err;
+ u16 tag;
+
+ map_idx = bnxt_cp_num_to_irq_num(bp, i);
+ irq = &bp->irq_tbl[map_idx];
+ tag = READ_ONCE(irq->new_tag);
+ if (irq->tag == tag)
+ continue;
+
+ if (pcie_tph_set_st_entry(bp->pdev, irq->msix_nr, tag))
+ continue;
+
+ err = netdev_rx_queue_restart(dev, irq->ring_nr);
+ if (err) {
+ netdev_err(dev, "RX queue restart failed: err=%d\n",
+ err);
+ continue;
+ }
+
+ irq->tag = tag;
+ }
+
+unlock:
+ bnxt_unlock_sp(bp);
+}
+
/* Only called from bnxt_sp_task() */
static void bnxt_reset(struct bnxt *bp, bool silent)
{
@@ -14892,6 +14936,9 @@ static void bnxt_sp_task(struct work_struct *work)
bnxt_devlink_health_fw_report(bp);
}
+ if (test_and_clear_bit(BNXT_TPH_UPDATE_SP_EVENT, &bp->sp_event))
+ bnxt_tph_update(bp);
+
smp_mb__before_atomic();
clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 44ea8fc7b766..dc8ec5e5733e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -1268,6 +1268,8 @@ struct bnxt_irq {
struct bnxt *bp;
int msix_nr;
int ring_nr;
+ u16 tag;
+ u16 new_tag;
struct irq_affinity_notify affinity_notify;
};
@@ -2642,6 +2644,7 @@ struct bnxt {
#define BNXT_RING_COAL_NOW_SP_EVENT 17
#define BNXT_FW_RESET_NOTIFY_SP_EVENT 18
#define BNXT_FW_EXCEPTION_SP_EVENT 19
+#define BNXT_TPH_UPDATE_SP_EVENT 20
#define BNXT_LINK_CFG_CHANGE_SP_EVENT 21
#define BNXT_THERMAL_THRESHOLD_SP_EVENT 22
#define BNXT_FW_ECHO_REQUEST_SP_EVENT 23
diff --git a/drivers/net/ethernet/google/gve/gve_ptp.c b/drivers/net/ethernet/google/gve/gve_ptp.c
index 06b1cf4a5efc..1d6c59f4ead3 100644
--- a/drivers/net/ethernet/google/gve/gve_ptp.c
+++ b/drivers/net/ethernet/google/gve/gve_ptp.c
@@ -26,6 +26,11 @@ int gve_clock_nic_ts_read(struct gve_priv *priv)
return 0;
}
+static int gve_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ return -EOPNOTSUPP;
+}
+
static int gve_ptp_gettimex64(struct ptp_clock_info *info,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
@@ -60,6 +65,7 @@ out:
static const struct ptp_clock_info gve_ptp_caps = {
.owner = THIS_MODULE,
.name = "gve clock",
+ .adjfine = gve_ptp_adjfine,
.gettimex64 = gve_ptp_gettimex64,
.settime64 = gve_ptp_settime64,
.do_aux_work = gve_ptp_do_aux_work,
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
index 8271f731a91f..0ece2f6fdffb 100644
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -886,6 +886,11 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
rx->rx_hsplit_unsplit_pkt += unsplit;
rx->rx_hsplit_bytes += hdr_len;
u64_stats_update_end(&rx->statss);
+
+ if (!buf_len) {
+ gve_free_buffer(rx, buf_state);
+ return 0;
+ }
} else if (!rx->ctx.skb_head && rx->dqo.page_pool &&
netmem_is_net_iov(buf_state->page_info.netmem)) {
/* when header split is disabled, the header went to the packet
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 434a31080855..6330540979d7 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -1310,6 +1310,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
pkt_len = cppi5_hdesc_get_pktlen(desc_rx);
cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
+ /* Port ID is contained in the lower 8-bits of the 16-bit Source Tag */
+ port_id &= 0xFF;
dev_dbg(dev, "%s rx port_id:%d\n", __func__, port_id);
port = am65_common_get_port(common, port_id);
ndev = port->ndev;
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index a16221995909..cb653861aad8 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -180,8 +180,10 @@ static void ngbe_irq_enable(struct wx *wx, bool queues)
/* mask interrupt */
if (queues)
wx_intr_enable(wx, NGBE_INTR_ALL);
- else
+ else if (wx->pdev->msix_enabled)
wx_intr_enable(wx, NGBE_INTR_MISC(wx));
+ else
+ wx_intr_enable(wx, BIT(0));
}
/**
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index ed46439a9f4e..92d3d340281f 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -146,6 +146,8 @@ static int ipvlan_init(struct net_device *dev)
dev->lltx = true;
netif_inherit_tso_max(dev, phy_dev);
dev->hard_header_len = phy_dev->hard_header_len;
+ dev->needed_headroom = phy_dev->needed_headroom;
+ dev->needed_tailroom = phy_dev->needed_tailroom;
netdev_lockdep_set_classes(dev);
@@ -773,6 +775,8 @@ static int ipvlan_device_event(struct notifier_block *unused,
case NETDEV_FEAT_CHANGE:
list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
netif_inherit_tso_max(ipvlan->dev, dev);
+ ipvlan->dev->needed_headroom = dev->needed_headroom;
+ ipvlan->dev->needed_tailroom = dev->needed_tailroom;
netdev_update_features(ipvlan->dev);
}
break;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index c40fa331836b..ff2f4bb651b7 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -950,6 +950,8 @@ static int macvlan_init(struct net_device *dev)
dev->lltx = true;
netif_inherit_tso_max(dev, lowerdev);
dev->hard_header_len = lowerdev->hard_header_len;
+ dev->needed_headroom = lowerdev->needed_headroom;
+ dev->needed_tailroom = lowerdev->needed_tailroom;
macvlan_set_lockdep_class(dev);
vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
@@ -1824,6 +1826,8 @@ static int macvlan_device_event(struct notifier_block *unused,
case NETDEV_FEAT_CHANGE:
list_for_each_entry(vlan, &port->vlans, list) {
netif_inherit_tso_max(vlan->dev, dev);
+ vlan->dev->needed_headroom = dev->needed_headroom;
+ vlan->dev->needed_tailroom = dev->needed_tailroom;
netdev_update_features(vlan->dev);
}
break;
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index c3a6ba96fc8a..029a4a532a10 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -127,8 +127,8 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
{
struct ntb_netdev_queue *q = qp_data;
struct ntb_netdev *dev = q->ntdev;
+ struct sk_buff *skb, *new_skb;
struct net_device *ndev;
- struct sk_buff *skb;
int rc;
ndev = dev->ndev;
@@ -144,6 +144,12 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
goto enqueue_again;
}
+ new_skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
+ if (!new_skb) {
+ ndev->stats.rx_dropped++;
+ goto enqueue_again;
+ }
+
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_NONE;
@@ -157,12 +163,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
ndev->stats.rx_bytes += len;
}
- skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
- if (!skb) {
- ndev->stats.rx_errors++;
- ndev->stats.rx_frame_errors++;
- return;
- }
+ skb = new_skb;
enqueue_again:
rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c
index 90580e32052f..7e545428900a 100644
--- a/drivers/net/ovpn/crypto.c
+++ b/drivers/net/ovpn/crypto.c
@@ -18,20 +18,12 @@
#include "crypto_aead.h"
#include "crypto.h"
-static void ovpn_ks_destroy_rcu(struct rcu_head *head)
-{
- struct ovpn_crypto_key_slot *ks;
-
- ks = container_of(head, struct ovpn_crypto_key_slot, rcu);
- ovpn_aead_crypto_key_slot_destroy(ks);
-}
-
void ovpn_crypto_key_slot_release(struct kref *kref)
{
struct ovpn_crypto_key_slot *ks;
ks = container_of(kref, struct ovpn_crypto_key_slot, refcount);
- call_rcu(&ks->rcu, ovpn_ks_destroy_rcu);
+ queue_rcu_work(ovpn_wq, &ks->free_work);
}
/* can only be invoked when all peer references have been dropped (i.e. RCU
@@ -58,15 +50,19 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)
bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)
{
struct ovpn_crypto_key_slot *ks = NULL;
+ struct ovpn_crypto_key_slot *tmp;
+ int slot = 0;
spin_lock_bh(&cs->lock);
- if (rcu_access_pointer(cs->slots[0])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[0], NULL,
- lockdep_is_held(&cs->lock));
- } else if (rcu_access_pointer(cs->slots[1])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[1], NULL,
- lockdep_is_held(&cs->lock));
+ tmp = rcu_access_pointer(cs->slots[slot]);
+ if (!tmp || tmp->key_id != key_id) {
+ slot = 1;
+ tmp = rcu_access_pointer(cs->slots[slot]);
}
+
+ if (tmp && tmp->key_id == key_id)
+ ks = rcu_replace_pointer(cs->slots[slot], NULL,
+ lockdep_is_held(&cs->lock));
spin_unlock_bh(&cs->lock);
if (ks)
diff --git a/drivers/net/ovpn/crypto.h b/drivers/net/ovpn/crypto.h
index 0e284fec3a75..e3feb16d5498 100644
--- a/drivers/net/ovpn/crypto.h
+++ b/drivers/net/ovpn/crypto.h
@@ -10,6 +10,8 @@
#ifndef _NET_OVPN_OVPNCRYPTO_H_
#define _NET_OVPN_OVPNCRYPTO_H_
+#include <linux/workqueue.h>
+
#include "pktid.h"
#include "proto.h"
@@ -45,8 +47,8 @@ struct ovpn_crypto_key_slot {
struct ovpn_pktid_recv pid_recv ____cacheline_aligned_in_smp;
struct ovpn_pktid_xmit pid_xmit ____cacheline_aligned_in_smp;
+ struct rcu_work free_work;
struct kref refcount;
- struct rcu_head rcu;
};
struct ovpn_crypto_state {
diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c
index 8f07c418622b..74eaf6fac2f5 100644
--- a/drivers/net/ovpn/crypto_aead.c
+++ b/drivers/net/ovpn/crypto_aead.c
@@ -9,6 +9,7 @@
#include <crypto/aead.h>
#include <linux/skbuff.h>
+#include <linux/workqueue.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/udp.h>
@@ -380,13 +381,19 @@ error:
return ERR_PTR(ret);
}
-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks)
+static void ovpn_aead_crypto_key_slot_free(struct ovpn_crypto_key_slot *ks)
{
- if (!ks)
- return;
-
crypto_free_aead(ks->encrypt);
crypto_free_aead(ks->decrypt);
+}
+
+static void ovpn_aead_crypto_key_slot_free_work(struct work_struct *work)
+{
+ struct ovpn_crypto_key_slot *ks;
+
+ ks = container_of(to_rcu_work(work), struct ovpn_crypto_key_slot,
+ free_work);
+ ovpn_aead_crypto_key_slot_free(ks);
kfree(ks);
}
@@ -420,6 +427,7 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)
ks->encrypt = NULL;
ks->decrypt = NULL;
+ INIT_RCU_WORK(&ks->free_work, ovpn_aead_crypto_key_slot_free_work);
kref_init(&ks->refcount);
ks->key_id = kc->key_id;
@@ -453,7 +461,8 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)
return ks;
destroy_ks:
- ovpn_aead_crypto_key_slot_destroy(ks);
+ ovpn_aead_crypto_key_slot_free(ks);
+ kfree(ks);
return ERR_PTR(ret);
}
diff --git a/drivers/net/ovpn/crypto_aead.h b/drivers/net/ovpn/crypto_aead.h
index 65a2ff307898..fae3b585a43b 100644
--- a/drivers/net/ovpn/crypto_aead.h
+++ b/drivers/net/ovpn/crypto_aead.h
@@ -22,7 +22,6 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
struct ovpn_crypto_key_slot *
ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc);
-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks);
enum ovpn_cipher_alg ovpn_aead_crypto_alg(struct ovpn_crypto_key_slot *ks);
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index 9a66d693039a..9526f8096da6 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -204,10 +204,10 @@ drop:
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
kfree_skb(skb);
drop_nocount:
- if (likely(peer))
- ovpn_peer_put(peer);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}
/* RX path entry point: decrypt packet and forward it to the device */
@@ -302,11 +302,11 @@ err_unlock:
err:
if (unlikely(skb))
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
- if (likely(peer))
- ovpn_peer_put(peer);
+ kfree_skb(skb);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
- kfree_skb(skb);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}
static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 168cfe9b59a9..0708249e9607 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <linux/workqueue.h>
#include <net/gro_cells.h>
#include <net/ip.h>
#include <net/rtnetlink.h>
@@ -26,6 +27,9 @@
#include "tcp.h"
#include "udp.h"
+/* module-owned workqueue on which all ovpn-specific work is queued */
+struct workqueue_struct *ovpn_wq;
+
static void ovpn_priv_free(struct net_device *net)
{
struct ovpn_priv *ovpn = netdev_priv(net);
@@ -264,10 +268,16 @@ static int __init ovpn_init(void)
ovpn_tcp_init();
+ ovpn_wq = alloc_workqueue("ovpn", WQ_PERCPU, 0);
+ if (!ovpn_wq) {
+ pr_err("ovpn: cannot allocate workqueue\n");
+ return -ENOMEM;
+ }
+
err = rtnl_link_register(&ovpn_link_ops);
if (err) {
pr_err("ovpn: can't register rtnl link ops: %d\n", err);
- return err;
+ goto destroy_wq;
}
err = ovpn_nl_register();
@@ -280,6 +290,9 @@ static int __init ovpn_init(void)
unreg_rtnl:
rtnl_link_unregister(&ovpn_link_ops);
+destroy_wq:
+ destroy_workqueue(ovpn_wq);
+ ovpn_wq = NULL;
return err;
}
@@ -288,7 +301,11 @@ static __exit void ovpn_cleanup(void)
ovpn_nl_unregister();
rtnl_link_unregister(&ovpn_link_ops);
+ flush_workqueue(ovpn_wq);
rcu_barrier();
+
+ destroy_workqueue(ovpn_wq);
+ ovpn_wq = NULL;
}
module_init(ovpn_init);
diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h
index 5898f6adada7..84499140e4bd 100644
--- a/drivers/net/ovpn/ovpnpriv.h
+++ b/drivers/net/ovpn/ovpnpriv.h
@@ -15,6 +15,10 @@
#include <uapi/linux/if_link.h>
#include <uapi/linux/ovpn.h>
+struct workqueue_struct;
+
+extern struct workqueue_struct *ovpn_wq;
+
/**
* struct ovpn_peer_collection - container of peers for MultiPeer mode
* @by_id: table of peers index by ID
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index b0519f9840d8..c95656ca7c35 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -62,7 +62,7 @@ void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)
/* now that interval and timeout have been changed, kick
* off the worker so that the next delay can be recomputed
*/
- mod_delayed_work(system_percpu_wq, &peer->ovpn->keepalive_work, 0);
+ mod_delayed_work(ovpn_wq, &peer->ovpn->keepalive_work, 0);
}
/**
@@ -1371,7 +1371,7 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
peer->id);
if (WARN_ON(!ovpn_peer_hold(peer)))
return 0;
- if (!schedule_work(&peer->keepalive_work))
+ if (!queue_work(ovpn_wq, &peer->keepalive_work))
ovpn_peer_put(peer);
}
@@ -1463,8 +1463,8 @@ void ovpn_peer_keepalive_work(struct work_struct *work)
netdev_dbg(ovpn->dev,
"scheduling keepalive work: now=%llu next_run=%llu delta=%llu\n",
next_run, now, next_run - now);
- schedule_delayed_work(&ovpn->keepalive_work,
- (next_run - now) * HZ);
+ queue_delayed_work(ovpn_wq, &ovpn->keepalive_work,
+ (next_run - now) * HZ);
}
unlock_ovpn(ovpn, &release_list);
}
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c
index 0af14055c39a..8fe8a8e750a4 100644
--- a/drivers/net/ovpn/tcp.c
+++ b/drivers/net/ovpn/tcp.c
@@ -151,7 +151,7 @@ err:
/* take reference for deferred peer deletion. should never fail */
if (WARN_ON(!ovpn_peer_hold(peer)))
goto err_nopeer;
- if (!schedule_work(&peer->tcp.defer_del_work))
+ if (!queue_work(ovpn_wq, &peer->tcp.defer_del_work))
ovpn_peer_put(peer);
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
err_nopeer:
@@ -284,13 +284,12 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)
* stream therefore we abort the connection
*/
ovpn_peer_hold(peer);
- if (!schedule_work(&peer->tcp.defer_del_work))
+ if (!queue_work(ovpn_wq, &peer->tcp.defer_del_work))
ovpn_peer_put(peer);
/* we bail out immediately and keep tx_in_progress set
* to true. This way we prevent more TX attempts
- * which would lead to more invocations of
- * schedule_work()
+ * which would lead to more invocations of queue_work()
*/
return;
}
@@ -487,7 +486,7 @@ static void ovpn_tcp_write_space(struct sock *sk)
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (likely(sock && sock->peer)) {
- schedule_work(&sock->tcp_tx_work);
+ queue_work(ovpn_wq, &sock->tcp_tx_work);
sock->peer->tcp.sk_cb.sk_write_space(sk);
}
rcu_read_unlock();
diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index b65d0f5fa1a0..0d2321bd18c8 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1370,7 +1370,7 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
if (devnum == MDIO_MMD_VEND2)
ret = rtlgen_write_vend2(phydev, regnum, val);
else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
- ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV);
+ ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV, val);
else
ret = -EOPNOTSUPP;
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 5d2d34d24ce8..9b5af08cdd47 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -1091,12 +1091,13 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
}
}
+ skb_probe_transport_header(skb);
+
/* Move network header to the right position for VLAN tagged packets */
if (eth_type_vlan(skb->protocol) &&
vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
skb_set_network_header(skb, depth);
- skb_probe_transport_header(skb);
dev_queue_xmit(skb);
rcu_read_unlock();
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 00e34afd858e..6ab84c837a33 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -865,18 +865,24 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq,
skb_reset_mac_header(skb);
- /* check if bpf_xdp_adjust_tail was used */
- off = xdp->data_end - orig_data_end;
- if (off != 0)
- __skb_put(skb, off); /* positive on grow, negative on shrink */
-
/* XDP frag metadata (e.g. nr_frags) are updated in eBPF helpers
- * (e.g. bpf_xdp_adjust_tail), we need to update data_len here.
+ * (e.g. bpf_xdp_adjust_tail). Remove the old fragment contribution
+ * from skb->len before updating data_len, then add the new one back.
*/
- if (xdp_buff_has_frags(xdp))
+ skb->len -= skb->data_len;
+ if (xdp_buff_has_frags(xdp)) {
skb->data_len = skb_shinfo(skb)->xdp_frags_size;
- else
+ skb->len += skb->data_len;
+ } else {
skb->data_len = 0;
+ }
+
+ /* Synchronize the skb tail with XDP's updated linear area. */
+ off = xdp->data_end - orig_data_end;
+ if (off != 0) {
+ skb_set_tail_pointer(skb, xdp->data_end - xdp->data);
+ skb->len += off; /* positive on grow, negative on shrink */
+ }
skb->protocol = eth_type_trans(skb, rq->dev);
@@ -961,7 +967,7 @@ static int veth_poll(struct napi_struct *napi, int budget)
struct veth_rq *rq =
container_of(napi, struct veth_rq, xdp_napi);
struct veth_priv *priv = netdev_priv(rq->dev);
- int queue_idx = rq->xdp_rxq.queue_index;
+ int queue_idx = rq - priv->rq;
struct netdev_queue *peer_txq;
struct veth_stats stats = {};
struct net_device *peer_dev;
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 1ded27768a97..824144bb7774 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -4500,7 +4500,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
if (change_igmp && vxlan_addr_multicast(&dst->remote_ip))
err = vxlan_multicast_leave(vxlan);
- if (conf.age_interval != vxlan->cfg.age_interval)
+ if (netif_running(dev) && conf.age_interval != vxlan->cfg.age_interval)
mod_timer(&vxlan->age_timer, jiffies);
netdev_adjacent_change_commit(dst->remote_dev, lowerdev, dev);
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 322041859217..f8c2fe5f2f58 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -1189,10 +1189,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
- if (!mt76_queue_is_wed_rro(q)) {
- napi_disable(&dev->napi[i]);
- netif_napi_del(&dev->napi[i]);
- }
+ netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
page_pool_destroy(q->page_pool);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 3480205d5fb9..68a059504e83 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -802,7 +802,7 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add)
out:
if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ)
- mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env);
+ __mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env);
}
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c
index c0e2b48a50bf..4722007abafd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c
@@ -71,36 +71,44 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
}
}
-int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
- enum environment_cap country_ie_env)
+/* Internal version that assumes mutex is already held by caller */
+int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
+ enum environment_cap country_ie_env)
{
struct mt76_dev *mdev = &dev->mt76;
struct ieee80211_hw *hw = mdev->hw;
struct wiphy *wiphy = hw->wiphy;
int ret = 0;
- dev->regd_in_progress = true;
-
- mt792x_mutex_acquire(dev);
if (!dev->regd_change)
- goto err;
+ return 0;
ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env);
if (ret < 0)
- goto err;
+ return ret;
mt7921_regd_channel_update(wiphy, dev);
ret = mt76_connac_mcu_set_channel_domain(hw->priv);
if (ret < 0)
- goto err;
+ return ret;
ret = mt7921_set_tx_sar_pwr(hw, NULL);
- if (ret < 0)
- goto err;
-err:
+ return ret;
+}
+
+int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
+ enum environment_cap country_ie_env)
+{
+ int ret = 0;
+
+ dev->regd_in_progress = true;
+
+ mt792x_mutex_acquire(dev);
+ ret = __mt7921_mcu_regd_update(dev, alpha2, country_ie_env);
mt792x_mutex_release(dev);
+
dev->regd_change = false;
dev->regd_in_progress = false;
wake_up(&dev->wait);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h
index 571f31629e9e..5b24d0902c36 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h
@@ -10,6 +10,8 @@ struct regulatory_request;
int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
enum environment_cap country_ie_env);
+int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
+ enum environment_cap country_ie_env);
void mt7921_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request);
bool mt7921_regd_clc_supported(struct mt792x_dev *dev);
diff --git a/drivers/pmdomain/arm/scmi_perf_domain.c b/drivers/pmdomain/arm/scmi_perf_domain.c
index 3693423459c9..e390f902a444 100644
--- a/drivers/pmdomain/arm/scmi_perf_domain.c
+++ b/drivers/pmdomain/arm/scmi_perf_domain.c
@@ -33,7 +33,7 @@ scmi_pd_set_perf_state(struct generic_pm_domain *genpd, unsigned int state)
return 0;
if (!state)
- return -EINVAL;
+ return 0;
ret = pd->perf_ops->level_set(pd->ph, pd->domain_id, state, false);
if (ret)
diff --git a/drivers/pmdomain/mediatek/mt8183-pm-domains.h b/drivers/pmdomain/mediatek/mt8183-pm-domains.h
index 3742782a2702..5e33b8628e85 100644
--- a/drivers/pmdomain/mediatek/mt8183-pm-domains.h
+++ b/drivers/pmdomain/mediatek/mt8183-pm-domains.h
@@ -47,7 +47,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = 0,
.sram_pdn_ack_bits = 0,
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ .caps = MTK_SCPD_DOMAIN_SUPPLY | MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG] = {
.name = "mfg",
@@ -57,7 +57,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ .caps = MTK_SCPD_DOMAIN_SUPPLY | MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG_CORE0] = {
.name = "mfg_core0",
@@ -67,6 +67,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG_CORE1] = {
.name = "mfg_core1",
@@ -76,6 +77,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG_2D] = {
.name = "mfg_2d",
@@ -85,6 +87,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8183_TOP_AXI_PROT_EN_1_MFG,
diff --git a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
index 53bdab66cf15..9a8a38d98cce 100644
--- a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
+++ b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
@@ -657,7 +657,7 @@ static int mtk_mfg_attach_dev(struct generic_pm_domain *pd, struct device *dev)
struct mtk_mfg *mfg = mtk_mfg_from_genpd(pd);
struct dev_pm_opp_data *so = mfg->stack_opps;
struct dev_pm_opp_data *go = mfg->gpu_opps;
- struct dev_pm_opp_data *prev_o;
+ struct dev_pm_opp_data *prev_o = NULL;
struct dev_pm_opp_data *o;
int i, ret;
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index f0a6339affd7..6089c8cf5bbc 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -486,16 +486,8 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
if (ret < 0)
return ret;
- if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
-
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
-
- /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */
- if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
- udelay(5);
-
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
/*
@@ -1058,12 +1050,15 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
node = of_find_node_with_property(np, "mediatek,infracfg");
if (node) {
regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg");
- of_node_put(node);
num_regmaps++;
- if (IS_ERR(regmap[0]))
- return dev_err_probe(dev, PTR_ERR(regmap[0]),
+ if (IS_ERR(regmap[0])) {
+ ret = dev_err_probe(dev, PTR_ERR(regmap[0]),
"%pOF: failed to get infracfg regmap\n",
node);
+ of_node_put(node);
+ return ret;
+ }
+ of_node_put(node);
} else {
regmap[0] = NULL;
}
@@ -1072,17 +1067,22 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
node = of_find_node_with_property(np, "mediatek,smi");
if (node) {
smi_np = of_parse_phandle(node, "mediatek,smi", 0);
- of_node_put(node);
- if (!smi_np)
+ if (!smi_np) {
+ of_node_put(node);
return -ENODEV;
+ }
regmap[1] = device_node_to_regmap(smi_np);
num_regmaps++;
of_node_put(smi_np);
- if (IS_ERR(regmap[1]))
- return dev_err_probe(dev, PTR_ERR(regmap[1]),
+ if (IS_ERR(regmap[1])) {
+ ret = dev_err_probe(dev, PTR_ERR(regmap[1]),
"%pOF: failed to get SMI regmap\n",
node);
+ of_node_put(node);
+ return ret;
+ }
+ of_node_put(node);
} else {
regmap[1] = NULL;
}
diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c
index 63120e703923..ffc46de8d07a 100644
--- a/drivers/pmdomain/qcom/rpmhpd.c
+++ b/drivers/pmdomain/qcom/rpmhpd.c
@@ -245,9 +245,13 @@ static struct rpmhpd *eliza_rpmhpds[] = {
[RPMHPD_GFX] = &gfx,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
+ [RPMHPD_MMCX] = &mmcx,
+ [RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
+ [RPMHPD_MXC] = &mxc,
+ [RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP] = &nsp,
};
diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c
index 002b41f53eff..ff743a8b0dfe 100644
--- a/drivers/regulator/fp9931.c
+++ b/drivers/regulator/fp9931.c
@@ -37,48 +37,18 @@ struct fp9931_data {
};
static const unsigned int VPOSNEG_table[] = {
- 7040000,
- 7040000,
- 7040000,
- 7040000,
- 7040000,
- 7040000,
- 7260000,
- 7490000,
- 7710000,
- 7930000,
- 8150000,
- 8380000,
- 8600000,
- 8820000,
- 9040000,
- 9270000,
- 9490000,
- 9710000,
- 9940000,
- 10160000,
- 10380000,
- 10600000,
- 10830000,
- 11050000,
- 11270000,
- 11490000,
- 11720000,
- 11940000,
- 12160000,
- 12380000,
- 12610000,
- 12830000,
- 13050000,
- 13280000,
- 13500000,
- 13720000,
- 13940000,
- 14170000,
- 14390000,
- 14610000,
- 14830000,
- 15060000,
+ 7040000, 7040000, 7040000, 7040000, 7040000, /* 00h-04h */
+ 7260000, 7490000, 7710000, 7930000, 8150000, 8380000, /* 05h-0Ah */
+ 8600000, 8820000, 9040000, 9270000, 9490000, 9710000, /* 0Bh-10h */
+ 9940000, 10160000, 10380000, 10600000, 10830000, 11050000, /* 11h-16h */
+ 11270000, 11490000, 11720000, 11940000, 12160000, 12380000, /* 17h-1Ch */
+ 12610000, 12830000, 13050000, 13280000, 13500000, 13720000, /* 1Dh-22h */
+ 13940000, 14170000, 14390000, 14610000, 14830000, 15060000, /* 23h-28h */
+ /* 29h-3Fh: clamped to 15.06V per datasheet */
+ 15060000, 15060000, 15060000, 15060000, 15060000, 15060000,
+ 15060000, 15060000, 15060000, 15060000, 15060000, 15060000,
+ 15060000, 15060000, 15060000, 15060000, 15060000, 15060000,
+ 15060000, 15060000, 15060000, 15060000, 15060000,
};
static const struct hwmon_channel_info *fp9931_info[] = {
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 756a4201225e..73856e3df337 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -1269,6 +1269,11 @@ static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
{}
};
+static const struct rpmh_vreg_init_data pm8350b_vreg_data[] = {
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"),
+ {}
+};
+
static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps515, "vdd-s1"),
RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
@@ -1869,6 +1874,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.data = pm8350_vreg_data,
},
{
+ .compatible = "qcom,pm8350b-rpmh-regulators",
+ .data = pm8350b_vreg_data,
+ },
+ {
.compatible = "qcom,pm8350c-rpmh-regulators",
.data = pm8350c_vreg_data,
},
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 643051332132..4fb2dc403962 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -4310,8 +4310,8 @@ static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
if (!res)
return res;
if (rest)
- res = memcmp(fsp, arr + ((num - rest) * lb_size),
- rest * lb_size);
+ res = !memcmp(fsp, arr + ((num - rest) * lb_size),
+ rest * lb_size);
if (!res)
return res;
if (compare_only)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 453a2232452d..b729407348f7 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2161,7 +2161,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
struct scsi_cmnd *scmd;
struct request *req;
- req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, 0);
+ req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, BLK_MQ_REQ_NOWAIT);
if (IS_ERR(req))
return;
scmd = blk_mq_rq_to_pdu(req);
@@ -2362,6 +2362,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
int scsi_error_handler(void *data)
{
struct Scsi_Host *shost = data;
+ bool eh_noresume;
/*
* We use TASK_INTERRUPTIBLE so that the thread is not
@@ -2403,7 +2404,8 @@ int scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
*/
- if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) {
+ eh_noresume = READ_ONCE(shost->eh_noresume);
+ if (!eh_noresume && scsi_autopm_get_host(shost) != 0) {
SCSI_LOG_ERROR_RECOVERY(1,
shost_printk(KERN_ERR, shost,
"scsi_eh_%d: unable to autoresume\n",
@@ -2427,7 +2429,7 @@ int scsi_error_handler(void *data)
* which are still online.
*/
scsi_restart_operations(shost);
- if (!shost->eh_noresume)
+ if (!eh_noresume)
scsi_autopm_put_host(shost);
}
__set_current_state(TASK_RUNNING);
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 2f2debc64e73..a9d055f9c5dd 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -283,6 +283,7 @@ static inline void dw_spi_shutdown_chip(struct dw_spi *dws)
dw_spi_enable_chip(dws, 0);
dw_spi_set_clk(dws, 0);
dws->current_freq = 0;
+ dws->cur_rx_sample_dly = 0;
}
extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
diff --git a/drivers/spi/spi-virtio.c b/drivers/spi/spi-virtio.c
index fa4c68049eca..2256dfec5407 100644
--- a/drivers/spi/spi-virtio.c
+++ b/drivers/spi/spi-virtio.c
@@ -358,6 +358,8 @@ static int virtio_spi_probe(struct virtio_device *vdev)
if (ret)
return dev_err_probe(&vdev->dev, ret, "Cannot register virtqueue cleanup\n");
+ virtio_device_ready(vdev);
+
/* Use devm version to register controller */
ret = devm_spi_register_controller(&vdev->dev, ctrl);
if (ret)
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index b4372fa268d0..633715b98625 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -698,6 +698,9 @@ static int optee_ffa_lend_protmem(struct optee *optee, struct tee_shm *protmem,
int rc;
mem_attr = kzalloc_objs(*mem_attr, ma_count);
+ if (!mem_attr)
+ return -ENOMEM;
+
for (n = 0; n < ma_count; n++) {
mem_attr[n].receiver = mem_attrs[n] & U16_MAX;
mem_attr[n].attrs = mem_attrs[n] >> 16;
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 13e6357a8bbb..a41b56dbf3b7 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -10016,7 +10016,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
* we are functional while we are here, skip host resume in error
* handling context.
*/
- hba->host->eh_noresume = 1;
+ WRITE_ONCE(hba->host->eh_noresume, 1);
/*
* Current function would be generally called from the power management
@@ -10038,7 +10038,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
}
scsi_device_put(sdp);
- hba->host->eh_noresume = 0;
+ WRITE_ONCE(hba->host->eh_noresume, 0);
return ret;
}
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index c97f10b48b5b..613dd28e3f1a 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -937,7 +937,8 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
/* last one */ {""}
};
- if (WARN_ON(user_ns != current_user_ns()))
+ /* The fscontext fd may have been passed to another user namespace. */
+ if (user_ns != current_user_ns())
return -EINVAL;
/* Never exec off this instance and never let anything stack on it. */
diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c
index de07f19b0caa..12cb50e0a166 100644
--- a/fs/ceph/ioctl.c
+++ b/fs/ceph/ioctl.c
@@ -72,7 +72,7 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
struct ceph_ioctl_layout nl;
int err;
- if (!inode_owner_or_capable(&nop_mnt_idmap, inode))
+ if (!inode_owner_or_capable(file_mnt_idmap(file), inode))
return -EACCES;
if (copy_from_user(&l, arg, sizeof(l)))
@@ -145,7 +145,7 @@ static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
int err;
struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(inode->i_sb)->mdsc;
- if (!inode_owner_or_capable(&nop_mnt_idmap, inode))
+ if (!inode_owner_or_capable(file_mnt_idmap(file), inode))
return -EACCES;
/* copy and validate */
diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c
index d8e46eb7e5eb..450a4dc9662e 100644
--- a/fs/ceph/mdsmap.c
+++ b/fs/ceph/mdsmap.c
@@ -15,7 +15,7 @@
#include "super.h"
#define CEPH_MDS_IS_READY(i, ignore_laggy) \
- (m->m_info[i].state > 0 && ignore_laggy ? true : !m->m_info[i].laggy)
+ (m->m_info[i].state > 0 && (ignore_laggy ? true : !m->m_info[i].laggy))
static int __mdsmap_get_random_mds(struct ceph_mdsmap *m, bool ignore_laggy)
{
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 8ca1767dafb6..2dfc313588d2 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -134,7 +134,8 @@ config EROFS_FS_ZIP_LZMA
config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS
int "EROFS LZMA default maximum decompression streams"
depends on EROFS_FS_ZIP_LZMA
- range 1 NR_CPUS
+ range 1 NR_CPUS if SMP
+ range 1 1 if !SMP
default 16
help
By default EROFS allocates one LZMA decompression stream per CPU.
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 60f0b7ceef0a..60b808b85fc4 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1544,7 +1544,8 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
int err;
err = -EIO;
- if (WARN_ON(fc->user_ns != current_user_ns()))
+ /* The fscontext fd may have been passed to another user namespace. */
+ if (fc->user_ns != current_user_ns())
goto out_err;
ovl_set_d_op(sb);
diff --git a/include/linux/rseq_entry.h b/include/linux/rseq_entry.h
index ed9da6e41a2a..31ce349ed42c 100644
--- a/include/linux/rseq_entry.h
+++ b/include/linux/rseq_entry.h
@@ -233,6 +233,7 @@ efault:
static __always_inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask)
{
if (unlikely(__rseq_grant_slice_extension(ti_work & mask))) {
+ guard(irq)();
hrtimer_rearm_deferred_tif(ti_work);
return true;
}
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 1cf4651f09ad..47750ccd1314 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -7,6 +7,8 @@
#include <linux/clockchips.h>
#include <linux/irqflags.h>
+#include <linux/jiffies.h>
+#include <linux/ktime.h>
#include <linux/percpu.h>
#include <linux/context_tracking_state.h>
#include <linux/cpumask.h>
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 20d9e55f8564..fd03f6319e88 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -270,6 +270,25 @@ int tcf_action_check_ctrlact(int action, struct tcf_proto *tp,
struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action,
struct tcf_chain *newchain);
+/* Range check for a control action supplied by user space.
+ *
+ * This is the same test tcf_action_check_ctrlact() applies to the primary
+ * control action, factored out for the *fallback* control actions
+ * (act_gact's TCA_GACT_PROB.paction and act_police's TCA_POLICE_RESULT),
+ * which must not reach tcf_action_check_ctrlact() because they have no
+ * goto_chain to allocate. Without it, user space can store kernel-internal
+ * verdicts such as TC_ACT_CONSUMED, which is TC_ACT_VALUE_MAX + 1 and is
+ * deliberately not part of the UAPI value range.
+ */
+static inline bool tcf_action_valid(int action)
+{
+ int opcode = TC_ACT_EXT_OPCODE(action);
+
+ if (!opcode)
+ return action <= TC_ACT_VALUE_MAX;
+ return opcode <= TC_ACT_EXT_OPCODE_MAX || action == TC_ACT_UNSPEC;
+}
+
#ifdef CONFIG_INET
DECLARE_STATIC_KEY_FALSE(tcf_frag_xmit_count);
#endif
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index d2813eb795be..be3a6617adf4 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -36,6 +36,12 @@
#define IP_VS_HDR_INVERSE 1
#define IP_VS_HDR_ICMP 2
+/* Destination Server Flags */
+#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */
+
+/* Destination Server Config Flags */
+#define IP_VS_DEST_CF_AVAILABLE 0x0001 /* server is available */
+
/* conn_tab limits (as per Kconfig) */
#define IP_VS_CONN_TAB_MIN_BITS 8
#if BITS_PER_LONG > 32
@@ -976,6 +982,7 @@ struct ip_vs_dest {
volatile unsigned int flags; /* dest status flags */
atomic_t conn_flags; /* flags to copy to conn */
atomic_t weight; /* server weight */
+ unsigned long cflags; /* config flags */
atomic_t last_weight; /* server latest weight */
__u16 tun_type; /* tunnel type */
__be16 tun_port; /* tunnel port */
@@ -987,10 +994,11 @@ struct ip_vs_dest {
/* connection counters and thresholds */
atomic_t activeconns; /* active connections */
- atomic_t inactconns; /* inactive connections */
+ atomic_t totalconns; /* total connections */
atomic_t persistconns; /* persistent connections */
__u32 u_threshold; /* upper threshold */
__u32 l_threshold; /* lower threshold */
+ __u32 l_threshold_val;/* used lower threshold */
/* for destination cache */
spinlock_t dst_lock; /* lock of dst_cache */
@@ -1907,6 +1915,8 @@ static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
kfree(dest);
}
+void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode);
+
/* IPVS sync daemon data and function prototypes
* (from ip_vs_sync.c)
*/
@@ -2058,7 +2068,7 @@ static inline bool ip_vs_conn_use_hash2(struct ip_vs_conn *cp)
!(cp->flags & IP_VS_CONN_F_TEMPLATE);
}
-void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+bool ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int dir, unsigned int toff,
bool has_ports, struct ip_vs_iphdr *ciph);
@@ -2220,14 +2230,21 @@ void ip_vs_unregister_hooks(struct netns_ipvs *ipvs, unsigned int af);
static inline int
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
{
- /* We think the overhead of processing active connections is 256
+ /* We think the overhead of processing active connections is 257
* times higher than that of inactive connections in average. (This
- * 256 times might not be accurate, we will change it later) We
+ * 257 times might not be accurate, we will change it later) We
* use the following formula to estimate the overhead now:
- * dest->activeconns*256 + dest->inactconns
+ * dest->activeconns*256 + dest->totalconns
*/
return (atomic_read(&dest->activeconns) << 8) +
- atomic_read(&dest->inactconns);
+ atomic_read(&dest->totalconns);
+}
+
+static inline int
+ip_vs_dest_inactconns(const struct ip_vs_dest *dest)
+{
+ return max(atomic_read(&dest->totalconns) -
+ atomic_read(&dest->activeconns), 0);
}
#ifdef CONFIG_IP_VS_PROTO_TCP
diff --git a/include/net/route.h b/include/net/route.h
index f90106f383c5..45290177a33c 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -276,6 +276,8 @@ int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
u32 table_id, struct fib_info *fi,
int *fa_index, int fa_start, unsigned int flags);
+void fnhe_update_pmtu(struct fib_nh_exception *fnhe, u32 new, u32 orig);
+
static inline void ip_rt_put(struct rtable *rt)
{
/* dst_release() accepts a NULL parameter.
diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h
index 6f2cd562b1de..74b3790e2a3d 100644
--- a/include/net/sctp/auth.h
+++ b/include/net/sctp/auth.h
@@ -22,6 +22,7 @@ struct sctp_endpoint;
struct sctp_association;
struct sctp_authkey;
struct sctp_hmacalgo;
+struct sctp_cookie;
/* Defines an HMAC algorithm supported by SCTP chunk authentication */
struct sctp_hmac {
@@ -72,6 +73,8 @@ struct sctp_shared_key *sctp_auth_get_shkey(
int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep,
struct sctp_association *asoc,
gfp_t gfp);
+bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep,
+ const struct sctp_cookie *cookie);
const struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id);
const struct sctp_hmac *
sctp_auth_asoc_get_hmac(const struct sctp_association *asoc);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index f6b286fa59f2..98b0ccf0813e 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -664,6 +664,9 @@ struct Scsi_Host {
/* Asynchronous scan in progress */
bool async_scan __guarded_by(&scan_mutex);
+ /* Don't resume host in EH */
+ bool eh_noresume;
+
unsigned active_mode:2;
/*
@@ -682,9 +685,6 @@ struct Scsi_Host {
/* Task mgmt function in progress */
unsigned tmf_in_progress:1;
- /* Don't resume host in EH */
- unsigned eh_noresume:1;
-
/* The controller does not support WRITE SAME */
unsigned no_write_same:1;
diff --git a/include/uapi/linux/ip_vs.h b/include/uapi/linux/ip_vs.h
index 1ed234e7f251..2c37c6ac7525 100644
--- a/include/uapi/linux/ip_vs.h
+++ b/include/uapi/linux/ip_vs.h
@@ -29,12 +29,6 @@
#define IP_VS_SVC_F_SCHED_SH_PORT IP_VS_SVC_F_SCHED2 /* SH use port */
/*
- * Destination Server Flags
- */
-#define IP_VS_DEST_F_AVAILABLE 0x0001 /* server is available */
-#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */
-
-/*
* IPVS sync daemon states
*/
#define IP_VS_STATE_NONE 0x0000 /* daemon is stopped */
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index 8d0f2ee24e0c..98dccefd801b 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -1653,8 +1653,12 @@ int io_import_reg_vec(int ddir, struct iov_iter *iter,
if (sizeof(struct bio_vec) > sizeof(struct iovec)) {
size_t bvec_bytes;
- bvec_bytes = nr_segs * sizeof(struct bio_vec);
- nr_segs = (bvec_bytes + sizeof(*iov) - 1) / sizeof(*iov);
+ if (check_mul_overflow((size_t)nr_segs, sizeof(struct bio_vec),
+ &bvec_bytes) ||
+ check_add_overflow(bvec_bytes, sizeof(*iov) - 1,
+ &bvec_bytes))
+ return -EOVERFLOW;
+ nr_segs = bvec_bytes / sizeof(*iov);
nr_segs += nr_iovs;
}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index ba5bd6a78fe7..1a73ba0747df 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2343,6 +2343,34 @@ static inline struct list_head *get_event_list(struct perf_event *event)
&event->pmu_ctx->flexible_active;
}
+/* @sibling must already be unlinked from its old leader's sibling_list. */
+static void perf_promote_sibling_to_leader(struct perf_event *sibling,
+ struct perf_event_context *ctx,
+ int group_caps)
+{
+ /*
+ * Events that have PERF_EV_CAP_SIBLING require being part of
+ * a group and cannot exist on their own, schedule them out
+ * and move them into the ERROR state. Also see
+ * _perf_event_enable(), it will not be able to recover this
+ * ERROR state.
+ */
+ if (sibling->event_caps & PERF_EV_CAP_SIBLING)
+ __event_disable(sibling, ctx, PERF_EVENT_STATE_ERROR);
+
+ sibling->group_leader = sibling;
+ sibling->group_caps = group_caps;
+
+ if (sibling->attach_state & PERF_ATTACH_CONTEXT) {
+ add_event_to_groups(sibling, ctx);
+
+ if (sibling->state == PERF_EVENT_STATE_ACTIVE)
+ list_add_tail(&sibling->active_list, get_event_list(sibling));
+ }
+
+ perf_event__header_size(sibling);
+}
+
static void perf_group_detach(struct perf_event *event)
{
struct perf_event *leader = event->group_leader;
@@ -2366,8 +2394,9 @@ static void perf_group_detach(struct perf_event *event)
*/
if (leader != event) {
list_del_init(&event->sibling_list);
- event->group_leader->nr_siblings--;
- event->group_leader->group_generation++;
+ leader->nr_siblings--;
+ leader->group_generation++;
+ perf_promote_sibling_to_leader(event, ctx, event->event_caps);
goto out;
}
@@ -2377,32 +2406,14 @@ static void perf_group_detach(struct perf_event *event)
* to whatever list we are on.
*/
list_for_each_entry_safe(sibling, tmp, &event->sibling_list, sibling_list) {
-
- /*
- * Events that have PERF_EV_CAP_SIBLING require being part of
- * a group and cannot exist on their own, schedule them out
- * and move them into the ERROR state. Also see
- * _perf_event_enable(), it will not be able to recover this
- * ERROR state.
- */
- if (sibling->event_caps & PERF_EV_CAP_SIBLING)
- __event_disable(sibling, ctx, PERF_EVENT_STATE_ERROR);
-
- sibling->group_leader = sibling;
list_del_init(&sibling->sibling_list);
/* Inherit group flags from the previous leader */
- sibling->group_caps = event->group_caps;
-
- if (sibling->attach_state & PERF_ATTACH_CONTEXT) {
- add_event_to_groups(sibling, event->ctx);
-
- if (sibling->state == PERF_EVENT_STATE_ACTIVE)
- list_add_tail(&sibling->active_list, get_event_list(sibling));
- }
+ perf_promote_sibling_to_leader(sibling, ctx, event->group_caps);
WARN_ON_ONCE(sibling->ctx != event->ctx);
}
+ event->nr_siblings = 0;
out:
for_each_sibling_event(tmp, leader)
@@ -2592,12 +2603,7 @@ __perf_remove_from_context(struct perf_event *event,
if (flags & DETACH_DEAD)
state = PERF_EVENT_STATE_DEAD;
- event_sched_out(event, ctx);
-
- if (event->state > PERF_EVENT_STATE_OFF)
- perf_cgroup_event_disable(event, ctx);
-
- perf_event_set_state(event, min(event->state, state));
+ __event_disable(event, ctx, state);
if (flags & DETACH_GROUP)
perf_group_detach(event);
@@ -2666,8 +2672,9 @@ static void __event_disable(struct perf_event *event,
enum perf_event_state state)
{
event_sched_out(event, ctx);
- perf_cgroup_event_disable(event, ctx);
- perf_event_set_state(event, state);
+ if (event->state > PERF_EVENT_STATE_OFF)
+ perf_cgroup_event_disable(event, ctx);
+ perf_event_set_state(event, min(event->state, state));
}
/*
@@ -13972,7 +13979,7 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_fd;
}
group_leader = fd_file(group)->private_data;
- if (group_leader->state <= PERF_EVENT_STATE_REVOKED) {
+ if (group_leader->state <= PERF_EVENT_STATE_EXIT) {
err = -ENODEV;
goto err_fd;
}
@@ -14103,6 +14110,12 @@ SYSCALL_DEFINE5(perf_event_open,
if (group_leader->ctx != ctx)
goto err_locked;
+ /* Recheck under ctx::mutex to serialize against remove-on-exec. */
+ if (group_leader->state <= PERF_EVENT_STATE_EXIT) {
+ err = -ENODEV;
+ goto err_locked;
+ }
+
/*
* Only a group leader can be exclusive or pinned
*/
diff --git a/kernel/pid.c b/kernel/pid.c
index f55189a3d07d..d01d0dd7114b 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -324,8 +324,10 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
* error path may try to wakeup the possibly freed ns->child_reaper.
*/
retval = -ENOMEM;
- if (unlikely(!(ns->pid_allocated & PIDNS_ADDING)))
- goto out_free;
+ for (upid = pid->numbers + ns->level; upid >= pid->numbers; --upid)
+ if (unlikely(!(upid->ns->pid_allocated & PIDNS_ADDING)))
+ goto out_free;
+
for (upid = pid->numbers + ns->level; upid >= pid->numbers; --upid) {
/* Make the PID visible to find_pid_ns. */
idr_replace(&upid->ns->idr, pid, upid->nr);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..f15f5764818e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7779,6 +7779,8 @@ requeue_delayed_entity(struct sched_entity *se)
WARN_ON_ONCE(!se->sched_delayed);
WARN_ON_ONCE(!se->on_rq);
+ update_curr(cfs_rq);
+
if (update_entity_lag(cfs_rq, se)) {
cfs_rq->nr_queued--;
if (se != cfs_rq->curr)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c01b10b99f67..3650d84d4f16 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -945,7 +945,7 @@ static int remove_cache_mod(struct trace_array *tr, const char *mod,
if (strcmp(event_mod->module, mod) != 0)
continue;
- if (match && strcmp(event_mod->match, match) != 0)
+ if (match && (!event_mod->match || strcmp(event_mod->match, match) != 0))
continue;
if (system &&
@@ -3566,6 +3566,7 @@ void trace_event_update_all(struct trace_eval_map **map, int len)
int last_i;
int i;
+ mutex_lock(&event_mutex);
down_write(&trace_event_sem);
list_for_each_entry_safe(call, p, &ftrace_events, list) {
/* events are usually grouped together with systems */
@@ -3604,6 +3605,7 @@ void trace_event_update_all(struct trace_eval_map **map, int len)
cond_resched();
}
up_write(&trace_event_sem);
+ mutex_unlock(&event_mutex);
}
static bool event_in_systems(struct trace_event_call *call,
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index d459bef245f4..8b2c405e7a66 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -1261,7 +1261,7 @@ static void rhashtable_free_one(struct rhashtable *ht, struct rhash_head *obj,
list = container_of(obj, struct rhlist_head, rhead);
do {
obj = &list->rhead;
- list = rht_dereference(list->next, ht);
+ list = rcu_dereference_raw(list->next);
free_fn(rht_obj(ht, obj), arg);
} while (list);
}
diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c
index 58a33d0380b0..7ecb8a26bfa3 100644
--- a/net/bridge/netfilter/nf_conntrack_bridge.c
+++ b/net/bridge/netfilter/nf_conntrack_bridge.c
@@ -280,6 +280,7 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
ret = nf_ct_br_defrag6(skb, &bridge_state);
break;
default:
+ nf_reset_ct(skb);
nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
return NF_ACCEPT;
}
diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c
index 377336982f7d..2c8fefc1a721 100644
--- a/net/ceph/cls_lock_client.c
+++ b/net/ceph/cls_lock_client.c
@@ -259,7 +259,8 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker)
if (ret)
return ret;
- ceph_decode_copy(p, &locker->id.name, sizeof(locker->id.name));
+ ceph_decode_copy_safe(p, end, &locker->id.name,
+ sizeof(locker->id.name), bad);
s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
if (IS_ERR(s))
return PTR_ERR(s);
@@ -270,19 +271,23 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker)
if (ret)
return ret;
- *p += sizeof(struct ceph_timespec); /* skip expiration */
+ /* skip expiration */
+ ceph_decode_skip_n(p, end, sizeof(struct ceph_timespec), bad);
ret = ceph_decode_entity_addr(p, end, &locker->info.addr);
if (ret)
return ret;
- len = ceph_decode_32(p);
- *p += len; /* skip description */
+ /* skip description */
+ ceph_decode_skip_string(p, end, bad);
dout("%s %s%llu cookie %s addr %s\n", __func__,
ENTITY_NAME(locker->id.name), locker->id.cookie,
ceph_pr_addr(&locker->info.addr));
return 0;
+
+bad:
+ return -EINVAL;
}
static int decode_lockers(void **p, void *end, u8 *type, char **tag,
diff --git a/net/ceph/decode.c b/net/ceph/decode.c
index bc109a1a4616..2f21af38cd9a 100644
--- a/net/ceph/decode.c
+++ b/net/ceph/decode.c
@@ -87,8 +87,9 @@ bad:
EXPORT_SYMBOL(ceph_decode_entity_addr);
/*
- * Return addr of desired type (MSGR2 or LEGACY) or error.
- * Make sure there is only one match.
+ * Return addr of desired type (MSGR2 or LEGACY) or error. In case of
+ * multiple matches, use the first one for compatibility with userspace
+ * messenger.
*
* Assume encoding with MSG_ADDR2.
*/
@@ -121,14 +122,13 @@ int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr));
if (tmp_addr.type == my_type) {
- if (found) {
- pr_err("another match of type %d in addrvec\n",
- le32_to_cpu(my_type));
- return -EINVAL;
+ if (!found) {
+ memcpy(addr, &tmp_addr, sizeof(*addr));
+ found = true;
+ } else {
+ dout("%s skipping extra match of type %d in addrvec\n",
+ __func__, le32_to_cpu(my_type));
}
-
- memcpy(addr, &tmp_addr, sizeof(*addr));
- found = true;
}
}
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 2ff00070c181..28d76c2f6b3e 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -5030,7 +5030,7 @@ static int decode_watchers(void **p, void *end,
if (ret)
return ret;
- *num_watchers = ceph_decode_32(p);
+ ceph_decode_32_safe(p, end, *num_watchers, bad);
*watchers = kzalloc_objs(**watchers, *num_watchers, GFP_NOIO);
if (!*watchers)
return -ENOMEM;
@@ -5044,6 +5044,9 @@ static int decode_watchers(void **p, void *end,
}
return 0;
+
+bad:
+ return -EINVAL;
}
/*
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index a4b0dd8672ec..d6282f0bcff8 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -2809,9 +2809,10 @@ static void get_temp_osds(struct ceph_osdmap *osdmap,
}
}
- /* primary_temp? */
+ /* primary_temp? (shouldn't ever be a nonexistent or down OSD) */
pg = lookup_pg_mapping(&osdmap->primary_temp, pgid);
- if (pg)
+ if (pg && !WARN_ON_ONCE(ceph_osd_is_down(osdmap,
+ pg->primary_temp.osd)))
temp->primary = pg->primary_temp.osd;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index af260ff5462a..ece6700536d9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5517,12 +5517,16 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
}
/* XDP frag metadata (e.g. nr_frags) are updated in eBPF helpers
- * (e.g. bpf_xdp_adjust_tail), we need to update data_len here.
+ * (e.g. bpf_xdp_adjust_tail). Remove the old fragment contribution
+ * from skb->len before updating data_len, then add the new one back.
*/
- if (xdp_buff_has_frags(xdp))
+ skb->len -= skb->data_len;
+ if (xdp_buff_has_frags(xdp)) {
skb->data_len = skb_shinfo(skb)->xdp_frags_size;
- else
+ skb->len += skb->data_len;
+ } else {
skb->data_len = 0;
+ }
/* check if XDP changed eth hdr such SKB needs update */
eth = (struct ethhdr *)xdp->data;
diff --git a/net/core/netdev_queues.c b/net/core/netdev_queues.c
index 4d6864bb4f6b..f5558b12877c 100644
--- a/net/core/netdev_queues.c
+++ b/net/core/netdev_queues.c
@@ -40,7 +40,7 @@ struct device *netdev_queue_get_dma_dev(struct net_device *dev,
struct netdev_rx_queue *hw_rxq;
struct device *dma_dev;
- netdev_assert_locked_ops_compat(dev);
+ netdev_assert_locked(dev);
/* Only RX side supports queue leasing today. */
if (type != NETDEV_QUEUE_TYPE_RX || !netif_rxq_is_leased(dev, idx))
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 78f84ae3ee12..0483519b7fb0 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1895,42 +1895,30 @@ static int call_fib_nh_notifiers(struct fib_nh *nh,
return NOTIFY_DONE;
}
-/* Update the PMTU of exceptions when:
- * - the new MTU of the first hop becomes smaller than the PMTU
- * - the old MTU was the same as the PMTU, and it limited discovery of
- * larger MTUs on the path. With that limit raised, we can now
- * discover larger MTUs
- * A special case is locked exceptions, for which the PMTU is smaller
- * than the minimal accepted PMTU:
- * - if the new MTU is greater than the PMTU, don't make any change
- * - otherwise, unlock and set PMTU
+/* Walk the exceptions of a nexthop after its first hop MTU changed. The
+ * chain is RCU protected here, while fnhe_update_pmtu() takes fnhe_lock
+ * for the update of each entry.
*/
void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
{
struct fnhe_hash_bucket *bucket;
int i;
- bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1);
+ rcu_read_lock();
+ bucket = rcu_dereference(nhc->nhc_exceptions);
if (!bucket)
- return;
+ goto out;
for (i = 0; i < FNHE_HASH_SIZE; i++) {
struct fib_nh_exception *fnhe;
- for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
+ for (fnhe = rcu_dereference(bucket[i].chain);
fnhe;
- fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
- if (fnhe->fnhe_mtu_locked) {
- if (new <= fnhe->fnhe_pmtu) {
- fnhe->fnhe_pmtu = new;
- fnhe->fnhe_mtu_locked = false;
- }
- } else if (new < fnhe->fnhe_pmtu ||
- orig == fnhe->fnhe_pmtu) {
- fnhe->fnhe_pmtu = new;
- }
- }
+ fnhe = rcu_dereference(fnhe->fnhe_next))
+ fnhe_update_pmtu(fnhe, new, orig);
}
+out:
+ rcu_read_unlock();
}
void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 152d8cb28f65..b82401a6baed 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -741,6 +741,35 @@ out_unlock:
spin_unlock_bh(&fnhe_lock);
}
+/* Update the PMTU of an exception when:
+ * - the new MTU of the first hop becomes smaller than the PMTU
+ * - the old MTU was the same as the PMTU, and it limited discovery of
+ * larger MTUs on the path. With that limit raised, we can now
+ * discover larger MTUs
+ * A special case is locked exceptions, for which the PMTU is smaller
+ * than the minimal accepted PMTU:
+ * - if the new MTU is greater than the PMTU, don't make any change
+ * - otherwise, unlock and set PMTU
+ *
+ * fnhe_lock keeps fnhe_pmtu and fnhe_mtu_locked consistent against
+ * update_or_create_fnhe(), which sets both under the same lock.
+ */
+void fnhe_update_pmtu(struct fib_nh_exception *fnhe, u32 new, u32 orig)
+{
+ spin_lock_bh(&fnhe_lock);
+
+ if (fnhe->fnhe_mtu_locked) {
+ if (new <= fnhe->fnhe_pmtu) {
+ fnhe->fnhe_pmtu = new;
+ fnhe->fnhe_mtu_locked = false;
+ }
+ } else if (new < fnhe->fnhe_pmtu || orig == fnhe->fnhe_pmtu) {
+ fnhe->fnhe_pmtu = new;
+ }
+
+ spin_unlock_bh(&fnhe_lock);
+}
+
static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4,
bool kill_route)
{
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 5b6378b94701..0f60a1dbf927 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1039,9 +1039,9 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
/* The fastest case is the first. */
icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + TCP_ATO_MIN / 2;
} else if (m < icsk->icsk_ack.ato) {
- icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + m;
- if (icsk->icsk_ack.ato > icsk->icsk_rto)
- icsk->icsk_ack.ato = icsk->icsk_rto;
+ icsk->icsk_ack.ato = min3((icsk->icsk_ack.ato >> 1) + (u32)m,
+ icsk->icsk_rto,
+ (u32)TCP_DELACK_MAX);
} else if (m > icsk->icsk_rto) {
/* Too long gap. Apparently sender failed to
* restart window, so that we send ACKs quickly.
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index bf171b5e1eb3..4df1c9745c5d 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -334,7 +334,9 @@ void tcp_delack_timer_handler(struct sock *sk)
if (inet_csk_ack_scheduled(sk)) {
if (!inet_csk_in_pingpong_mode(sk)) {
/* Delayed ACK missed: inflate ATO. */
- icsk->icsk_ack.ato = min_t(u32, icsk->icsk_ack.ato << 1, icsk->icsk_rto);
+ icsk->icsk_ack.ato = min3((u32)icsk->icsk_ack.ato << 1,
+ icsk->icsk_rto,
+ (u32)TCP_DELACK_MAX);
} else {
/* Delayed ACK missed: leave pingpong mode and
* deflate ATO.
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c
index b26986fda9d6..c12d5e1ee550 100644
--- a/net/l2tp/l2tp_debugfs.c
+++ b/net/l2tp/l2tp_debugfs.c
@@ -306,6 +306,10 @@ static int l2tp_dfs_seq_release(struct inode *inode, struct file *file)
seq = file->private_data;
pd = seq->private;
+ if (pd->session)
+ l2tp_session_put(pd->session);
+ if (pd->tunnel)
+ l2tp_tunnel_put(pd->tunnel);
if (pd->net)
put_net_track(pd->net, &pd->ns_tracker);
kfree(pd);
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index f8881699e1ca..ef8fdfaf051d 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1597,7 +1597,53 @@ static const struct seq_operations pppol2tp_seq_ops = {
.stop = pppol2tp_seq_stop,
.show = pppol2tp_seq_show,
};
-#endif /* CONFIG_PROC_FS */
+
+static int pppol2tp_proc_open(struct inode *inode, struct file *file)
+{
+ struct net *net = pde_data(inode);
+ struct pppol2tp_seq_data *pd;
+
+ net = maybe_get_net(net);
+ if (!net)
+ return -ENXIO;
+
+ pd = __seq_open_private(file, &pppol2tp_seq_ops, sizeof(*pd));
+ if (!pd) {
+ put_net(net);
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_NET_NS
+ pd->p.net = net;
+ netns_tracker_alloc(net, &pd->p.ns_tracker, GFP_KERNEL);
+#endif
+ return 0;
+}
+
+static int pppol2tp_proc_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct pppol2tp_seq_data *pd = seq->private;
+
+ if (pd->session)
+ l2tp_session_put(pd->session);
+ if (pd->tunnel)
+ l2tp_tunnel_put(pd->tunnel);
+
+#ifdef CONFIG_NET_NS
+ put_net_track(pd->p.net, &pd->p.ns_tracker);
+#else
+ put_net(&init_net);
+#endif
+ return seq_release_private(inode, file);
+}
+
+static const struct proc_ops pppol2tp_proc_ops = {
+ .proc_open = pppol2tp_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = pppol2tp_proc_release,
+};
/*****************************************************************************
* Network namespace
@@ -1608,8 +1654,8 @@ static __net_init int pppol2tp_init_net(struct net *net)
struct proc_dir_entry *pde;
int err = 0;
- pde = proc_create_net("pppol2tp", 0444, net->proc_net,
- &pppol2tp_seq_ops, sizeof(struct pppol2tp_seq_data));
+ pde = proc_create_data("pppol2tp", 0444, net->proc_net,
+ &pppol2tp_proc_ops, net);
if (!pde) {
err = -ENOMEM;
goto out;
@@ -1624,9 +1670,13 @@ static __net_exit void pppol2tp_exit_net(struct net *net)
remove_proc_entry("pppol2tp", net->proc_net);
}
+#endif /* CONFIG_PROC_FS */
+
static struct pernet_operations pppol2tp_net_ops = {
+#ifdef CONFIG_PROC_FS
.init = pppol2tp_init_net,
.exit = pppol2tp_exit_net,
+#endif
};
/*****************************************************************************
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
index 226fdf17b683..d6a7e6604542 100644
--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
+++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
mtype_ext_cleanup(set);
bitmap_zero(map->members, map->elements);
set->elements = 0;
- atomic64_set(&set->ext_size, 0);
+ DEBUG_NET_WARN_ON_ONCE(atomic64_read(&set->ext_size) > 0);
}
/* Calculate the actual memory size of the set data */
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 543851a923d0..0a86a170ba90 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -680,11 +680,18 @@ __ip_set_get(struct ip_set *set)
}
static void
-__ip_set_put(struct ip_set *set)
+__ip_set_put_locked(struct ip_set *set)
{
- write_lock_bh(&ip_set_ref_lock);
+ lockdep_assert_held(&ip_set_ref_lock);
BUG_ON(set->ref == 0);
set->ref--;
+}
+
+static void
+__ip_set_put(struct ip_set *set)
+{
+ write_lock_bh(&ip_set_ref_lock);
+ __ip_set_put_locked(set);
write_unlock_bh(&ip_set_ref_lock);
}
@@ -855,11 +862,11 @@ __ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index)
{
struct ip_set *set;
- rcu_read_lock();
- set = rcu_dereference(inst->ip_set_list)[index];
+ write_lock_bh(&ip_set_ref_lock);
+ set = ip_set(inst, index);
if (set)
- __ip_set_put(set);
- rcu_read_unlock();
+ __ip_set_put_locked(set);
+ write_unlock_bh(&ip_set_ref_lock);
}
void
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index ca3ef9479e83..f070088742d6 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -301,9 +301,12 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
e->set = set;
INIT_LIST_HEAD(&e->list);
list_set_init_extensions(set, ext, e);
- if (n)
+ if (n) {
list_set_replace(set, e, n);
- else if (next)
+ return 0;
+ }
+
+ if (next)
list_add_tail_rcu(&e->list, &next->list);
else if (prev)
list_add_rcu(&e->list, &prev->list);
@@ -420,8 +423,7 @@ list_set_flush(struct ip_set *set)
list_for_each_entry_safe(e, n, &map->members, list)
list_set_del(set, e);
- set->elements = 0;
- atomic64_set(&set->ext_size, 0);
+ DEBUG_NET_WARN_ON_ONCE(set->elements > 0);
}
static void
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 36c5cba03f5b..6fa3e1dc534c 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -1081,12 +1081,6 @@ static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
#endif
-static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
-{
- return atomic_read(&dest->activeconns)
- + atomic_read(&dest->inactconns);
-}
-
/*
* Bind a connection entry with a virtual service destination
* Called just after a new connection entry is created.
@@ -1147,23 +1141,22 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
/* Update the connection counters */
if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
+ int tc;
+
/* It is a normal connection, so modify the counters
* according to the flags, later the protocol can
* update them on state change
*/
if (!(flags & IP_VS_CONN_F_INACTIVE))
atomic_inc(&dest->activeconns);
- else
- atomic_inc(&dest->inactconns);
+ tc = atomic_inc_return(&dest->totalconns);
+ if (tc == READ_ONCE(dest->u_threshold))
+ ip_vs_dest_update_overload(dest, 1);
} else {
/* It is a persistent connection/template, so increase
the persistent connection counter */
atomic_inc(&dest->persistconns);
}
-
- if (dest->u_threshold != 0 &&
- ip_vs_dest_totalconns(dest) >= dest->u_threshold)
- dest->flags |= IP_VS_DEST_F_OVERLOAD;
}
@@ -1244,30 +1237,20 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
/* Update the connection counters */
if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
- /* It is a normal connection, so decrease the inactconns
- or activeconns counter */
- if (cp->flags & IP_VS_CONN_F_INACTIVE) {
- atomic_dec(&dest->inactconns);
- } else {
+ int tc;
+
+ /* It is a normal connection, so decrease the counters */
+ if (!(cp->flags & IP_VS_CONN_F_INACTIVE))
atomic_dec(&dest->activeconns);
- }
+ tc = atomic_fetch_dec(&dest->totalconns);
+ if (tc == READ_ONCE(dest->l_threshold_val))
+ ip_vs_dest_update_overload(dest, -1);
} else {
/* It is a persistent connection/template, so decrease
the persistent connection counter */
atomic_dec(&dest->persistconns);
}
- if (dest->l_threshold != 0) {
- if (ip_vs_dest_totalconns(dest) < dest->l_threshold)
- dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
- } else if (dest->u_threshold != 0) {
- if (ip_vs_dest_totalconns(dest) * 4 < dest->u_threshold * 3)
- dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
- } else {
- if (dest->flags & IP_VS_DEST_F_OVERLOAD)
- dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
- }
-
ip_vs_dest_put(dest);
}
@@ -1296,7 +1279,7 @@ int ip_vs_check_template(struct ip_vs_conn *ct, struct ip_vs_dest *cdest)
* Checking the dest server status.
*/
if ((dest == NULL) ||
- !(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
+ !(dest->cflags & IP_VS_DEST_CF_AVAILABLE) ||
expire_quiescent_template(ipvs, dest) ||
(cdest && (dest != cdest))) {
IP_VS_DBG_BUF(9, "check_template: dest not available for "
@@ -2037,7 +2020,7 @@ repeat:
cp = ip_vs_hn0_to_conn(hn);
resched_score++;
dest = cp->dest;
- if (!dest || (dest->flags & IP_VS_DEST_F_AVAILABLE))
+ if (!dest || (dest->cflags & IP_VS_DEST_CF_AVAILABLE))
continue;
if (atomic_read(&cp->n_control))
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 0bdaeb4ed61e..eb806813292a 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -302,7 +302,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
struct ip_vs_dest *dest = cp->dest;
struct netns_ipvs *ipvs = cp->ipvs;
- if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if (dest && (dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
struct ip_vs_cpu_stats *s;
struct ip_vs_service *svc;
@@ -338,7 +338,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
struct ip_vs_dest *dest = cp->dest;
struct netns_ipvs *ipvs = cp->ipvs;
- if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if (dest && (dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
struct ip_vs_cpu_stats *s;
struct ip_vs_service *svc;
@@ -923,7 +923,7 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
* Packet has been made sufficiently writable in caller
* - inout: 1=in->out, 0=out->in
*/
-void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+bool ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int inout, unsigned int toff,
bool has_ports, struct ip_vs_iphdr *ciph)
{
@@ -931,6 +931,11 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
struct iphdr *cih = (struct iphdr *)(icmph + 1);
+ /* Before now we may used ihl from skb frag, revalidate it after
+ * copying it into skb head to prevent out-of-bounds access
+ */
+ if (cih->ihl * 4 != ciph->len - ciph->off)
+ return false;
if (inout) {
iph->saddr = cp->vaddr.ip;
ip_send_check(iph);
@@ -964,6 +969,7 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
else
IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
"Forwarding altered incoming ICMP");
+ return true;
}
#ifdef CONFIG_IP_VS_IPV6
@@ -1055,7 +1061,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
else
#endif
- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+ if (!ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph))
+ goto out;
if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
goto out;
@@ -1950,6 +1957,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
if (pskb_pull(skb, offset2) == NULL)
goto ignore_tunnel;
skb_reset_network_header(skb);
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
/* Ensure the IP header is present in headroom */
if (!pskb_may_pull(skb, hlen_orig))
goto ignore_tunnel;
@@ -2210,7 +2218,7 @@ ip_vs_in_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state
}
/* Check the server status */
- if (cp && cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if (cp && cp->dest && !(cp->dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
/* the destination server is not available */
if (sysctl_expire_nodest_conn(ipvs)) {
bool old_ct = ip_vs_conn_uses_old_conntrack(cp, skb);
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index bcf40b8c41cf..8f9a8e491ad6 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1304,6 +1304,40 @@ void ip_vs_stats_free(struct ip_vs_stats *stats)
}
}
+/* Update overload flag based on number of dest conns and lower/upper
+ * connection thresholds:
+ * - conns reach u_threshold and exceed it: set the flag
+ * - conns go below l_threshold (or 75% of u_threshold): clear the flag
+ */
+static void __ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode)
+{
+ int conns;
+ u32 l, u;
+
+ lockdep_assert_held(&dest->dst_lock);
+ u = READ_ONCE(dest->u_threshold);
+ if (!u)
+ goto unset;
+ l = READ_ONCE(dest->l_threshold_val);
+ conns = atomic_read(&dest->totalconns);
+ if (conns >= (mode > 0 ? l : u)) {
+ dest->flags |= IP_VS_DEST_F_OVERLOAD;
+ return;
+ }
+ if (conns >= (mode < 0 ? u : l))
+ return;
+
+unset:
+ dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
+}
+
+void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode)
+{
+ spin_lock_bh(&dest->dst_lock);
+ __ip_vs_dest_update_overload(dest, mode);
+ spin_unlock_bh(&dest->dst_lock);
+}
+
/*
* Update a destination in the given service
*/
@@ -1368,12 +1402,21 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
}
/* set the dest status flags */
- dest->flags |= IP_VS_DEST_F_AVAILABLE;
+ dest->cflags |= IP_VS_DEST_CF_AVAILABLE;
- if (udest->u_threshold == 0 || udest->u_threshold > dest->u_threshold)
- dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
- dest->u_threshold = udest->u_threshold;
- dest->l_threshold = udest->l_threshold;
+ if (READ_ONCE(dest->u_threshold) != udest->u_threshold ||
+ READ_ONCE(dest->l_threshold) != udest->l_threshold) {
+ spin_lock_bh(&dest->dst_lock);
+ WRITE_ONCE(dest->u_threshold, udest->u_threshold);
+ WRITE_ONCE(dest->l_threshold, udest->l_threshold);
+ /* Low threshold defaults to 75% of upper threshold */
+ WRITE_ONCE(dest->l_threshold_val,
+ udest->l_threshold ? :
+ (udest->u_threshold -
+ (udest->u_threshold >> 2)));
+ __ip_vs_dest_update_overload(dest, 0);
+ spin_unlock_bh(&dest->dst_lock);
+ }
dest->af = udest->af;
@@ -1445,7 +1488,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
dest->port = udest->port;
atomic_set(&dest->activeconns, 0);
- atomic_set(&dest->inactconns, 0);
+ atomic_set(&dest->totalconns, 0);
atomic_set(&dest->persistconns, 0);
refcount_set(&dest->refcnt, 1);
@@ -1486,6 +1529,9 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
return -ERANGE;
}
+ if (udest->u_threshold > INT_MAX)
+ return -EINVAL;
+
if (udest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
if (udest->tun_port == 0) {
pr_err("%s(): tunnel port is zero\n", __func__);
@@ -1559,6 +1605,9 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
return -ERANGE;
}
+ if (udest->u_threshold > INT_MAX)
+ return -EINVAL;
+
if (udest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
if (udest->tun_port == 0) {
pr_err("%s(): tunnel port is zero\n", __func__);
@@ -1613,7 +1662,7 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
struct ip_vs_dest *dest,
int svcupd)
{
- dest->flags &= ~IP_VS_DEST_F_AVAILABLE;
+ dest->cflags &= ~IP_VS_DEST_CF_AVAILABLE;
spin_lock_bh(&dest->dst_lock);
__ip_vs_dst_cache_reset(dest);
@@ -3031,7 +3080,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
atomic_read(&dest->weight),
atomic_read(&dest->activeconns),
- atomic_read(&dest->inactconns));
+ ip_vs_dest_inactconns(dest));
else
#endif
seq_printf(seq,
@@ -3042,7 +3091,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
atomic_read(&dest->weight),
atomic_read(&dest->activeconns),
- atomic_read(&dest->inactconns));
+ ip_vs_dest_inactconns(dest));
}
}
@@ -3667,10 +3716,10 @@ __ip_vs_get_dest_entries(struct netns_ipvs *ipvs, const struct ip_vs_get_dests *
entry.port = dest->port;
entry.conn_flags = atomic_read(&dest->conn_flags);
entry.weight = atomic_read(&dest->weight);
- entry.u_threshold = dest->u_threshold;
- entry.l_threshold = dest->l_threshold;
+ entry.u_threshold = READ_ONCE(dest->u_threshold);
+ entry.l_threshold = READ_ONCE(dest->l_threshold);
entry.activeconns = atomic_read(&dest->activeconns);
- entry.inactconns = atomic_read(&dest->inactconns);
+ entry.inactconns = ip_vs_dest_inactconns(dest);
entry.persistconns = atomic_read(&dest->persistconns);
ip_vs_copy_stats(&kstats, &dest->stats);
ip_vs_export_stats_user(&entry.stats, &kstats);
@@ -4277,12 +4326,14 @@ static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
dest->tun_port) ||
nla_put_u16(skb, IPVS_DEST_ATTR_TUN_FLAGS,
dest->tun_flags) ||
- nla_put_u32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold) ||
- nla_put_u32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_U_THRESH,
+ READ_ONCE(dest->u_threshold)) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_L_THRESH,
+ READ_ONCE(dest->l_threshold)) ||
nla_put_u32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
atomic_read(&dest->activeconns)) ||
nla_put_u32(skb, IPVS_DEST_ATTR_INACT_CONNS,
- atomic_read(&dest->inactconns)) ||
+ ip_vs_dest_inactconns(dest)) ||
nla_put_u32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
atomic_read(&dest->persistconns)) ||
nla_put_u16(skb, IPVS_DEST_ATTR_ADDR_FAMILY, dest->af))
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index e1f62f6b25e2..43abed7a26a6 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -219,8 +219,8 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
s = (struct ip_vs_dh_state *) svc->sched_data;
dest = ip_vs_dh_get(svc->af, s, &iph->daddr);
- if (!dest
- || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
+ if (!dest ||
+ !(dest->cflags & IP_VS_DEST_CF_AVAILABLE)
|| atomic_read(&dest->weight) <= 0
|| is_overloaded(dest)) {
ip_vs_scheduler_err(svc, "no destination available");
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 15ccb2b2fa1f..693bcc82ccb7 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -502,7 +502,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
dest = en->dest;
- if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
+ if ((dest->cflags & IP_VS_DEST_CF_AVAILABLE) &&
atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
goto out;
}
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index c90ea897c3f7..f53f05ceea36 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -169,8 +169,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
if (least->flags & IP_VS_DEST_F_OVERLOAD)
continue;
- if ((atomic_read(&least->weight) > 0)
- && (least->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if ((atomic_read(&least->weight) > 0) &&
+ (least->cflags & IP_VS_DEST_CF_AVAILABLE)) {
loh = ip_vs_dest_conn_overhead(least);
goto nextstage;
}
@@ -186,8 +186,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
doh = ip_vs_dest_conn_overhead(dest);
if (((__s64)loh * atomic_read(&dest->weight) >
- (__s64)doh * atomic_read(&least->weight))
- && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ (__s64)doh * atomic_read(&least->weight)) &&
+ (dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
least = dest;
loh = doh;
}
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c
index 38cc38c5d8bb..18b976a7c4d2 100644
--- a/net/netfilter/ipvs/ip_vs_lc.c
+++ b/net/netfilter/ipvs/ip_vs_lc.c
@@ -30,7 +30,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
/*
* Simply select the server with the least number of
- * (activeconns<<5) + inactconns
+ * (activeconns*256) + totalconns
* Except whose weight is equal to zero.
* If the weight is equal to zero, it means that the server is
* quiesced, the existing connections to the server still get
@@ -56,7 +56,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
IP_VS_DBG_ADDR(least->af, &least->addr),
ntohs(least->port),
atomic_read(&least->activeconns),
- atomic_read(&least->inactconns));
+ ip_vs_dest_inactconns(least));
return least;
}
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index c80567c73469..fb8af6b15a39 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -446,12 +446,10 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
(next_state != IP_VS_SCTP_S_ESTABLISHED)) {
atomic_dec(&dest->activeconns);
- atomic_inc(&dest->inactconns);
cp->flags |= IP_VS_CONN_F_INACTIVE;
} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
(next_state == IP_VS_SCTP_S_ESTABLISHED)) {
atomic_inc(&dest->activeconns);
- atomic_dec(&dest->inactconns);
cp->flags &= ~IP_VS_CONN_F_INACTIVE;
}
}
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 99a286fdc90c..fec0e8b47b71 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -526,12 +526,10 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
!tcp_state_active(new_state)) {
atomic_dec(&dest->activeconns);
- atomic_inc(&dest->inactconns);
cp->flags |= IP_VS_CONN_F_INACTIVE;
} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
tcp_state_active(new_state)) {
atomic_inc(&dest->activeconns);
- atomic_dec(&dest->inactconns);
cp->flags &= ~IP_VS_CONN_F_INACTIVE;
}
}
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 93038abbf5e0..ea5fdd4f4ce7 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -878,13 +878,10 @@ static void ip_vs_proc_conn(struct netns_ipvs *ipvs, struct ip_vs_conn_param *pa
spin_lock_bh(&cp->lock);
if ((cp->flags ^ flags) & IP_VS_CONN_F_INACTIVE &&
!(flags & IP_VS_CONN_F_TEMPLATE) && dest) {
- if (flags & IP_VS_CONN_F_INACTIVE) {
+ if (flags & IP_VS_CONN_F_INACTIVE)
atomic_dec(&dest->activeconns);
- atomic_inc(&dest->inactconns);
- } else {
+ else
atomic_inc(&dest->activeconns);
- atomic_dec(&dest->inactconns);
- }
}
flags &= IP_VS_CONN_F_BACKUP_UPD_MASK;
flags |= cp->flags & ~IP_VS_CONN_F_BACKUP_UPD_MASK;
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index c4508f3f43dd..04450a48f01a 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -351,7 +351,7 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
* stored in dest_trash.
*/
if (!rt_dev_is_down(dst_dev_rcu(&rt->dst)) &&
- dest->flags & IP_VS_DEST_F_AVAILABLE)
+ dest->cflags & IP_VS_DEST_CF_AVAILABLE)
__ip_vs_dst_set(dest, dest_dst, &rt->dst, 0);
else
noref = 0;
@@ -530,7 +530,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
* stored in dest_trash.
*/
if (!rt_dev_is_down(dst_dev_rcu(&rt->dst)) &&
- dest->flags & IP_VS_DEST_F_AVAILABLE)
+ dest->cflags & IP_VS_DEST_CF_AVAILABLE)
__ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie);
else
noref = 0;
@@ -1580,7 +1580,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error;
- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+ if (!ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph))
+ goto tx_error;
/* Another hack: avoid icmp_send in ip_fragment */
skb->ignore_df = 1;
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index ad96896516b6..7a40e4e0e33e 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -79,6 +79,12 @@ void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
struct net *net;
va_list args;
+ /* nfnetlink_log may re-enter conntrack attribute dumping and try to
+ * take ct->lock again via helpers such as tcp_to_nlattr(), so invalid
+ * conntrack logs must only be emitted after dropping ct->lock.
+ */
+ lockdep_assert_not_held(&ct->lock);
+
net = nf_ct_net(ct);
if (likely(net->ct.sysctl_log_invalid == 0))
return;
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 7e10fa65cbdd..71cc920f6856 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -336,10 +336,12 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
struct sctphdr _sctph;
const struct sctp_chunkhdr *sch;
struct sctp_chunkhdr _sch;
+ bool log_invalid = false;
u_int32_t offset, count;
unsigned int *timeouts;
unsigned long map[256 / sizeof(unsigned long)] = { 0 };
bool ignore = false;
+ u8 invalid_type = 0;
if (sctp_error(skb, dataoff, state))
return -NF_ACCEPT;
@@ -451,10 +453,8 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
/* Invalid */
if (new_state == SCTP_CONNTRACK_MAX) {
- nf_ct_l4proto_log_invalid(skb, ct, state,
- "Invalid, old_state %d, dir %d, type %d",
- old_state, dir, sch->type);
-
+ log_invalid = true;
+ invalid_type = sch->type;
goto out_unlock;
}
@@ -529,6 +529,10 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
out_unlock:
spin_unlock_bh(&ct->lock);
+ if (log_invalid)
+ nf_ct_l4proto_log_invalid(skb, ct, state,
+ "Invalid, old_state %d, dir %d, type %d",
+ old_state, dir, invalid_type);
out:
return -NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ceeed3d7fe52..30b970e2ade5 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -480,37 +480,81 @@ static void tcp_init_sender(struct ip_ct_tcp_state *sender,
}
}
-__printf(6, 7)
-static enum nf_ct_tcp_action nf_tcp_log_invalid(const struct sk_buff *skb,
- const struct nf_conn *ct,
- const struct nf_hook_state *state,
- const struct ip_ct_tcp_state *sender,
- enum nf_ct_tcp_action ret,
- const char *fmt, ...)
+enum nf_tcp_invalid_log_type {
+ NF_TCP_LOG_NONE,
+ NF_TCP_LOG_OVERSHOT,
+ NF_TCP_LOG_SEQ_OVER,
+ NF_TCP_LOG_ACK_OVER,
+ NF_TCP_LOG_SEQ_UNDER,
+ NF_TCP_LOG_ACK_UNDER,
+};
+
+struct nf_tcp_invalid_log {
+ enum nf_tcp_invalid_log_type type;
+ u32 value;
+};
+
+static enum nf_ct_tcp_action
+nf_tcp_store_invalid(const struct nf_conn *ct,
+ const struct ip_ct_tcp_state *sender,
+ struct nf_tcp_invalid_log *log,
+ enum nf_ct_tcp_action ret,
+ enum nf_tcp_invalid_log_type type,
+ u32 value)
{
const struct nf_tcp_net *tn = nf_tcp_pernet(nf_ct_net(ct));
- struct va_format vaf;
- va_list args;
bool be_liberal;
be_liberal = sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || tn->tcp_be_liberal;
if (be_liberal)
return NFCT_TCP_ACCEPT;
- va_start(args, fmt);
- vaf.fmt = fmt;
- vaf.va = &args;
- nf_ct_l4proto_log_invalid(skb, ct, state, "%pV", &vaf);
- va_end(args);
-
+ log->type = type;
+ log->value = value;
return ret;
}
+static void nf_tcp_log_invalid(const struct sk_buff *skb,
+ const struct nf_conn *ct,
+ const struct nf_hook_state *state,
+ const struct nf_tcp_invalid_log *log)
+{
+ switch (log->type) {
+ case NF_TCP_LOG_OVERSHOT:
+ nf_ct_l4proto_log_invalid(skb, ct, state,
+ "%u bytes more than expected",
+ log->value);
+ break;
+ case NF_TCP_LOG_SEQ_OVER:
+ nf_ct_l4proto_log_invalid(skb, ct, state,
+ "SEQ is over upper bound %u (over the window of the receiver)",
+ log->value);
+ break;
+ case NF_TCP_LOG_ACK_OVER:
+ nf_ct_l4proto_log_invalid(skb, ct, state,
+ "ACK is over upper bound %u (ACKed data not seen yet)",
+ log->value);
+ break;
+ case NF_TCP_LOG_SEQ_UNDER:
+ nf_ct_l4proto_log_invalid(skb, ct, state,
+ "SEQ is under lower bound %u (already ACKed data retransmitted)",
+ log->value);
+ break;
+ case NF_TCP_LOG_ACK_UNDER:
+ nf_ct_l4proto_log_invalid(skb, ct, state,
+ "ignored ACK under lower bound %u (possible overly delayed)",
+ log->value);
+ break;
+ case NF_TCP_LOG_NONE:
+ break;
+ }
+}
+
static enum nf_ct_tcp_action
tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir,
unsigned int index, const struct sk_buff *skb,
unsigned int dataoff, const struct tcphdr *tcph,
- const struct nf_hook_state *hook_state)
+ struct nf_tcp_invalid_log *log)
{
struct ip_ct_tcp *state = &ct->proto.tcp;
struct ip_ct_tcp_state *sender = &state->seen[dir];
@@ -640,31 +684,29 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir,
sender->td_end = end;
sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED;
- return nf_tcp_log_invalid(skb, ct, hook_state, sender, NFCT_TCP_IGNORE,
- "%u bytes more than expected", overshot);
+ return nf_tcp_store_invalid(ct, sender, log, NFCT_TCP_IGNORE,
+ NF_TCP_LOG_OVERSHOT, overshot);
}
- return nf_tcp_log_invalid(skb, ct, hook_state, sender, NFCT_TCP_INVALID,
- "SEQ is over upper bound %u (over the window of the receiver)",
- sender->td_maxend + 1);
+ return nf_tcp_store_invalid(ct, sender, log, NFCT_TCP_INVALID,
+ NF_TCP_LOG_SEQ_OVER, sender->td_maxend + 1);
}
if (!before(sack, receiver->td_end + 1))
- return nf_tcp_log_invalid(skb, ct, hook_state, sender, NFCT_TCP_INVALID,
- "ACK is over upper bound %u (ACKed data not seen yet)",
- receiver->td_end + 1);
+ return nf_tcp_store_invalid(ct, sender, log, NFCT_TCP_INVALID,
+ NF_TCP_LOG_ACK_OVER, receiver->td_end + 1);
/* Is the ending sequence in the receive window (if available)? */
in_recv_win = !receiver->td_maxwin ||
after(end, sender->td_end - receiver->td_maxwin - 1);
if (!in_recv_win)
- return nf_tcp_log_invalid(skb, ct, hook_state, sender, NFCT_TCP_IGNORE,
- "SEQ is under lower bound %u (already ACKed data retransmitted)",
- sender->td_end - receiver->td_maxwin - 1);
+ return nf_tcp_store_invalid(ct, sender, log, NFCT_TCP_IGNORE,
+ NF_TCP_LOG_SEQ_UNDER,
+ sender->td_end - receiver->td_maxwin - 1);
if (!after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1))
- return nf_tcp_log_invalid(skb, ct, hook_state, sender, NFCT_TCP_IGNORE,
- "ignored ACK under lower bound %u (possible overly delayed)",
- receiver->td_end - MAXACKWINDOW(sender) - 1);
+ return nf_tcp_store_invalid(ct, sender, log, NFCT_TCP_IGNORE,
+ NF_TCP_LOG_ACK_UNDER,
+ receiver->td_end - MAXACKWINDOW(sender) - 1);
/* Take into account window scaling (RFC 1323). */
if (!tcph->syn)
@@ -719,11 +761,8 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir,
return NFCT_TCP_ACCEPT;
}
-static void __cold nf_tcp_handle_invalid(struct nf_conn *ct,
- enum ip_conntrack_dir dir,
- int index,
- const struct sk_buff *skb,
- const struct nf_hook_state *hook_state)
+static bool __cold
+nf_tcp_handle_invalid(struct nf_conn *ct, enum ip_conntrack_dir dir, int index)
{
const unsigned int *timeouts;
const struct nf_tcp_net *tn;
@@ -732,7 +771,7 @@ static void __cold nf_tcp_handle_invalid(struct nf_conn *ct,
if (!test_bit(IPS_ASSURED_BIT, &ct->status) ||
test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status))
- return;
+ return false;
/* We don't want to have connections hanging around in ESTABLISHED
* state for long time 'just because' conntrack deemed a FIN/RST
@@ -747,7 +786,7 @@ static void __cold nf_tcp_handle_invalid(struct nf_conn *ct,
case TCP_FIN_SET:
break;
default:
- return;
+ return false;
}
if (ct->proto.tcp.last_dir != dir &&
@@ -755,7 +794,7 @@ static void __cold nf_tcp_handle_invalid(struct nf_conn *ct,
ct->proto.tcp.last_index == TCP_RST_SET)) {
expires = nf_ct_expires(ct);
if (expires < 120 * HZ)
- return;
+ return false;
tn = nf_tcp_pernet(nf_ct_net(ct));
timeouts = nf_ct_timeout_lookup(ct);
@@ -764,16 +803,15 @@ static void __cold nf_tcp_handle_invalid(struct nf_conn *ct,
timeout = READ_ONCE(timeouts[TCP_CONNTRACK_UNACK]);
if (expires > timeout) {
- nf_ct_l4proto_log_invalid(skb, ct, hook_state,
- "packet (index %d, dir %d) response for index %d lower timeout to %u",
- index, dir, ct->proto.tcp.last_index, timeout);
-
WRITE_ONCE(ct->timeout, timeout + nfct_time_stamp);
+ return true;
}
} else {
ct->proto.tcp.last_index = index;
ct->proto.tcp.last_dir = dir;
}
+
+ return false;
}
/* table of valid flag combinations - PUSH, ECE and CWR are always valid */
@@ -969,7 +1007,9 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
struct net *net = nf_ct_net(ct);
struct nf_tcp_net *tn = nf_tcp_pernet(net);
enum tcp_conntrack new_state, old_state;
+ struct nf_tcp_invalid_log log = {};
unsigned int index, *timeouts;
+ bool lowered_timeout = false;
enum nf_ct_tcp_action res;
enum ip_conntrack_dir dir;
const struct tcphdr *th;
@@ -1252,14 +1292,18 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
}
res = tcp_in_window(ct, dir, index,
- skb, dataoff, th, state);
+ skb, dataoff, th, &log);
switch (res) {
case NFCT_TCP_IGNORE:
spin_unlock_bh(&ct->lock);
+ nf_tcp_log_invalid(skb, ct, state, &log);
return NF_ACCEPT;
case NFCT_TCP_INVALID:
- nf_tcp_handle_invalid(ct, dir, index, skb, state);
+ lowered_timeout = nf_tcp_handle_invalid(ct, dir, index);
spin_unlock_bh(&ct->lock);
+ nf_tcp_log_invalid(skb, ct, state, &log);
+ if (lowered_timeout)
+ nf_ct_l4proto_log_invalid(skb, ct, state, "lowered timeout to UNACK");
return -NF_ACCEPT;
case NFCT_TCP_ACCEPT:
break;
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index b66e65439341..8b1165f2b5a4 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -332,17 +332,18 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
err = rhashtable_insert_fast(&flow_table->rhashtable,
- &flow->tuplehash[0].node,
+ &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
nf_flow_offload_rhash_params);
if (err < 0)
return err;
+ /* GC only iterates original-direction entries; publish original last. */
err = rhashtable_insert_fast(&flow_table->rhashtable,
- &flow->tuplehash[1].node,
+ &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
nf_flow_offload_rhash_params);
if (err < 0) {
rhashtable_remove_fast(&flow_table->rhashtable,
- &flow->tuplehash[0].node,
+ &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
nf_flow_offload_rhash_params);
return err;
}
diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c
index e37b09b3203b..5ffde27d450a 100644
--- a/net/netfilter/nf_log_syslog.c
+++ b/net/netfilter/nf_log_syslog.c
@@ -1014,7 +1014,7 @@ err1:
return ret;
}
-static void __net_exit nf_log_syslog_net_exit(struct net *net)
+static void __net_exit nf_log_syslog_net_pre_exit(struct net *net)
{
nf_log_unset(net, &nf_ip_logger);
nf_log_unset(net, &nf_arp_logger);
@@ -1025,7 +1025,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net)
static struct pernet_operations nf_log_syslog_net_ops = {
.init = nf_log_syslog_net_init,
- .exit = nf_log_syslog_net_exit,
+ .pre_exit = nf_log_syslog_net_pre_exit,
};
static int __init nf_log_syslog_init(void)
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index 8998a24651ff..0ac3c26dfb3d 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -558,7 +558,7 @@ static void nft_flow_rule_offload_abort(struct net *net,
break;
}
- if (WARN_ON_ONCE(err))
+ if (WARN_ON_ONCE(err && err != -ENOMEM))
break;
}
}
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 5fee61b3813c..6c7fa2ed34f5 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1170,21 +1170,26 @@ static int __net_init nfnl_log_net_init(struct net *net)
return 0;
}
-static void __net_exit nfnl_log_net_exit(struct net *net)
+static void __net_exit nfnl_log_net_pre_exit(struct net *net)
{
- struct nfnl_log_net *log = nfnl_log_pernet(net);
- unsigned int i;
-
#ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
#endif
nf_log_unset(net, &nfulnl_logger);
+}
+
+static void __net_exit nfnl_log_net_exit(struct net *net)
+{
+ struct nfnl_log_net *log = nfnl_log_pernet(net);
+ unsigned int i;
+
for (i = 0; i < INSTANCE_BUCKETS; i++)
WARN_ON_ONCE(!hlist_empty(&log->instance_table[i]));
}
static struct pernet_operations nfnl_log_net_ops = {
.init = nfnl_log_net_init,
+ .pre_exit = nfnl_log_net_pre_exit,
.exit = nfnl_log_net_exit,
.id = &nfnl_log_net_id,
.size = sizeof(struct nfnl_log_net),
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 435756877aba..1168bd6b09cd 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1943,13 +1943,13 @@ static void packet_parse_headers(struct sk_buff *skb, struct socket *sock)
sock->type == SOCK_RAW)
skb->protocol = dev_parse_header_protocol(skb);
+ skb_probe_transport_header(skb);
+
/* Move network header to the right position for VLAN tagged packets */
if (likely(skb->dev->type == ARPHRD_ETHER) &&
eth_type_vlan(skb->protocol) &&
vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
skb_set_network_header(skb, depth);
-
- skb_probe_transport_header(skb);
}
/*
@@ -2660,6 +2660,9 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
len = ((to_write > len_max) ? len_max : to_write);
}
+ if (unlikely(!skb->len))
+ return -EINVAL;
+
packet_parse_headers(skb, sock);
return tp_len;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index f141634df214..600b7804befd 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -41,11 +41,9 @@ int tcf_dev_queue_xmit(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb))
}
EXPORT_SYMBOL_GPL(tcf_dev_queue_xmit);
-static void tcf_action_goto_chain_exec(const struct tc_action *a,
+static void tcf_action_goto_chain_exec(const struct tcf_chain *chain,
struct tcf_result *res)
{
- const struct tcf_chain *chain = rcu_dereference_bh(a->goto_chain);
-
res->goto_tp = rcu_dereference_bh(chain->filter_chain);
}
@@ -1170,12 +1168,14 @@ repeat:
return TC_ACT_OK;
}
} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
- if (unlikely(!rcu_access_pointer(a->goto_chain))) {
+ struct tcf_chain *chain = rcu_dereference_bh(a->goto_chain);
+
+ if (unlikely(!chain)) {
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_CHAIN_NOTFOUND);
return TC_ACT_SHOT;
}
- tcf_action_goto_chain_exec(a, res);
+ tcf_action_goto_chain_exec(chain, res);
}
if (ret != TC_ACT_PIPE)
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index be535a261fa0..e250969c84ac 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -840,8 +840,15 @@ static int tcf_ct_ipv6_is_fragment(struct sk_buff *skb, bool *frag)
return 0;
}
+/* On error, tells the caller whether it still owns @skb and must free it
+ * itself. @skb is ours only when the header checks below reject the packet
+ * before it is handed to the defragmentation engine; once nf_ct_handle_
+ * fragments() has been called the skb is either queued (-EINPROGRESS) or has
+ * already been freed by it.
+ */
static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
- u8 family, u16 zone, bool *defrag)
+ u8 family, u16 zone, bool *defrag,
+ bool *skb_is_ours)
{
enum ip_conntrack_info ctinfo;
struct tc_skb_cb cb;
@@ -859,8 +866,12 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
err = tcf_ct_ipv4_is_fragment(skb, &frag);
else
err = tcf_ct_ipv6_is_fragment(skb, &frag);
- if (err || !frag)
+ if (err) {
+ *skb_is_ours = true;
return err;
+ }
+ if (!frag)
+ return 0;
cb = *tc_skb_cb(skb);
err = nf_ct_handle_fragments(net, skb, zone, family, &proto, &cb.mru);
@@ -977,6 +988,7 @@ TC_INDIRECT_SCOPE int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
int nh_ofs, err, retval;
struct tcf_ct_params *p;
bool add_helper = false;
+ bool skb_is_ours = false;
bool skip_add = false;
bool defrag = false;
struct nf_conn *ct;
@@ -1012,9 +1024,18 @@ TC_INDIRECT_SCOPE int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
*/
nh_ofs = skb_network_offset(skb);
skb_pull_rcsum(skb, nh_ofs);
- err = tcf_ct_handle_fragments(net, skb, family, p->zone, &defrag);
- if (err)
+ err = tcf_ct_handle_fragments(net, skb, family, p->zone, &defrag,
+ &skb_is_ours);
+ if (err) {
+ /* The skb is still ours only when the header checks rejected
+ * it; returning TC_ACT_CONSUMED for such a packet would leak
+ * it, since no caller frees an skb it was told it no longer
+ * owns.
+ */
+ if (skb_is_ours)
+ goto drop;
goto out_frag;
+ }
err = nf_ct_skb_network_trim(skb, family);
if (err)
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index e949280eb800..565860cccba6 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -89,6 +89,11 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
p_parm = nla_data(tb[TCA_GACT_PROB]);
if (p_parm->ptype >= MAX_RAND)
return -EINVAL;
+ if (!tcf_action_valid(p_parm->paction)) {
+ NL_SET_ERR_MSG(extack,
+ "invalid fallback control action");
+ return -EINVAL;
+ }
if (TC_ACT_EXT_CMP(p_parm->paction, TC_ACT_GOTO_CHAIN)) {
NL_SET_ERR_MSG(extack,
"goto chain not allowed on fallback");
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index b16468a98c55..ce08f6840ef7 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -128,6 +128,12 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
if (tb[TCA_POLICE_RESULT]) {
tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]);
+ if (!tcf_action_valid(tcfp_result)) {
+ NL_SET_ERR_MSG(extack,
+ "invalid fallback control action");
+ err = -EINVAL;
+ goto failure;
+ }
if (TC_ACT_EXT_CMP(tcfp_result, TC_ACT_GOTO_CHAIN)) {
NL_SET_ERR_MSG(extack,
"goto chain not allowed on fallback");
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 001d8c4ebfed..6d19155becc8 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -374,7 +374,8 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
}
static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
- u32 gen_flags, const struct tcf_proto *tp)
+ u32 gen_flags, const struct tcf_proto *tp,
+ struct netlink_ext_ack *extack)
{
struct bpf_prog *fp;
char *name = NULL;
@@ -388,6 +389,19 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
if (IS_ERR(fp))
return PTR_ERR(fp);
+ if (bpf_prog_is_dev_bound(fp->aux)) {
+ struct tcf_block *block = tp->chain->block;
+ struct net_device *dev;
+
+ dev = block->q ? qdisc_dev(block->q) : NULL;
+ if (!dev || !bpf_offload_dev_match(fp, dev)) {
+ NL_SET_ERR_MSG(extack,
+ "Program is bound to a different device");
+ bpf_prog_put(fp);
+ return -EINVAL;
+ }
+ }
+
if (tb[TCA_BPF_NAME]) {
name = nla_memdup(tb[TCA_BPF_NAME], GFP_KERNEL);
if (!name) {
@@ -492,7 +506,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
prog->gen_flags = gen_flags;
ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
- cls_bpf_prog_from_efd(tb, prog, gen_flags, tp);
+ cls_bpf_prog_from_efd(tb, prog, gen_flags, tp, extack);
if (ret < 0)
goto errout_idr;
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index ac98b1c2144a..c297d7dbcf91 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -1346,6 +1346,9 @@ static void u32_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
{
struct tc_u_knode *n = fh;
+ if (TC_U32_KEY(n->handle) == 0)
+ return;
+
tc_cls_bind_class(classid, cl, q, &n->res, base);
}
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5b0ae616e1ff..5be0bed2685e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -543,6 +543,9 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
asoc->addip_last_asconf->transport == peer)
asoc->addip_last_asconf->transport = NULL;
+ if (asoc->new_transport == peer)
+ asoc->new_transport = NULL;
+
/* If we have something on the transmitted list, we have to
* save it off. The best place is the active path.
*/
@@ -1713,6 +1716,8 @@ void sctp_asconf_queue_teardown(struct sctp_association *asoc)
sctp_assoc_free_asconf_queue(asoc);
/* Free any cached ASCONF chunk. */
- if (asoc->addip_last_asconf)
+ if (asoc->addip_last_asconf) {
sctp_chunk_free(asoc->addip_last_asconf);
+ asoc->addip_last_asconf = NULL;
+ }
}
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index c901d373af80..cc4229ee116d 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -377,6 +377,81 @@ nomem:
return -ENOMEM;
}
+static bool sctp_auth_chunk_id_forbidden(__u8 chunk_id)
+{
+ switch (chunk_id) {
+ case SCTP_CID_INIT:
+ case SCTP_CID_INIT_ACK:
+ case SCTP_CID_SHUTDOWN_COMPLETE:
+ case SCTP_CID_AUTH:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Verify AUTH parameters copied from a state cookie before they are restored
+ * into an association. When cookie authentication is disabled these fields
+ * are peer-controlled, so they must satisfy the same constraints as locally
+ * generated AUTH parameters.
+ */
+bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep,
+ const struct sctp_cookie *cookie)
+{
+ const struct sctp_paramhdr *random;
+ const struct sctp_hmac_algo_param *hmacs;
+ const struct sctp_chunks_param *chunks;
+ u16 hmacs_len, chunks_len;
+ u16 n_hmacs, n_chunks, i;
+ bool has_sha1 = false;
+
+ if (sctp_sk(ep->base.sk)->cookie_auth_enable || !ep->auth_enable)
+ return true;
+
+ random = (const struct sctp_paramhdr *)cookie->auth_random;
+ if (random->type != SCTP_PARAM_RANDOM ||
+ ntohs(random->length) != sizeof(*random) + SCTP_AUTH_RANDOM_LENGTH)
+ return false;
+
+ hmacs = (const struct sctp_hmac_algo_param *)cookie->auth_hmacs;
+ hmacs_len = ntohs(hmacs->param_hdr.length);
+ if (hmacs->param_hdr.type != SCTP_PARAM_HMAC_ALGO ||
+ hmacs_len < sizeof(struct sctp_paramhdr) +
+ sizeof(hmacs->hmac_ids[0]) ||
+ hmacs_len > sizeof(cookie->auth_hmacs) ||
+ (hmacs_len - sizeof(struct sctp_paramhdr)) %
+ sizeof(hmacs->hmac_ids[0]))
+ return false;
+
+ n_hmacs = (hmacs_len - sizeof(struct sctp_paramhdr)) /
+ sizeof(hmacs->hmac_ids[0]);
+ for (i = 0; i < n_hmacs; i++) {
+ u16 hmac_id = ntohs(hmacs->hmac_ids[i]);
+
+ if (!sctp_hmac_supported(hmac_id))
+ return false;
+ if (hmac_id == SCTP_AUTH_HMAC_ID_SHA1)
+ has_sha1 = true;
+ }
+ if (!has_sha1)
+ return false;
+
+ chunks = (const struct sctp_chunks_param *)cookie->auth_chunks;
+ chunks_len = ntohs(chunks->param_hdr.length);
+ if (chunks->param_hdr.type != SCTP_PARAM_CHUNKS ||
+ chunks_len < sizeof(struct sctp_paramhdr) ||
+ chunks_len > sizeof(cookie->auth_chunks))
+ return false;
+
+ n_chunks = chunks_len - sizeof(struct sctp_paramhdr);
+ for (i = 0; i < n_chunks; i++) {
+ if (sctp_auth_chunk_id_forbidden(chunks->chunks[i]))
+ return false;
+ }
+
+ return true;
+}
+
/* Public interface to create the association shared key.
* See code above for the algorithm.
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index e25612e9d082..236e25abc7a4 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1852,6 +1852,9 @@ struct sctp_association *sctp_unpack_cookie(
/* Set up our peer's port number. */
retval->peer.port = ntohs(chunk->sctp_hdr->source);
+ if (!sctp_auth_verify_cookie_params(ep, bear_cookie))
+ goto malformed;
+
/* Populate the association from the cookie. */
memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 708fa07d5fff..3a8e16b29660 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -6145,8 +6145,12 @@ enum sctp_disposition sctp_sf_t4_timer_expire(
struct sctp_cmd_seq *commands)
{
struct sctp_chunk *chunk = asoc->addip_last_asconf;
- struct sctp_transport *transport = chunk->transport;
+ struct sctp_transport *transport;
+
+ if (!chunk)
+ return SCTP_DISPOSITION_CONSUME;
+ transport = chunk->transport;
SCTP_INC_STATS(net, SCTP_MIB_T4_RTO_EXPIREDS);
/* ADDIP 4.1 B1) Increment the error counters and perform path failure
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 8e4ef2630ae4..683a136e53ef 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1061,18 +1061,23 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,
static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)
{
- struct tipc_link_entry *le = &n->links[bearer_id];
struct tipc_media_addr *maddr = NULL;
- struct tipc_link *l = le->link;
int old_bearer_id = bearer_id;
+ struct tipc_link_entry *le;
struct sk_buff_head xmitq;
-
- if (!l)
- return;
+ struct tipc_link *l;
__skb_queue_head_init(&xmitq);
+ /* Synchronize the link lookup with bearer teardown. */
tipc_node_write_lock(n);
+ le = &n->links[bearer_id];
+ l = le->link;
+ if (!l) {
+ tipc_node_write_unlock_fast(n);
+ return;
+ }
+
if (!tipc_link_is_establishing(l)) {
__tipc_node_link_down(n, &bearer_id, &xmitq, &maddr);
} else {
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 62d46736e24b..d1ad31986cf2 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -2014,6 +2014,11 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
if (err < 0)
return err;
+ /* If crypto failed the connection is broken */
+ err = ctx->async_wait.err;
+ if (err)
+ goto splice_read_end;
+
if (!skb_queue_empty(&ctx->rx_list)) {
skb = __skb_dequeue(&ctx->rx_list);
} else {
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 0783555e2526..9fcaaf55cba5 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -186,6 +186,7 @@ static void unix_del_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
if (!vertex->out_degree) {
edge->predecessor->vertex = NULL;
list_move_tail(&vertex->entry, &fpl->vertices);
+ list_del(&vertex->scc_entry);
}
}
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 14b970f16020..ae90e9f513d1 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -735,6 +735,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8F06"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "Victus by HP Laptop 16-e1xxx"),
}
},
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index d43475a63ac2..e4d139108d72 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -2157,6 +2157,7 @@ config SND_SOC_TAC5XX2_SDW
tristate "Texas Instruments TAC5XX2 SoundWire Smart Amplifier"
depends on SOUNDWIRE
depends on SND_SOC_SDCA
+ select REGMAP_SOUNDWIRE_MBQ
help
This option enables support for Texas Instruments TAC5XX2 family
of SoundWire Smart Amplifiers. This includes TAC5572, TAC5672,
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 1e930b27c67a..42acb6cef77a 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -1899,7 +1899,7 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
/* initialization write */
- if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) {
+ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || !rt1320->first_hw_init) {
switch (rt1320->dev_id) {
case RT1320_DEV_ID:
if (rt1320->version_id < RT1320_VC)
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index e9819653b30d..e7e39671a576 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3496,6 +3496,10 @@ static int rt5645_probe(struct snd_soc_component *component)
if (!rt5645->eq_param)
return -ENOMEM;
+ /* no machine driver to call rt5645_set_jack_detect(), so detect here */
+ if (!rt5645->pdata.jd_mode && rt5645->gpiod_hp_det)
+ rt5645_irq(0, rt5645);
+
return 0;
}
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 209067e98e1f..95d875c44b91 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -1544,8 +1544,8 @@ static ssize_t acoustic_ctl_write(struct file *file,
if (src[0] > max_pkg_len && src[0] != count) {
dev_err(priv->dev, "pkg(%u), max(%u), count(%u) mismatch.\n",
src[0], max_pkg_len, (unsigned int)count);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}
switch (src[1]) {
@@ -1559,14 +1559,14 @@ static ssize_t acoustic_ctl_write(struct file *file,
break;
default:
dev_err(priv->dev, "%s Wrong code %02x.\n", __func__, src[1]);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}
if (len < 1) {
dev_err(priv->dev, "pkg fmt invalid %02x.\n", len);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}
for (j = 0; j < priv->ndev; j++)
@@ -1576,8 +1576,8 @@ static ssize_t acoustic_ctl_write(struct file *file,
}
if (j >= priv->ndev) {
dev_err(priv->dev, "no such device 0x%02x.\n", src[2]);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}
reg = TASDEVICE_REG(src[3], src[4], src[5]);
@@ -1608,7 +1608,7 @@ static ssize_t acoustic_ctl_write(struct file *file,
dev_err(priv->dev, "i2c communication error.\n");
else
ret = count;
-exit:
+
kfree(src);
return ret;
}
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index e9ee752d5ec3..9b016136c639 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -847,6 +847,16 @@ static const struct platform_device_id board_ids[] = {
SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
SOF_ES8336_JD_INVERTED),
},
+ {
+ .name = "nvl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 649378957b20..7899f7ffd99b 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -915,6 +915,13 @@ static const struct platform_device_id board_ids[] = {
/* SSP 0 and SSP 2 are used for HDMI IN */
SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
+ {
+ .name = "nvl_rt5682_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_SSP_PORT_CODEC(1) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c
index 729c0cd7c19c..b80d24966cbd 100644
--- a/sound/soc/intel/boards/sof_ssp_amp.c
+++ b/sound/soc/intel/boards/sof_ssp_amp.c
@@ -222,6 +222,12 @@ static const struct platform_device_id board_ids[] = {
/* SSP 0 and SSP 2 are used for HDMI IN */
SOF_HDMI_PLAYBACK_PRESENT),
},
+ {
+ .name = "nvl_lt6911_hdmi_ssp",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_PLAYBACK_PRESENT),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
index a7f4097d426c..8f6e987c791e 100644
--- a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
@@ -16,6 +16,11 @@ static const struct snd_soc_acpi_codecs nvl_essx_83x6 = {
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
+static const struct snd_soc_acpi_codecs nvl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
+};
+
static const struct snd_soc_acpi_codecs nvl_rt5682_rt5682s_hp = {
.num_codecs = 2,
.codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
@@ -24,6 +29,13 @@ static const struct snd_soc_acpi_codecs nvl_rt5682_rt5682s_hp = {
struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = {
{
.comp_ids = &nvl_essx_83x6,
+ .drv_name = "nvl_es83x6_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &nvl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-nvl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &nvl_essx_83x6,
.drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-nvl-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
@@ -32,11 +44,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = {
},
{
.comp_ids = &nvl_rt5682_rt5682s_hp,
+ .drv_name = "nvl_rt5682_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &nvl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-nvl-rt5682-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &nvl_rt5682_rt5682s_hp,
.drv_name = "sof_rt5682",
.sof_tplg_filename = "sof-nvl-rt5682", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB,
},
+ /* place amp/hdmi-in only boards in the end of table */
+ {
+ .id = "INTC10B0",
+ .drv_name = "nvl_lt6911_hdmi_ssp",
+ .sof_tplg_filename = "sof-nvl-hdmi-ssp02.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_machines);
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 8f7a76758535..f15336197ed3 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -281,8 +281,7 @@ static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg)
{
u32 val;
void __iomem *reg;
- struct device *dev = arg;
- struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
+ struct xlnx_pcm_drv_data *adata = arg;
reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS;
val = readl(reg);
@@ -300,8 +299,7 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg)
{
u32 val;
void __iomem *reg;
- struct device *dev = arg;
- struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
+ struct xlnx_pcm_drv_data *adata = arg;
reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS;
val = readl(reg);
@@ -637,7 +635,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
}
ret = devm_request_irq(dev, aud_drv_data->mm2s_irq,
xlnx_mm2s_irq_handler, 0,
- "xlnx_formatter_pcm_mm2s_irq", dev);
+ "xlnx_formatter_pcm_mm2s_irq", aud_drv_data);
if (ret) {
dev_err(dev, "xlnx audio mm2s irq request failed\n");
goto clk_err;
@@ -664,7 +662,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, aud_drv_data->s2mm_irq,
xlnx_s2mm_irq_handler, 0,
"xlnx_formatter_pcm_s2mm_irq",
- dev);
+ aud_drv_data);
if (ret) {
dev_err(dev, "xlnx audio s2mm irq request failed\n");
goto clk_err;
diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c
index 83980fb83ac8..1dc78f536ef9 100644
--- a/sound/usb/midi2.c
+++ b/sound/usb/midi2.c
@@ -677,6 +677,14 @@ static int parse_midi_2_0_endpoints(struct snd_usb_midi2_interface *umidi)
return 0;
}
+static void free_ump_private_data(struct snd_ump_endpoint *ump)
+{
+ struct snd_usb_midi2_ump *rmidi = ump->private_data;
+
+ if (rmidi)
+ rmidi->ump = NULL;
+}
+
static void free_all_midi2_umps(struct snd_usb_midi2_interface *umidi)
{
struct snd_usb_midi2_ump *rmidi;
@@ -727,6 +735,7 @@ static int create_midi2_ump(struct snd_usb_midi2_interface *umidi,
ump->private_data = rmidi;
ump->ops = &snd_usb_midi_v2_ump_ops;
+ ump->private_free = free_ump_private_data;
rmidi->eps[STR_IN] = ep_in;
rmidi->eps[STR_OUT] = ep_out;
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 90ca39dbed18..4d2957e62fbd 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2367,6 +2367,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x1038, 0x1294, /* SteelSeries Arctis Pro Wireless */
QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
+ DEVICE_FLG(0x1038, 0x2232, /* SteelSeries Arctis Nova 5 */
+ QUIRK_FLAG_MIXER_GET_CUR_BROKEN),
DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x12d1, 0x3a07, /* HUAWEI USB-C HEADSET */
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 8d4db2241cc2..b622052ec3e9 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -42,6 +42,7 @@ TARGETS += filesystems/fuse
TARGETS += filesystems/move_mount
TARGETS += filesystems/empty_mntns
TARGETS += filesystems/fsmount_ns
+TARGETS += filesystems/fscontext_ns
TARGETS += firmware
TARGETS += fpu
TARGETS += ftrace
diff --git a/tools/testing/selftests/filesystems/fscontext_ns/Makefile b/tools/testing/selftests/filesystems/fscontext_ns/Makefile
new file mode 100644
index 000000000000..7e3506294757
--- /dev/null
+++ b/tools/testing/selftests/filesystems/fscontext_ns/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_GEN_PROGS := fscontext_ns_test
+
+CFLAGS += -Wall -O0 -g $(KHDR_INCLUDES) $(TOOLS_INCLUDES)
+LDLIBS := -lcap
+
+include ../../lib.mk
+
+$(OUTPUT)/fscontext_ns_test: fscontext_ns_test.c ../utils.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
diff --git a/tools/testing/selftests/filesystems/fscontext_ns/fscontext_ns_test.c b/tools/testing/selftests/filesystems/fscontext_ns/fscontext_ns_test.c
new file mode 100644
index 000000000000..0f30a3e6e197
--- /dev/null
+++ b/tools/testing/selftests/filesystems/fscontext_ns/fscontext_ns_test.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Christian Brauner <brauner@kernel.org>
+ *
+ * Test that completing a filesystem context from another user namespace
+ * doesn't warn.
+ *
+ * fsopen() records the caller's user namespace in fc->user_ns and hands
+ * back an ordinary file descriptor. The task that issues
+ * FSCONFIG_CMD_CREATE need not be the one that created the context: the fd
+ * is inherited across fork() and exec() and it can be passed over a unix
+ * socket. vfs_cmd_create() authorizes the create with mount_capable(),
+ * which for FS_USERNS_MOUNT checks ns_capable(fc->user_ns, CAP_SYS_ADMIN),
+ * and that succeeds for a task holding CAP_SYS_ADMIN in an ancestor of
+ * fc->user_ns.
+ *
+ * binfmt_misc and overlayfs used to WARN_ON() that mismatch, which let an
+ * unprivileged user taint the kernel, flood the log and panic a kernel
+ * booted with panic_on_warn. The mount must still be refused, but it must
+ * not warn.
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../wrappers.h"
+#include "../utils.h"
+#include "../../kselftest_harness.h"
+
+#ifndef FSCONFIG_CMD_CREATE
+#define FSCONFIG_CMD_CREATE 6
+#endif
+
+/* TAINT_WARN, i.e. bit 9 of /proc/sys/kernel/tainted. */
+#define TAINT_WARN_BIT 9
+
+static bool taint_warn_set(void)
+{
+ unsigned long taint = 0;
+ FILE *f;
+
+ f = fopen("/proc/sys/kernel/tainted", "r");
+ if (!f)
+ return false;
+ if (fscanf(f, "%lu", &taint) != 1)
+ taint = 0;
+ fclose(f);
+
+ return taint & (1UL << TAINT_WARN_BIT);
+}
+
+static int send_fd(int sock, int fd)
+{
+ char cmsgbuf[CMSG_SPACE(sizeof(int))] = {};
+ char b[1] = { 'x' };
+ struct iovec iov = { .iov_base = b, .iov_len = sizeof(b) };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cmsgbuf,
+ .msg_controllen = sizeof(cmsgbuf),
+ };
+ struct cmsghdr *cmsg;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+ return sendmsg(sock, &msg, 0) < 0 ? -1 : 0;
+}
+
+static int recv_fd(int sock)
+{
+ char cmsgbuf[CMSG_SPACE(sizeof(int))] = {};
+ char b[1];
+ struct iovec iov = { .iov_base = b, .iov_len = sizeof(b) };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cmsgbuf,
+ .msg_controllen = sizeof(cmsgbuf),
+ };
+ struct cmsghdr *cmsg;
+ int fd = -1;
+
+ if (recvmsg(sock, &msg, 0) <= 0)
+ return -1;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS)
+ return -1;
+ memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
+
+ return fd;
+}
+
+/*
+ * Create a context for @fsname in a child and complete it here. With @nest
+ * the child first creates its own user namespace, so that the context is
+ * created in a descendant of the namespace completing it. The child needs a
+ * mount namespace of its own as well: fsopen() gates on may_mount(), which
+ * asks for CAP_SYS_ADMIN in the user namespace owning the caller's mount
+ * namespace.
+ *
+ * Returns the result of FSCONFIG_CMD_CREATE with errno set, or -ENODATA if
+ * the child could not create the context at all.
+ */
+static int create_from_child(const char *fsname, bool nest)
+{
+ int sock[2], fd, ret, status;
+ pid_t pid;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock))
+ return -ENODATA;
+
+ pid = fork();
+ if (pid < 0) {
+ close(sock[0]);
+ close(sock[1]);
+ return -ENODATA;
+ }
+
+ if (pid == 0) {
+ close(sock[0]);
+
+ if (nest && unshare(CLONE_NEWUSER | CLONE_NEWNS))
+ _exit(1);
+
+ fd = sys_fsopen(fsname, 0);
+ if (fd < 0)
+ _exit(1);
+ if (send_fd(sock[1], fd))
+ _exit(1);
+ _exit(0);
+ }
+
+ close(sock[1]);
+ fd = recv_fd(sock[0]);
+ close(sock[0]);
+ wait_for_pid(pid);
+ waitpid(pid, &status, WNOHANG);
+
+ if (fd < 0)
+ return -ENODATA;
+
+ errno = 0;
+ ret = sys_fsconfig(fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+ status = errno;
+ close(fd);
+ errno = status;
+
+ return ret;
+}
+
+FIXTURE(fscontext_ns) {
+ bool warn_before;
+};
+
+FIXTURE_SETUP(fscontext_ns)
+{
+ self->warn_before = taint_warn_set();
+
+ if (setup_userns() != 0)
+ SKIP(return, "setup_userns failed");
+}
+
+FIXTURE_TEARDOWN(fscontext_ns)
+{
+}
+
+/*
+ * The condition the kernel used to WARN about. It has to be refused, and it
+ * has to be refused quietly: an unprivileged task reaches this.
+ */
+FIXTURE_VARIANT(fscontext_ns) {
+ const char *fsname;
+ int expected_errno;
+};
+
+FIXTURE_VARIANT_ADD(fscontext_ns, binfmt_misc) {
+ .fsname = "binfmt_misc",
+ .expected_errno = EINVAL,
+};
+
+FIXTURE_VARIANT_ADD(fscontext_ns, overlay) {
+ .fsname = "overlay",
+ .expected_errno = EIO,
+};
+
+TEST_F(fscontext_ns, create_from_descendant_userns)
+{
+ int ret;
+
+ ret = create_from_child(variant->fsname, true);
+ if (ret == -ENODATA)
+ SKIP(return, "%s unavailable", variant->fsname);
+
+ ASSERT_EQ(-1, ret);
+ ASSERT_EQ(variant->expected_errno, errno);
+
+ /*
+ * Only meaningful if nothing had warned before us. Note that an
+ * unrelated warning racing this test would look like a failure.
+ */
+ if (self->warn_before)
+ TH_LOG("TAINT_WARN already set, not checking for a new warning");
+ else
+ ASSERT_FALSE(taint_warn_set());
+}
+
+/*
+ * The same handover within one user namespace is a supported thing to do and
+ * has to keep working. binfmt_misc takes no options, so the create succeeds
+ * outright and this also shows the test really drives the create path.
+ */
+TEST(create_from_same_userns)
+{
+ int ret;
+
+ if (setup_userns() != 0)
+ SKIP(return, "setup_userns failed");
+
+ ret = create_from_child("binfmt_misc", false);
+ if (ret == -ENODATA)
+ SKIP(return, "binfmt_misc unavailable");
+
+ ASSERT_EQ(0, ret);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc
index f2048c244526..19430bd5864c 100644
--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc
@@ -12,9 +12,32 @@ echo 0 > events/enable
echo > dynamic_events
REALBIN=`readlink -f /bin/sh`
-ENTRYPOINT=`readelf -h ${REALBIN} | grep Entry | sed -e 's/[^0]*//'`
-echo "p:myevent ${REALBIN}:${ENTRYPOINT}" >> uprobe_events
+# Get the entry point virtual address from ELF header
+ENTRY=`readelf -hW ${REALBIN} | grep "Entry point" | awk '{print $NF}'`
+
+# Convert virtual address to file offset: find the LOAD segment containing
+# the entry point, then compute file_offset = e_entry - p_vaddr + p_offset.
+# For PIE binaries this is a no-op (vaddr == file offset), but for non-PIE
+# executables the virtual address is much larger than the file size and
+# must be converted, otherwise uprobe_register() rejects it with -EINVAL.
+ENTRY_DEC=$(printf '%d' "$ENTRY")
+OFFSET=$ENTRY
+while IFS= read -r line; do
+ set -- $line
+ [ "$1" = "LOAD" ] || continue
+ VA_DEC=$(printf '%d' "$3")
+ OFF_DEC=$(printf '%d' "$2")
+ FSZ_DEC=$(printf '%d' "$5")
+ if [ "$ENTRY_DEC" -ge "$VA_DEC" ] && [ "$ENTRY_DEC" -lt "$((VA_DEC + FSZ_DEC))" ]; then
+ OFFSET=$(printf '0x%x' "$((ENTRY_DEC - VA_DEC + OFF_DEC))")
+ break
+ fi
+done << EOF
+$(readelf -lW ${REALBIN} | grep LOAD)
+EOF
+
+echo "p:myevent ${REALBIN}:${OFFSET}" >> uprobe_events
grep -q myevent uprobe_events
test -d events/uprobes/myevent
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index a0e72e402748..9d3cd4fff062 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -24,6 +24,7 @@
#include "kselftest_harness.h"
#define TLS_PAYLOAD_MAX_LEN 16384
+#define TLS_HDR_LEN 5
#define SOL_TLS 282
static int fips_enabled;
@@ -2732,28 +2733,83 @@ TEST_F(tls_err, bad_rec)
EXPECT_EQ(errno, EAGAIN);
}
+/* cfd carries a byte stream, so one recv() can return part of a
+ * record. Take the fragment length from the record header and wait
+ * for the remainder.
+ */
+static void tls_send_bad_auth(struct __test_metadata *_metadata,
+ int fd, int cfd, int fd2)
+{
+ char buf[128];
+ int len;
+
+ memrnd(buf, sizeof(buf) / 2);
+ ASSERT_EQ(send(fd, buf, sizeof(buf) / 2, 0), sizeof(buf) / 2);
+
+ ASSERT_EQ(recv(cfd, buf, TLS_HDR_LEN, MSG_WAITALL), TLS_HDR_LEN);
+
+ len = ((unsigned char)buf[3] << 8) | (unsigned char)buf[4];
+ ASSERT_GT(len, 0);
+ ASSERT_LE(len, (int)sizeof(buf) - TLS_HDR_LEN);
+
+ ASSERT_EQ(recv(cfd, buf + TLS_HDR_LEN, len, MSG_WAITALL), len);
+
+ buf[TLS_HDR_LEN + len - 1]++;
+
+ ASSERT_EQ(send(fd2, buf, TLS_HDR_LEN + len, 0), TLS_HDR_LEN + len);
+}
+
TEST_F(tls_err, bad_auth)
{
char buf[128];
- int n;
if (self->notls)
SKIP(return, "no TLS support");
- memrnd(buf, sizeof(buf) / 2);
- EXPECT_EQ(send(self->fd, buf, sizeof(buf) / 2, 0), sizeof(buf) / 2);
- n = recv(self->cfd, buf, sizeof(buf), 0);
- EXPECT_GT(n, sizeof(buf) / 2);
+ tls_send_bad_auth(_metadata, self->fd, self->cfd, self->fd2);
- buf[n - 1]++;
-
- EXPECT_EQ(send(self->fd2, buf, n, 0), n);
EXPECT_EQ(recv(self->cfd2, buf, sizeof(buf), 0), -1);
EXPECT_EQ(errno, EBADMSG);
EXPECT_EQ(recv(self->cfd2, buf, sizeof(buf), 0), -1);
EXPECT_EQ(errno, EBADMSG);
}
+/* A record that did not authenticate breaks the connection for every
+ * reader, splice included.
+ *
+ * The two decrypt paths reach that result differently. A synchronous
+ * decrypt leaves the record parsed, so the splice re-runs the decrypt
+ * and fails on the record itself; the ctx->async_wait.err check in
+ * tls_sw_splice_read() is not what stops it. Only an asynchronous
+ * decrypt, which needs a TLS 1.2 socket and an AEAD advertising
+ * CRYPTO_ALG_ASYNC, consumes the record before the failure is
+ * recorded, leaving that check the sole reason the splice fails.
+ */
+TEST_F(tls_err, bad_auth_splice)
+{
+ char buf[128];
+ ssize_t ret;
+ int p[2];
+
+ if (self->notls)
+ SKIP(return, "no TLS support");
+
+ tls_send_bad_auth(_metadata, self->fd, self->cfd, self->fd2);
+
+ EXPECT_EQ(recv(self->cfd2, buf, sizeof(buf), 0), -1);
+ EXPECT_EQ(errno, EBADMSG);
+
+ ASSERT_GE(pipe(p), 0);
+
+ ret = splice(self->cfd2, NULL, p[1], NULL, sizeof(buf),
+ SPLICE_F_NONBLOCK);
+ EXPECT_EQ(ret, -1);
+ EXPECT_EQ(errno, EBADMSG);
+
+ close(p[0]);
+ close(p[1]);
+}
+
TEST_F(tls_err, bad_in_large_read)
{
char txt[3][64];
@@ -3009,7 +3065,6 @@ static size_t parse_tls_records(struct __test_metadata *_metadata,
{
const __u8 *rec = rx_buf;
size_t total_plaintext_rx = 0;
- const __u8 rec_header_len = 5;
while (rec < rx_buf + rx_len) {
__u16 record_payload_len;
@@ -3029,7 +3084,7 @@ static size_t parse_tls_records(struct __test_metadata *_metadata,
/* Plaintext must not exceed the specified limit */
ASSERT_LE(plaintext_len, max_payload_len);
- rec += rec_header_len + record_payload_len;
+ rec += TLS_HDR_LEN + record_payload_len;
}
return total_plaintext_rx;
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json
index da65f838bd52..8ab48def89b6 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json
@@ -702,5 +702,45 @@
"$TC qdisc del dev $DUMMY clsact",
"$TC qdisc del dev $DUMMY root handle 1:"
]
+ },
+ {
+ "id": "c7a3",
+ "name": "Verify act_ct drops a packet whose header checks fail",
+ "category": [
+ "actions",
+ "ct",
+ "scapy"
+ ],
+ "plugins": {
+ "requires": [
+ "nsPlugin",
+ "scapyPlugin"
+ ]
+ },
+ "setup": [
+ [
+ "$TC qdisc del dev $DEV1 clsact",
+ 0,
+ 1,
+ 2,
+ 255
+ ],
+ "$TC qdisc add dev $DEV1 clsact"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV1 ingress protocol all prio 1 matchall action ct",
+ "scapy": [
+ {
+ "iface": "$DEV0",
+ "count": 10,
+ "packet": "Ether(type=0x86dd)/IPv6(nh=0, plen=0, src='::1', dst='::2')"
+ }
+ ],
+ "expExitCode": "0",
+ "verifyCmd": "$TC -s qdisc show dev $DEV1 clsact",
+ "matchPattern": "dropped 10",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DEV1 clsact"
+ ]
}
]