diff options
author | Mike Pagano <mpagano@gentoo.org> | 2023-09-13 07:04:11 -0400 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2023-09-13 07:04:11 -0400 |
commit | fcec9389a083f96ad3b1a91221c1151a42c9292b (patch) | |
tree | b5392ccdfa03f23c4073845d740bc7080de9ef24 | |
parent | Linux patch 6.4.15 (diff) | |
download | linux-patches-fcec9389a083f96ad3b1a91221c1151a42c9292b.tar.gz linux-patches-fcec9389a083f96ad3b1a91221c1151a42c9292b.tar.bz2 linux-patches-fcec9389a083f96ad3b1a91221c1151a42c9292b.zip |
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1015_linux-6.4.16.patch | 37960 |
2 files changed, 37964 insertions, 0 deletions
diff --git a/0000_README b/0000_README index 5a91174a..087660bb 100644 --- a/0000_README +++ b/0000_README @@ -103,6 +103,10 @@ Patch: 1014_linux-6.4.15.patch From: https://www.kernel.org Desc: Linux 6.4.15 +Patch: 1015_linux-6.4.16.patch +From: https://www.kernel.org +Desc: Linux 6.4.16 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1015_linux-6.4.16.patch b/1015_linux-6.4.16.patch new file mode 100644 index 00000000..d8f25ac8 --- /dev/null +++ b/1015_linux-6.4.16.patch @@ -0,0 +1,37960 @@ +diff --git a/Documentation/ABI/testing/sysfs-bus-fsi-devices-sbefifo b/Documentation/ABI/testing/sysfs-bus-fsi-devices-sbefifo +index 531fe9d6b40aa..c7393b4dd2d88 100644 +--- a/Documentation/ABI/testing/sysfs-bus-fsi-devices-sbefifo ++++ b/Documentation/ABI/testing/sysfs-bus-fsi-devices-sbefifo +@@ -5,6 +5,6 @@ Description: + Indicates whether or not this SBE device has experienced a + timeout; i.e. the SBE did not respond within the time allotted + by the driver. A value of 1 indicates that a timeout has +- ocurred and no transfers have completed since the timeout. A +- value of 0 indicates that no timeout has ocurred, or if one +- has, more recent transfers have completed successful. ++ occurred and no transfers have completed since the timeout. A ++ value of 0 indicates that no timeout has occurred, or if one ++ has, more recent transfers have completed successfully. +diff --git a/Documentation/ABI/testing/sysfs-driver-chromeos-acpi b/Documentation/ABI/testing/sysfs-driver-chromeos-acpi +index c308926e1568a..7c8e129fc1005 100644 +--- a/Documentation/ABI/testing/sysfs-driver-chromeos-acpi ++++ b/Documentation/ABI/testing/sysfs-driver-chromeos-acpi +@@ -134,4 +134,4 @@ KernelVersion: 5.19 + Description: + Returns the verified boot data block shared between the + firmware verification step and the kernel verification step +- (binary). ++ (hex dump). +diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs +index 8140fc98f5aee..ad3d76d37c8ba 100644 +--- a/Documentation/ABI/testing/sysfs-fs-f2fs ++++ b/Documentation/ABI/testing/sysfs-fs-f2fs +@@ -54,9 +54,9 @@ Description: Controls the in-place-update policy. + 0x00 DISABLE disable IPU(=default option in LFS mode) + 0x01 FORCE all the time + 0x02 SSR if SSR mode is activated +- 0x04 UTIL if FS utilization is over threashold ++ 0x04 UTIL if FS utilization is over threshold + 0x08 SSR_UTIL if SSR mode is activated and FS utilization is over +- threashold ++ threshold + 0x10 FSYNC activated in fsync path only for high performance + flash storages. IPU will be triggered only if the + # of dirty pages over min_fsync_blocks. +@@ -117,7 +117,7 @@ Date: December 2021 + Contact: "Konstantin Vyshetsky" <vkon@google.com> + Description: Controls the number of discards a thread will issue at a time. + Higher number will allow the discard thread to finish its work +- faster, at the cost of higher latency for incomming I/O. ++ faster, at the cost of higher latency for incoming I/O. + + What: /sys/fs/f2fs/<disk>/min_discard_issue_time + Date: December 2021 +@@ -334,7 +334,7 @@ Description: This indicates how many GC can be failed for the pinned + state. 2048 trials is set by default. + + What: /sys/fs/f2fs/<disk>/extension_list +-Date: Feburary 2018 ++Date: February 2018 + Contact: "Chao Yu" <yuchao0@huawei.com> + Description: Used to control configure extension list: + - Query: cat /sys/fs/f2fs/<disk>/extension_list +diff --git a/Documentation/devicetree/bindings/clock/qcom,qdu1000-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,qdu1000-gcc.yaml +index 767a9d03aa327..d712b1a87e25f 100644 +--- a/Documentation/devicetree/bindings/clock/qcom,qdu1000-gcc.yaml ++++ b/Documentation/devicetree/bindings/clock/qcom,qdu1000-gcc.yaml +@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# + title: Qualcomm Global Clock & Reset Controller for QDU1000 and QRU1000 + + maintainers: +- - Melody Olvera <quic_molvera@quicinc.com> ++ - Taniya Das <quic_tdas@quicinc.com> ++ - Imran Shaik <quic_imrashai@quicinc.com> + + description: | + Qualcomm global clock control module which supports the clocks, resets and +diff --git a/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml b/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml +index 1289605456408..55800fb0221d0 100644 +--- a/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml ++++ b/Documentation/devicetree/bindings/extcon/maxim,max77843.yaml +@@ -23,6 +23,7 @@ properties: + + connector: + $ref: /schemas/connector/usb-connector.yaml# ++ unevaluatedProperties: false + + ports: + $ref: /schemas/graph.yaml#/properties/ports +diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpm-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpm-regulator.yaml +index 8a08698e34846..b4eb4001eb3d2 100644 +--- a/Documentation/devicetree/bindings/regulator/qcom,rpm-regulator.yaml ++++ b/Documentation/devicetree/bindings/regulator/qcom,rpm-regulator.yaml +@@ -49,7 +49,7 @@ patternProperties: + ".*-supply$": + description: Input supply phandle(s) for this node + +- "^((s|l|lvs)[0-9]*)|(s[1-2][a-b])|(ncp)|(mvs)|(usb-switch)|(hdmi-switch)$": ++ "^((s|l|lvs)[0-9]*|s[1-2][a-b]|ncp|mvs|usb-switch|hdmi-switch)$": + description: List of regulators and its properties + $ref: regulator.yaml# + unevaluatedProperties: false +diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst +index 6fa3a62795016..022198c513506 100644 +--- a/Documentation/scsi/scsi_mid_low_api.rst ++++ b/Documentation/scsi/scsi_mid_low_api.rst +@@ -1190,11 +1190,11 @@ Members of interest: + - pointer to scsi_device object that this command is + associated with. + resid +- - an LLD should set this signed integer to the requested ++ - an LLD should set this unsigned integer to the requested + transfer length (i.e. 'request_bufflen') less the number + of bytes that are actually transferred. 'resid' is + preset to 0 so an LLD can ignore it if it cannot detect +- underruns (overruns should be rare). If possible an LLD ++ underruns (overruns should not be reported). An LLD + should set 'resid' prior to invoking 'done'. The most + interesting case is data transfers from a SCSI target + device (e.g. READs) that underrun. +diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst +index 2d6e3bbdd0404..72677a280cd64 100644 +--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst ++++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst +@@ -58,6 +58,9 @@ the subdevice exposes, drivers return the ENOSPC error code and adjust the + value of the ``num_routes`` field. Application should then reserve enough memory + for all the route entries and call ``VIDIOC_SUBDEV_G_ROUTING`` again. + ++On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the ++``num_routes`` field to reflect the actual number of routes returned. ++ + .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| + + .. c:type:: v4l2_subdev_routing +@@ -138,9 +141,7 @@ ENOSPC + + EINVAL + The sink or source pad identifiers reference a non-existing pad, or reference +- pads of different types (ie. the sink_pad identifiers refers to a source pad) +- or the sink or source stream identifiers reference a non-existing stream on +- the sink or source pad. ++ pads of different types (ie. the sink_pad identifiers refers to a source pad). + + E2BIG + The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is +diff --git a/Makefile b/Makefile +index 212d1c7e4a1a3..34ea74d74476f 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 4 +-SUBLEVEL = 15 ++SUBLEVEL = 16 + EXTRAVERSION = + NAME = Hurr durr I'ma ninja sloth + +@@ -1289,7 +1289,7 @@ prepare0: archprepare + # All the preparing.. + prepare: prepare0 + ifdef CONFIG_RUST +- $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh -v ++ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh + $(Q)$(MAKE) $(build)=rust + endif + +@@ -1825,7 +1825,7 @@ $(DOC_TARGETS): + # "Is Rust available?" target + PHONY += rustavailable + rustavailable: +- $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh -v && echo "Rust is available!" ++ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh && echo "Rust is available!" + + # Documentation target + # +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 59829fc903152..3cf1bf724e8ed 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -335,6 +335,7 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += \ + kirkwood-iconnect.dtb \ + kirkwood-iomega_ix2_200.dtb \ + kirkwood-is2.dtb \ ++ kirkwood-km_fixedeth.dtb \ + kirkwood-km_kirkwood.dtb \ + kirkwood-l-50.dtb \ + kirkwood-laplug.dtb \ +@@ -880,7 +881,10 @@ dtb-$(CONFIG_ARCH_OMAP3) += \ + am3517-craneboard.dtb \ + am3517-evm.dtb \ + am3517_mt_ventoux.dtb \ ++ logicpd-torpedo-35xx-devkit.dtb \ + logicpd-torpedo-37xx-devkit.dtb \ ++ logicpd-torpedo-37xx-devkit-28.dtb \ ++ logicpd-som-lv-35xx-devkit.dtb \ + logicpd-som-lv-37xx-devkit.dtb \ + omap3430-sdp.dtb \ + omap3-beagle.dtb \ +@@ -1561,6 +1565,8 @@ dtb-$(CONFIG_MACH_ARMADA_38X) += \ + armada-388-helios4.dtb \ + armada-388-rd.dtb + dtb-$(CONFIG_MACH_ARMADA_39X) += \ ++ armada-390-db.dtb \ ++ armada-395-gp.dtb \ + armada-398-db.dtb + dtb-$(CONFIG_MACH_ARMADA_XP) += \ + armada-xp-axpwifiap.dtb \ +@@ -1590,6 +1596,7 @@ dtb-$(CONFIG_MACH_DOVE) += \ + dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt2701-evb.dtb \ + mt6580-evbp1.dtb \ ++ mt6582-prestigio-pmt5008-3g.dtb \ + mt6589-aquaris5.dtb \ + mt6589-fairphone-fp1.dtb \ + mt6592-evb.dtb \ +@@ -1645,6 +1652,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ + aspeed-bmc-intel-s2600wf.dtb \ + aspeed-bmc-inspur-fp5280g2.dtb \ + aspeed-bmc-inspur-nf5280m6.dtb \ ++ aspeed-bmc-inspur-on5263m5.dtb \ + aspeed-bmc-lenovo-hr630.dtb \ + aspeed-bmc-lenovo-hr855xg2.dtb \ + aspeed-bmc-microsoft-olympus.dtb \ +diff --git a/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts b/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts +index 0734aa249b8e0..0f6d7fe30068f 100644 +--- a/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts ++++ b/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts +@@ -26,7 +26,6 @@ + led-wlan { + label = "bcm53xx:blue:wlan"; + gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>; +- linux,default-trigger = "default-off"; + }; + + led-system { +@@ -46,3 +45,16 @@ + }; + }; + }; ++ ++&gmac0 { ++ phy-mode = "rgmii"; ++ phy-handle = <&bcm54210e>; ++ ++ mdio { ++ /delete-node/ switch@1e; ++ ++ bcm54210e: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts b/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts +index e6fb6cbe69633..4e0ef0af726f5 100644 +--- a/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts ++++ b/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts +@@ -26,7 +26,6 @@ + led-5ghz { + label = "bcm53xx:blue:5ghz"; + gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "default-off"; + }; + + led-system { +@@ -42,7 +41,6 @@ + led-2ghz { + label = "bcm53xx:blue:2ghz"; + gpios = <&pcie0_chipcommon 3 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "default-off"; + }; + }; + +@@ -83,3 +81,16 @@ + }; + }; + }; ++ ++&gmac0 { ++ phy-mode = "rgmii"; ++ phy-handle = <&bcm54210e>; ++ ++ mdio { ++ /delete-node/ switch@1e; ++ ++ bcm54210e: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/bcm47189-tenda-ac9.dts b/arch/arm/boot/dts/bcm47189-tenda-ac9.dts +index dab2e5f63a727..06b1a582809ca 100644 +--- a/arch/arm/boot/dts/bcm47189-tenda-ac9.dts ++++ b/arch/arm/boot/dts/bcm47189-tenda-ac9.dts +@@ -135,8 +135,8 @@ + label = "lan4"; + }; + +- port@5 { +- reg = <5>; ++ port@8 { ++ reg = <8>; + label = "cpu"; + ethernet = <&gmac0>; + }; +diff --git a/arch/arm/boot/dts/bcm53573.dtsi b/arch/arm/boot/dts/bcm53573.dtsi +index 3f03a381db0f2..eed1a6147f0bf 100644 +--- a/arch/arm/boot/dts/bcm53573.dtsi ++++ b/arch/arm/boot/dts/bcm53573.dtsi +@@ -127,6 +127,9 @@ + + pcie0: pcie@2000 { + reg = <0x00002000 0x1000>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; + }; + + usb2: usb2@4000 { +@@ -156,8 +159,6 @@ + }; + + ohci: usb@d000 { +- #usb-cells = <0>; +- + compatible = "generic-ohci"; + reg = <0xd000 0x1000>; + interrupt-parent = <&gic>; +diff --git a/arch/arm/boot/dts/bcm947189acdbmr.dts b/arch/arm/boot/dts/bcm947189acdbmr.dts +index 3709baa2376f5..0b8727ae6f16d 100644 +--- a/arch/arm/boot/dts/bcm947189acdbmr.dts ++++ b/arch/arm/boot/dts/bcm947189acdbmr.dts +@@ -60,9 +60,9 @@ + spi { + compatible = "spi-gpio"; + num-chipselects = <1>; +- gpio-sck = <&chipcommon 21 0>; +- gpio-miso = <&chipcommon 22 0>; +- gpio-mosi = <&chipcommon 23 0>; ++ sck-gpios = <&chipcommon 21 0>; ++ miso-gpios = <&chipcommon 22 0>; ++ mosi-gpios = <&chipcommon 23 0>; + cs-gpios = <&chipcommon 24 0>; + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm/boot/dts/integratorap.dts b/arch/arm/boot/dts/integratorap.dts +index 5b52d75bc6bed..d9927d3181dce 100644 +--- a/arch/arm/boot/dts/integratorap.dts ++++ b/arch/arm/boot/dts/integratorap.dts +@@ -158,7 +158,7 @@ + valid-mask = <0x003fffff>; + }; + +- pci: pciv3@62000000 { ++ pci: pci@62000000 { + compatible = "arm,integrator-ap-pci", "v3,v360epc-pci"; + device_type = "pci"; + #interrupt-cells = <1>; +diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi +index f0ef86fadc9d9..e328216443135 100644 +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -230,9 +230,12 @@ + interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hc_irq", "pwr_irq"; + bus-width = <8>; +- clocks = <&gcc GCC_SDCC1_AHB_CLK>, <&gcc GCC_SDCC1_APPS_CLK>, +- <&gcc GCC_DCD_XO_CLK>; +- clock-names = "iface", "core", "xo"; ++ clocks = <&gcc GCC_SDCC1_AHB_CLK>, ++ <&gcc GCC_SDCC1_APPS_CLK>, ++ <&xo>; ++ clock-names = "iface", ++ "core", ++ "xo"; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/qcom-sdx65-mtp.dts b/arch/arm/boot/dts/qcom-sdx65-mtp.dts +index 57bc3b03d3aac..4264ace66b295 100644 +--- a/arch/arm/boot/dts/qcom-sdx65-mtp.dts ++++ b/arch/arm/boot/dts/qcom-sdx65-mtp.dts +@@ -7,7 +7,7 @@ + #include "qcom-sdx65.dtsi" + #include <dt-bindings/regulator/qcom,rpmh-regulator.h> + #include <arm64/qcom/pmk8350.dtsi> +-#include <arm64/qcom/pm8150b.dtsi> ++#include <arm64/qcom/pm7250b.dtsi> + #include "qcom-pmx65.dtsi" + + / { +diff --git a/arch/arm/boot/dts/s3c6410-mini6410.dts b/arch/arm/boot/dts/s3c6410-mini6410.dts +index 17097da36f5ed..0b07b3c319604 100644 +--- a/arch/arm/boot/dts/s3c6410-mini6410.dts ++++ b/arch/arm/boot/dts/s3c6410-mini6410.dts +@@ -51,7 +51,7 @@ + + ethernet@18000000 { + compatible = "davicom,dm9000"; +- reg = <0x18000000 0x2 0x18000004 0x2>; ++ reg = <0x18000000 0x2>, <0x18000004 0x2>; + interrupt-parent = <&gpn>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + davicom,no-eeprom; +diff --git a/arch/arm/boot/dts/s5pv210-smdkv210.dts b/arch/arm/boot/dts/s5pv210-smdkv210.dts +index fbae768d65e27..901e7197b1368 100644 +--- a/arch/arm/boot/dts/s5pv210-smdkv210.dts ++++ b/arch/arm/boot/dts/s5pv210-smdkv210.dts +@@ -41,7 +41,7 @@ + + ethernet@a8000000 { + compatible = "davicom,dm9000"; +- reg = <0xA8000000 0x2 0xA8000002 0x2>; ++ reg = <0xa8000000 0x2>, <0xa8000002 0x2>; + interrupt-parent = <&gph1>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + local-mac-address = [00 00 de ad be ef]; +@@ -55,6 +55,14 @@ + default-brightness-level = <6>; + pinctrl-names = "default"; + pinctrl-0 = <&pwm3_out>; ++ power-supply = <&dc5v_reg>; ++ }; ++ ++ dc5v_reg: regulator-0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "DC5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + }; + }; + +diff --git a/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi b/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi +index b01470a9a3d53..fd89542c69c93 100644 +--- a/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi ++++ b/arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi +@@ -97,9 +97,11 @@ + adc1: adc@0 { + pinctrl-names = "default"; + pinctrl-0 = <&adc1_in6_pins_a>; +- st,min-sample-time-nsecs = <5000>; +- st,adc-channels = <6>; + status = "disabled"; ++ channel@6 { ++ reg = <6>; ++ st,min-sample-time-ns = <5000>; ++ }; + }; + + adc2: adc@100 { +@@ -366,8 +368,8 @@ + &m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; +- mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; +- mbox-names = "vq0", "vq1", "shutdown"; ++ mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>; ++ mbox-names = "vq0", "vq1", "shutdown", "detach"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + interrupt-names = "wdg"; +diff --git a/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi b/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi +index e22871dc580c8..cf74852514906 100644 +--- a/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi ++++ b/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi +@@ -230,8 +230,8 @@ + &m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; +- mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; +- mbox-names = "vq0", "vq1", "shutdown"; ++ mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>; ++ mbox-names = "vq0", "vq1", "shutdown", "detach"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + status = "okay"; +diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi +index c06edd2eacb0c..74a11ccc5333f 100644 +--- a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi ++++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi +@@ -80,17 +80,19 @@ + vdda-supply = <&vdda>; + vref-supply = <&vdda>; + status = "okay"; ++}; + +- adc1: adc@0 { +- st,min-sample-time-nsecs = <5000>; +- st,adc-channels = <0>; +- status = "okay"; ++&adc1 { ++ channel@0 { ++ reg = <0>; ++ st,min-sample-time-ns = <5000>; + }; ++}; + +- adc2: adc@100 { +- st,adc-channels = <1>; +- st,min-sample-time-nsecs = <5000>; +- status = "okay"; ++&adc2 { ++ channel@1 { ++ reg = <1>; ++ st,min-sample-time-ns = <5000>; + }; + }; + +@@ -414,8 +416,8 @@ + &m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; +- mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; +- mbox-names = "vq0", "vq1", "shutdown"; ++ mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>; ++ mbox-names = "vq0", "vq1", "shutdown", "detach"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + status = "okay"; +diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi +index 7d5d6d4360385..c792dff433fc5 100644 +--- a/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi ++++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi +@@ -111,17 +111,39 @@ + vdda-supply = <&vdda>; + vref-supply = <&vdda>; + status = "okay"; ++}; + +- adc1: adc@0 { +- st,adc-channels = <0 1 6>; +- st,min-sample-time-nsecs = <5000>; +- status = "okay"; ++&adc1 { ++ channel@0 { ++ reg = <0>; ++ st,min-sample-time-ns = <5000>; + }; + +- adc2: adc@100 { +- st,adc-channels = <0 1 2>; +- st,min-sample-time-nsecs = <5000>; +- status = "okay"; ++ channel@1 { ++ reg = <1>; ++ st,min-sample-time-ns = <5000>; ++ }; ++ ++ channel@6 { ++ reg = <6>; ++ st,min-sample-time-ns = <5000>; ++ }; ++}; ++ ++&adc2 { ++ channel@0 { ++ reg = <0>; ++ st,min-sample-time-ns = <5000>; ++ }; ++ ++ channel@1 { ++ reg = <1>; ++ st,min-sample-time-ns = <5000>; ++ }; ++ ++ channel@2 { ++ reg = <2>; ++ st,min-sample-time-ns = <5000>; + }; + }; + +diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi +index bba19f21e5277..89881a26c6141 100644 +--- a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi ++++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi +@@ -227,8 +227,8 @@ + &m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; +- mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; +- mbox-names = "vq0", "vq1", "shutdown"; ++ mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>; ++ mbox-names = "vq0", "vq1", "shutdown", "detach"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + status = "okay"; +diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h +index dfeed440254a8..fe4326d938c18 100644 +--- a/arch/arm/include/asm/syscall.h ++++ b/arch/arm/include/asm/syscall.h +@@ -25,6 +25,9 @@ static inline int syscall_get_nr(struct task_struct *task, + if (IS_ENABLED(CONFIG_AEABI) && !IS_ENABLED(CONFIG_OABI_COMPAT)) + return task_thread_info(task)->abi_syscall; + ++ if (task_thread_info(task)->abi_syscall == -1) ++ return -1; ++ + return task_thread_info(task)->abi_syscall & __NR_SYSCALL_MASK; + } + +diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S +index 03d4c5578c5c9..b60bba3c1d516 100644 +--- a/arch/arm/kernel/entry-common.S ++++ b/arch/arm/kernel/entry-common.S +@@ -90,6 +90,7 @@ slow_work_pending: + cmp r0, #0 + beq no_work_pending + movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE) ++ str scno, [tsk, #TI_ABI_SYSCALL] @ make sure tracers see update + ldmia sp, {r0 - r6} @ have to reload r0 - r6 + b local_restart @ ... and off we go + ENDPROC(ret_fast_syscall) +diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c +index 2d8e2516906b6..fef32d73f9120 100644 +--- a/arch/arm/kernel/ptrace.c ++++ b/arch/arm/kernel/ptrace.c +@@ -783,8 +783,9 @@ long arch_ptrace(struct task_struct *child, long request, + break; + + case PTRACE_SET_SYSCALL: +- task_thread_info(child)->abi_syscall = data & +- __NR_SYSCALL_MASK; ++ if (data != -1) ++ data &= __NR_SYSCALL_MASK; ++ task_thread_info(child)->abi_syscall = data; + ret = 0; + break; + +diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c +index 777f9f8e7cd86..5e05dd1324e7b 100644 +--- a/arch/arm/mach-omap2/powerdomain.c ++++ b/arch/arm/mach-omap2/powerdomain.c +@@ -174,7 +174,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) + break; + case PWRDM_STATE_PREV: + prev = pwrdm_read_prev_pwrst(pwrdm); +- if (pwrdm->state != prev) ++ if (prev >= 0 && pwrdm->state != prev) + pwrdm->state_counter[prev]++; + if (prev == PWRDM_POWER_RET) + _update_logic_membank_counters(pwrdm); +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +index b4409349eb3f6..1004ab0abb131 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +@@ -355,28 +355,6 @@ + >; + }; + +- pinctrl_fec: fecgrp { +- fsl,pins = < +- MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC 0x3 +- MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO 0x3 +- MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0 0x91 +- MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1 0x91 +- MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2 0x91 +- MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3 0x91 +- MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC 0x91 +- MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL 0x91 +- MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0 0x1f +- MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1 0x1f +- MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2 0x1f +- MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3 0x1f +- MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL 0x1f +- MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC 0x1f +- MX8MP_IOMUXC_SAI1_RXD1__ENET1_1588_EVENT1_OUT 0x1f +- MX8MP_IOMUXC_SAI1_RXD0__ENET1_1588_EVENT1_IN 0x1f +- MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19 0x19 +- >; +- }; +- + pinctrl_gpio_led: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19 +diff --git a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts +index d7d7c63e62e25..79d294c2ee199 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts ++++ b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts +@@ -1312,6 +1312,7 @@ + + uartd: serial@70006300 { + compatible = "nvidia,tegra30-hsuart"; ++ reset-names = "serial"; + status = "okay"; + + bluetooth { +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts +index caa9e952a149c..a1194c4e15f0e 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts +@@ -2010,6 +2010,7 @@ + + serial@3100000 { + compatible = "nvidia,tegra194-hsuart"; ++ reset-names = "serial"; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts +index 3ec449f5cab78..fa92a870cfc40 100644 +--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts ++++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts +@@ -75,7 +75,7 @@ + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 121 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 121 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -101,13 +101,13 @@ + button { + label = "Volume Up"; + linux,code = <KEY_VOLUMEUP>; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + pinctrl-names = "default"; +- pinctrl-0 = <&msmgpio_leds>, ++ pinctrl-0 = <&tlmm_leds>, + <&pm8916_gpios_leds>, + <&pm8916_mpps_leds>; + +@@ -117,7 +117,7 @@ + label = "apq8016-sbc:green:user1"; + function = LED_FUNCTION_HEARTBEAT; + color = <LED_COLOR_ID_GREEN>; +- gpios = <&msmgpio 21 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; +@@ -126,7 +126,7 @@ + label = "apq8016-sbc:green:user2"; + function = LED_FUNCTION_DISK_ACTIVITY; + color = <LED_COLOR_ID_GREEN>; +- gpios = <&msmgpio 120 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 120 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; +@@ -186,14 +186,14 @@ + compatible = "adi,adv7533"; + reg = <0x39>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; + + adi,dsi-lanes = <4>; + clocks = <&rpmcc RPM_SMD_BB_CLK2>; + clock-names = "cec"; + +- pd-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; ++ pd-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + + avdd-supply = <&pm8916_l6>; + v1p2-supply = <&pm8916_l6>; +@@ -276,8 +276,8 @@ + compatible = "ovti,ov5640"; + reg = <0x3b>; + +- enable-gpios = <&msmgpio 34 GPIO_ACTIVE_HIGH>; +- reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>; ++ powerdown-gpios = <&tlmm 34 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_default>; + +@@ -285,9 +285,9 @@ + clock-names = "xclk"; + clock-frequency = <23880000>; + +- vdddo-supply = <&camera_vdddo_1v8>; +- vdda-supply = <&camera_vdda_2v8>; +- vddd-supply = <&camera_vddd_1v5>; ++ DOVDD-supply = <&camera_vdddo_1v8>; ++ AVDD-supply = <&camera_vdda_2v8>; ++ DVDD-supply = <&camera_vddd_1v5>; + + /* No camera mezzanine by default */ + status = "disabled"; +@@ -310,6 +310,10 @@ + status = "okay"; + }; + ++&lpass_codec { ++ status = "okay"; ++}; ++ + &mdss { + status = "okay"; + }; +@@ -325,6 +329,40 @@ + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ /* ++ * The 96Boards specification expects a 1.8V power rail on the low-speed ++ * expansion connector that is able to provide at least 0.18W / 100 mA. ++ * L15/L16 are connected in parallel to provide 55 mA each. A minimum load ++ * must be specified to ensure the regulators are not put in LPM where they ++ * would only provide 5 mA. ++ */ ++ pm8916_l15: l15 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-system-load = <50000>; ++ regulator-allow-set-load; ++ regulator-always-on; ++ }; ++ pm8916_l16: l16 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-system-load = <50000>; ++ regulator-allow-set-load; ++ regulator-always-on; ++ }; ++ ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++}; ++ ++&pm8916_s4 { ++ regulator-always-on; ++ regulator-boot-on; ++}; ++ + &sdhc_1 { + status = "okay"; + +@@ -340,7 +378,7 @@ + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + }; + + &sound { +@@ -399,6 +437,7 @@ + }; + + &wcd_codec { ++ status = "okay"; + clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "mclk"; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; +@@ -441,125 +480,6 @@ + &stm { status = "okay"; }; + &tpiu { status = "okay"; }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1250000>; +- regulator-max-microvolt = <1350000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1850000>; +- regulator-max-microvolt = <2150000>; +- +- regulator-always-on; +- regulator-boot-on; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2900000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2800000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <2950000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- /* +- * The 96Boards specification expects a 1.8V power rail on the low-speed +- * expansion connector that is able to provide at least 0.18W / 100 mA. +- * L15/L16 are connected in parallel to provide 55 mA each. A minimum load +- * must be specified to ensure the regulators are not put in LPM where they +- * would only provide 5 mA. +- */ +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-system-load = <50000>; +- regulator-allow-set-load; +- regulator-always-on; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-system-load = <50000>; +- regulator-allow-set-load; +- regulator-always-on; +- }; +- +- l17 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- + /* + * 2mA drive strength is not enough when connecting multiple + * I2C devices with different pull up resistors. +@@ -600,7 +520,7 @@ + * ones actually used for GPIO. + */ + +-&msmgpio { ++&tlmm { + gpio-line-names = + "[UART0_TX]", /* GPIO_0, LSEC pin 5 */ + "[UART0_RX]", /* GPIO_1, LSEC pin 7 */ +@@ -725,7 +645,7 @@ + "USR_LED_2_CTRL", /* GPIO 120 */ + "SB_HS_ID"; + +- msmgpio_leds: msmgpio-leds-state { ++ tlmm_leds: tlmm-leds-state { + pins = "gpio21", "gpio120"; + function = "gpio"; + +diff --git a/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts b/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts +index 13cd9ad167df7..7b77a80f049c6 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts +@@ -39,14 +39,14 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 110 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -58,7 +58,7 @@ + accelerometer@10 { + compatible = "bosch,bmc150_accel"; + reg = <0x10>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&pm8916_l17>; +@@ -89,10 +89,10 @@ + compatible = "edt,edt-ft5406"; + reg = <0x38>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + +- reset-gpios = <&msmgpio 12 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + vcc-supply = <&pm8916_l16>; + iovcc-supply = <&pm8916_l6>; +@@ -114,6 +114,18 @@ + status = "okay"; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l16: l16 { ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ }; ++ ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_vib { + status = "okay"; + }; +@@ -131,7 +143,7 @@ + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_HIGH>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_HIGH>; + + status = "okay"; + }; +@@ -153,110 +165,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-system-load = <200000>; +- regulator-allow-set-load; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <2900000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio115"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts +index fecb69944cfa3..d2abbdec5fe68 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts +@@ -30,7 +30,7 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; +@@ -42,7 +42,7 @@ + pinctrl-0 = <&gpio_leds_default>; + + led-0 { +- gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "torch"; + function = LED_FUNCTION_TORCH; + }; +@@ -50,7 +50,7 @@ + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 69 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 69 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -66,9 +66,9 @@ + touchscreen@26 { + compatible = "mstar,msg2638"; + reg = <0x26>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; +- reset-gpios = <&msmgpio 100 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 100 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_reset_default>; + vdd-supply = <&pm8916_l17>; +@@ -86,7 +86,7 @@ + reg = <0x0c>; + vdd-supply = <&pm8916_l17>; + vid-supply = <&pm8916_l6>; +- reset-gpios = <&msmgpio 8 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&mag_reset_default>; + mount-matrix = "0", "1", "0", +@@ -99,7 +99,7 @@ + reg = <0x0f>; + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <31 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&accel_int_default>; +@@ -111,7 +111,7 @@ + proximity@48 { + compatible = "sensortek,stk3310"; + reg = <0x48>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&proximity_int_default>; +@@ -122,7 +122,7 @@ + reg = <0x68>; + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <97 IRQ_TYPE_EDGE_RISING>, + <98 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; +@@ -136,7 +136,7 @@ + led-controller@68 { + compatible = "si-en,sn3190"; + reg = <0x68>; +- shutdown-gpios = <&msmgpio 89 GPIO_ACTIVE_HIGH>; ++ shutdown-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&led_enable_default &led_shutdown_default>; + #address-cells = <1>; +@@ -156,6 +156,13 @@ + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_vib { + status = "okay"; + }; +@@ -175,7 +182,7 @@ + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + }; + + &usb { +@@ -195,110 +202,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio31"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts +index 91284a1d0966f..c58a70fdf36fb 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts +@@ -30,14 +30,14 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + debounce-interval = <15>; + }; + + button-volume-down { + label = "Volume Down"; +- gpios = <&msmgpio 117 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 117 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEDOWN>; + debounce-interval = <15>; + }; +@@ -49,7 +49,7 @@ + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + +- gpio = <&msmgpio 87 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 87 GPIO_ACTIVE_HIGH>; + enable-active-high; + + startup-delay-us = <200>; +@@ -60,7 +60,7 @@ + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpios = <&msmgpio 110 GPIO_ACTIVE_HIGH>; ++ id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -76,7 +76,7 @@ + vdd-supply = <&pm8916_l8>; + vid-supply = <&pm8916_l6>; + +- reset-gpios = <&msmgpio 112 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 112 GPIO_ACTIVE_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&mag_reset_default>; +@@ -86,7 +86,7 @@ + compatible = "invensense,mpu6515"; + reg = <0x68>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <36 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&pm8916_l17>; +@@ -108,10 +108,10 @@ + compatible = "edt,edt-ft5306"; + reg = <0x38>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + +- reset-gpios = <&msmgpio 12 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + vcc-supply = <&pm8916_l11>; + iovcc-supply = <&pm8916_l6>; +@@ -128,6 +128,13 @@ + status = "okay"; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &sdhc_1 { + status = "okay"; + +@@ -143,7 +150,7 @@ + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + }; + + &usb { +@@ -163,110 +170,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + gpio_keys_default: gpio-keys-default-state { + pins = "gpio107", "gpio117"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-gplus-fl8005a.dts b/arch/arm64/boot/dts/qcom/msm8916-gplus-fl8005a.dts +index 525ec76efeeb7..221db7edec5ef 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-gplus-fl8005a.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-gplus-fl8005a.dts +@@ -24,8 +24,8 @@ + flash-led-controller { + /* Actually qcom,leds-gpio-flash */ + compatible = "sgmicro,sgm3140"; +- enable-gpios = <&msmgpio 31 GPIO_ACTIVE_HIGH>; +- flash-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>; ++ flash-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&camera_flash_default>; + pinctrl-names = "default"; +@@ -45,7 +45,7 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; +@@ -59,21 +59,21 @@ + led-red { + function = LED_FUNCTION_CHARGING; + color = <LED_COLOR_ID_RED>; +- gpios = <&msmgpio 117 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; + retain-state-suspended; + }; + + led-green { + function = LED_FUNCTION_CHARGING; + color = <LED_COLOR_ID_GREEN>; +- gpios = <&msmgpio 118 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 118 GPIO_ACTIVE_HIGH>; + retain-state-suspended; + }; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 110 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb_id_default>; + pinctrl-names = "default"; + }; +@@ -87,10 +87,10 @@ + compatible = "edt,edt-ft5406"; + reg = <0x38>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + +- reset-gpios = <&msmgpio 12 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + vcc-supply = <&pm8916_l17>; + iovcc-supply = <&pm8916_l6>; +@@ -114,6 +114,13 @@ + status = "okay"; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_vib { + status = "okay"; + }; +@@ -131,7 +138,7 @@ + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + pinctrl-names = "default", "sleep"; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + + status = "okay"; + }; +@@ -153,110 +160,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-system-load = <200000>; +- regulator-allow-set-load; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + camera_flash_default: camera-flash-default-state { + pins = "gpio31", "gpio32"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts b/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts +index 5b1bac8f51220..b02e8f9a8ca0d 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts +@@ -43,7 +43,7 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; +@@ -55,21 +55,21 @@ + pinctrl-0 = <&gpio_leds_default>; + + led-0 { +- gpios = <&msmgpio 8 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_RED>; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; + }; + + led-1 { +- gpios = <&msmgpio 9 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 9 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_GREEN>; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; + }; + + led-2 { +- gpios = <&msmgpio 10 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 10 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_BLUE>; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; +@@ -78,7 +78,7 @@ + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 117 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 117 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -94,7 +94,7 @@ + vdd-supply = <&pm8916_l17>; + vid-supply = <&pm8916_l6>; + +- reset-gpios = <&msmgpio 36 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 36 GPIO_ACTIVE_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&mag_reset_default>; +@@ -104,7 +104,7 @@ + compatible = "kionix,kx023-1025"; + reg = <0x1e>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&pm8916_l17>; +@@ -122,7 +122,7 @@ + compatible = "avago,apds9930"; + reg = <0x39>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <113 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&pm8916_l17>; +@@ -146,7 +146,7 @@ + regulator-name = "outp"; + regulator-min-microvolt = <5400000>; + regulator-max-microvolt = <5400000>; +- enable-gpios = <&msmgpio 97 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 97 GPIO_ACTIVE_HIGH>; + regulator-active-discharge = <1>; + }; + +@@ -154,7 +154,7 @@ + regulator-name = "outn"; + regulator-min-microvolt = <5400000>; + regulator-max-microvolt = <5400000>; +- enable-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + regulator-active-discharge = <1>; + }; + }; +@@ -169,7 +169,7 @@ + #address-cells = <1>; + #size-cells = <0>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&pm8916_l17>; +@@ -199,11 +199,11 @@ + compatible = "nxp,pn547", "nxp,nxp-nci-i2c"; + reg = <0x28>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + +- enable-gpios = <&msmgpio 20 GPIO_ACTIVE_HIGH>; +- firmware-gpios = <&msmgpio 2 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; ++ firmware-gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_default>; +@@ -218,11 +218,32 @@ + status = "okay"; + }; + ++&lpass_codec { ++ status = "okay"; ++}; ++ ++&pm8916_l8 { ++ regulator-min-microvolt = <2950000>; ++ regulator-max-microvolt = <2950000>; ++}; ++ + &pm8916_resin { + status = "okay"; + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l16: l16 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_vib { + status = "okay"; + }; +@@ -243,7 +264,7 @@ + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdhc2_cd_default>; + + /* +- * The Huawei device tree sets cd-gpios = <&msmgpio 38 GPIO_ACTIVE_HIGH>. ++ * The Huawei device tree sets cd-gpios = <&tlmm 38 GPIO_ACTIVE_HIGH>. + * However, gpio38 does not change its state when inserting/removing the + * SD card, it's just low all the time. The Huawei kernel seems to use + * polling for SD card detection instead. +@@ -255,7 +276,7 @@ + * Maybe Huawei decided to replace the second SIM card slot with the + * SD card slot and forgot to re-route to gpio38. + */ +- cd-gpios = <&msmgpio 56 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 56 GPIO_ACTIVE_LOW>; + }; + + &sound { +@@ -302,6 +323,7 @@ + }; + + &wcd_codec { ++ status = "okay"; + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; +@@ -316,110 +338,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2950000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + accel_irq_default: accel-irq-default-state { + pins = "gpio115"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +index f1dd625e18227..4aa2281bdbcaa 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +@@ -41,7 +41,7 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; +@@ -53,7 +53,7 @@ + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + +- gpio = <&msmgpio 17 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 17 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -62,8 +62,8 @@ + + flash-led-controller { + compatible = "sgmicro,sgm3140"; +- flash-gpios = <&msmgpio 31 GPIO_ACTIVE_HIGH>; +- enable-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; ++ flash-gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&camera_flash_default>; +@@ -122,7 +122,7 @@ + * to the BMC156. However, there are two pads next to the chip + * that can be shorted to make it work if needed. + * +- * interrupt-parent = <&msmgpio>; ++ * interrupt-parent = <&tlmm>; + * interrupts = <116 IRQ_TYPE_EDGE_RISING>; + */ + +@@ -141,7 +141,7 @@ + compatible = "bosch,bmc156_magn"; + reg = <0x12>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <113 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; +@@ -156,21 +156,21 @@ + reg = <0x23>; + proximity-near-level = <75>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; + pinctrl-0 = <&light_int_default>; + + vdd-supply = <&pm8916_l17>; +- vio-supply = <&pm8916_l6>; ++ vddio-supply = <&pm8916_l6>; + }; + + gyroscope@68 { + compatible = "bosch,bmg160"; + reg = <0x68>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <23 IRQ_TYPE_EDGE_RISING>, + <22 IRQ_TYPE_EDGE_RISING>; + +@@ -191,7 +191,7 @@ + #address-cells = <1>; + #size-cells = <0>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <®_ctp>; +@@ -223,6 +223,13 @@ + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_usbin { + status = "okay"; + }; +@@ -267,110 +274,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio116"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts +index b79e80913af9f..a1208c8e06203 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts +@@ -20,6 +20,21 @@ + stdout-path = "serial0"; + }; + ++ flash-led-controller { ++ compatible = "ocs,ocp8110"; ++ enable-gpios = <&tlmm 49 GPIO_ACTIVE_HIGH>; ++ flash-gpios = <&tlmm 119 GPIO_ACTIVE_HIGH>; ++ ++ pinctrl-0 = <&camera_front_flash_default>; ++ pinctrl-names = "default"; ++ ++ flash_led: led { ++ function = LED_FUNCTION_FLASH; ++ color = <LED_COLOR_ID_WHITE>; ++ flash-max-timeout-us = <250000>; ++ }; ++ }; ++ + gpio-keys { + compatible = "gpio-keys"; + +@@ -30,7 +45,7 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; +@@ -39,7 +54,7 @@ + compatible = "gpio-leds"; + + led-0 { +- gpios = <&msmgpio 17 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 17 GPIO_ACTIVE_HIGH>; + color = <LED_COLOR_ID_WHITE>; + default-state = "off"; + function = LED_FUNCTION_KBD_BACKLIGHT; +@@ -51,7 +66,7 @@ + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 110 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -67,7 +82,7 @@ + vdd-supply = <&pm8916_l17>; + vid-supply = <&pm8916_l6>; + +- reset-gpios = <&msmgpio 111 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 111 GPIO_ACTIVE_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&mag_reset_default>; +@@ -95,6 +110,13 @@ + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_vib { + status = "okay"; + }; +@@ -114,7 +136,7 @@ + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + }; + + &usb { +@@ -134,110 +156,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + button_backlight_default: button-backlight-default-state { + pins = "gpio17"; + function = "gpio"; +@@ -246,6 +165,13 @@ + bias-disable; + }; + ++ camera_front_flash_default: camera-front-flash-default-state { ++ pins = "gpio49", "gpio119"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-disable; ++ }; ++ + gpio_keys_default: gpio-keys-default-state { + pins = "gpio107"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi +index 33dfcf318a81b..1e07f70768f41 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi +@@ -3,7 +3,7 @@ + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + */ + +-&msmgpio { ++&tlmm { + + blsp1_uart1_default: blsp1-uart1-default-state { + /* TX, RX, CTS_N, RTS_N */ +diff --git a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi +index 6eb5e0a395100..d83f767ac5bf4 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-pm8916.dtsi +@@ -47,30 +47,92 @@ + }; + + &rpm_requests { +- smd_rpm_regulators: regulators { ++ pm8916_rpm_regulators: regulators { + compatible = "qcom,rpm-pm8916-regulators"; ++ vdd_l1_l2_l3-supply = <&pm8916_s3>; ++ vdd_l4_l5_l6-supply = <&pm8916_s4>; ++ vdd_l7-supply = <&pm8916_s4>; + + /* pm8916_s1 is managed by rpmpd (MSM8916_VDDCX) */ +- pm8916_s3: s3 {}; +- pm8916_s4: s4 {}; + +- pm8916_l1: l1 {}; +- pm8916_l2: l2 {}; ++ pm8916_s3: s3 { ++ regulator-min-microvolt = <1250000>; ++ regulator-max-microvolt = <1350000>; ++ }; ++ ++ pm8916_s4: s4 { ++ regulator-min-microvolt = <1850000>; ++ regulator-max-microvolt = <2150000>; ++ }; ++ ++ /* ++ * Some of the regulators are unused or managed by another ++ * processor (e.g. the modem). We should still define nodes for ++ * them to ensure the vote from the application processor can be ++ * dropped in case the regulators are already on during boot. ++ * ++ * The labels for these nodes are omitted on purpose because ++ * boards should configure a proper voltage before using them. ++ */ ++ l1 {}; ++ ++ pm8916_l2: l2 { ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ }; ++ + /* pm8916_l3 is managed by rpmpd (MSM8916_VDDMX) */ +- pm8916_l4: l4 {}; +- pm8916_l5: l5 {}; +- pm8916_l6: l6 {}; +- pm8916_l7: l7 {}; +- pm8916_l8: l8 {}; +- pm8916_l9: l9 {}; +- pm8916_l10: l10 {}; +- pm8916_l11: l11 {}; +- pm8916_l12: l12 {}; +- pm8916_l13: l13 {}; +- pm8916_l14: l14 {}; +- pm8916_l15: l15 {}; +- pm8916_l16: l16 {}; +- pm8916_l17: l17 {}; +- pm8916_l18: l18 {}; ++ ++ l4 {}; ++ ++ pm8916_l5: l5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ pm8916_l6: l6 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ pm8916_l7: l7 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ pm8916_l8: l8 { ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ }; ++ ++ pm8916_l9: l9 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ l10 {}; ++ ++ pm8916_l11: l11 { ++ regulator-min-microvolt = <2950000>; ++ regulator-max-microvolt = <2950000>; ++ regulator-allow-set-load; ++ regulator-system-load = <200000>; ++ }; ++ ++ pm8916_l12: l12 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <2950000>; ++ }; ++ ++ pm8916_l13: l13 { ++ regulator-min-microvolt = <3075000>; ++ regulator-max-microvolt = <3075000>; ++ }; ++ ++ l14 {}; ++ l15 {}; ++ l16 {}; ++ l17 {}; ++ l18 {}; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi +index 16d67749960e0..550ba6b9d4cd8 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi +@@ -44,13 +44,13 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + + button-home { + label = "Home"; +- gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 109 GPIO_ACTIVE_LOW>; + linux,code = <KEY_HOMEPAGE>; + }; + }; +@@ -65,7 +65,7 @@ + + event-hall-sensor { + label = "Hall Effect Sensor"; +- gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; + linux,input-type = <EV_SW>; + linux,code = <SW_LID>; + linux,can-disable; +@@ -83,7 +83,7 @@ + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + +- gpio = <&msmgpio 76 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 76 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -96,7 +96,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 73 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -105,8 +105,8 @@ + + i2c-muic { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&muic_i2c_default>; +@@ -118,7 +118,7 @@ + compatible = "siliconmitus,sm5502-muic"; + + reg = <0x25>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; +@@ -128,8 +128,8 @@ + + i2c-tkey { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 17 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 17 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_i2c_default>; +@@ -142,7 +142,7 @@ + compatible = "coreriver,tc360-touchkey"; + reg = <0x20>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <98 IRQ_TYPE_EDGE_FALLING>; + + /* vcc/vdd-supply are board-specific */ +@@ -157,8 +157,8 @@ + + i2c-nfc { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 0 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 1 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 0 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 1 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_i2c_default>; +@@ -170,11 +170,11 @@ + compatible = "samsung,s3fwrn5-i2c"; + reg = <0x27>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + +- en-gpios = <&msmgpio 20 GPIO_ACTIVE_LOW>; +- wake-gpios = <&msmgpio 49 GPIO_ACTIVE_HIGH>; ++ en-gpios = <&tlmm 20 GPIO_ACTIVE_LOW>; ++ wake-gpios = <&tlmm 49 GPIO_ACTIVE_HIGH>; + + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + +@@ -200,7 +200,7 @@ + accelerometer: accelerometer@10 { + compatible = "bosch,bmc150_accel"; + reg = <0x10>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&pm8916_l17>; +@@ -225,7 +225,7 @@ + battery@35 { + compatible = "richtek,rt5033-battery"; + reg = <0x35>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <121 IRQ_TYPE_EDGE_BOTH>; + + pinctrl-names = "default"; +@@ -252,6 +252,13 @@ + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &sdhc_1 { + status = "okay"; + +@@ -267,7 +274,7 @@ + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + }; + + &usb { +@@ -279,110 +286,7 @@ + extcon = <&muic>; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio115"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts +index a1ca4d8834201..9068aa6f7b293 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts +@@ -15,7 +15,7 @@ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + +- gpio = <&msmgpio 9 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 9 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -28,7 +28,7 @@ + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + +- gpio = <&msmgpio 86 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 86 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -41,7 +41,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 60 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 60 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -67,7 +67,7 @@ + compatible = "zinitix,bt541"; + + reg = <0x20>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + touchscreen-size-x = <540>; +@@ -93,7 +93,7 @@ + + vdd3-supply = <®_panel_vdd3>; + vci-supply = <&pm8916_l17>; +- reset-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>; + + port { + panel_in: endpoint { +@@ -120,7 +120,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&msmgpio { ++&tlmm { + panel_vdd3_default: panel-vdd3-default-state { + pins = "gpio9"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts +index 4e10b8a5e9f9c..388482a1e3d9f 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts +@@ -15,7 +15,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 97 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 97 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -36,7 +36,7 @@ + compatible = "melfas,mms345l"; + + reg = <0x48>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + touchscreen-size-x = <720>; +@@ -71,7 +71,7 @@ + compatible = "qcom,wcn3660b"; + }; + +-&msmgpio { ++&tlmm { + tkey_en_default: tkey-en-default-state { + pins = "gpio97"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi +index f6c4a011fdfd2..0cdd6af7817f4 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi +@@ -18,7 +18,7 @@ + compatible = "siliconmitus,sm5504-muic"; + reg = <0x14>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; +@@ -32,7 +32,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 97 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 97 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -66,7 +66,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&msmgpio { ++&tlmm { + tkey_en_default: tkey-en-default-state { + pins = "gpio97"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts +index 4cbd68b894481..3f145dde4059f 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts +@@ -33,7 +33,7 @@ + function = LED_FUNCTION_KBD_BACKLIGHT; + color = <LED_COLOR_ID_WHITE>; + +- gpios = <&msmgpio 60 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 60 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&gpio_leds_default>; +@@ -42,14 +42,14 @@ + }; + + ®_motor_vdd { +- gpio = <&msmgpio 72 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 72 GPIO_ACTIVE_HIGH>; + }; + + ®_touch_key { + status = "disabled"; + }; + +-&msmgpio { ++&tlmm { + gpio_leds_default: gpio-led-default-state { + pins = "gpio60"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi +index 74ffd04db8d84..cb1b6318a246d 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi +@@ -34,13 +34,13 @@ + + volume-up-button { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + + home-button { + label = "Home"; +- gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 109 GPIO_ACTIVE_LOW>; + linux,code = <KEY_HOMEPAGE>; + }; + }; +@@ -55,7 +55,7 @@ + + hall-sensor-switch { + label = "Hall Effect Sensor"; +- gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; + linux,input-type = <EV_SW>; + linux,code = <SW_LID>; + linux,can-disable; +@@ -74,7 +74,7 @@ + maxim,over-heat-temp = <600>; + maxim,over-volt = <4400>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <121 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 = <&fuelgauge_int_default>; +@@ -97,7 +97,7 @@ + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l5>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "INT1"; + +@@ -120,6 +120,13 @@ + status = "okay"; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + /* FIXME: Replace with MAX77849 MUIC when driver is available */ + &pm8916_usbin { + status = "okay"; +@@ -138,7 +145,7 @@ + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + pinctrl-names = "default", "sleep"; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + + status = "okay"; + }; +@@ -162,110 +169,7 @@ + compatible = "qcom,wcn3660b"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-system-load = <200000>; +- regulator-allow-set-load; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio115"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts +index 607a5dc8a5341..48111c6a2c78f 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts +@@ -25,7 +25,7 @@ + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + +- gpio = <&msmgpio 76 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 76 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&motor_en_default>; +@@ -38,7 +38,7 @@ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + +- gpio = <&msmgpio 73 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&tsp_en_default>; +@@ -51,7 +51,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 73 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + +@@ -71,20 +71,20 @@ + touchscreen@4a { + compatible = "atmel,maxtouch"; + reg = <0x4a>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + + vdd-supply = <®_tsp_1p8v>; + vdda-supply = <®_tsp_3p3v>; + +- reset-gpios = <&msmgpio 114 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 114 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&tsp_int_rst_default>; + pinctrl-names = "default"; + }; + }; + +-&msmgpio { ++&tlmm { + motor_en_default: motor-en-default-state { + pins = "gpio76"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts +index 5d6f8383306bb..98ceaad7fcea9 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts +@@ -15,7 +15,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 73 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <®_tsp_en_default>; +@@ -24,7 +24,7 @@ + + vibrator { + compatible = "gpio-vibrator"; +- enable-gpios = <&msmgpio 76 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 76 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&vibrator_en_default>; + pinctrl-names = "default"; +@@ -37,7 +37,7 @@ + touchscreen@20 { + compatible = "zinitix,bt532"; + reg = <0x20>; +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + touchscreen-size-x = <768>; +@@ -51,7 +51,7 @@ + }; + }; + +-&msmgpio { ++&tlmm { + reg_tsp_en_default: reg-tsp-en-default-state { + pins = "gpio73"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi +index adeee0830e768..b2d2bc205ef27 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi +@@ -32,7 +32,7 @@ + + event-hall-sensor { + label = "Hall Effect Sensor"; +- gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; + linux,input-type = <EV_SW>; + linux,code = <SW_LID>; + linux,can-disable; +@@ -49,21 +49,21 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + + button-home { + label = "Home Key"; +- gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 109 GPIO_ACTIVE_LOW>; + linux,code = <KEY_HOMEPAGE>; + }; + }; + + i2c_muic: i2c-muic { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&muic_i2c_default>; +@@ -75,7 +75,7 @@ + compatible = "siliconmitus,sm5703-muic"; + reg = <0x25>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; +@@ -108,7 +108,7 @@ + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + +- cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + }; + + &usb { +@@ -128,110 +128,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <3000000>; +- regulator-max-microvolt = <3000000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + gpio_hall_sensor_default: gpio-hall-sensor-default-state { + pins = "gpio52"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts +index 1a41a4db874da..13a1d8828447b 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts +@@ -53,13 +53,13 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + + button-home { + label = "Home"; +- gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 109 GPIO_ACTIVE_LOW>; + linux,code = <KEY_HOMEPAGE>; + }; + }; +@@ -74,7 +74,7 @@ + + event-hall-sensor { + label = "Hall Effect Sensor"; +- gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; + linux,input-type = <EV_SW>; + linux,code = <SW_LID>; + linux,can-disable; +@@ -87,7 +87,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 73 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -100,7 +100,7 @@ + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + +- gpio = <&msmgpio 86 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 86 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -113,7 +113,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&msmgpio 60 GPIO_ACTIVE_HIGH>; ++ gpio = <&tlmm 60 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -122,8 +122,8 @@ + + i2c-muic { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&muic_i2c_default>; +@@ -135,7 +135,7 @@ + compatible = "siliconmitus,sm5504-muic"; + reg = <0x14>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; +@@ -145,8 +145,8 @@ + + i2c-tkey { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 17 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 17 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_i2c_default>; +@@ -158,7 +158,7 @@ + compatible = "coreriver,tc360-touchkey"; + reg = <0x20>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <98 IRQ_TYPE_EDGE_FALLING>; + + vcc-supply = <®_touch_key>; +@@ -174,8 +174,8 @@ + + i2c-nfc { + compatible = "i2c-gpio"; +- sda-gpios = <&msmgpio 0 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; +- scl-gpios = <&msmgpio 1 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&tlmm 0 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; ++ scl-gpios = <&tlmm 1 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_i2c_default>; +@@ -187,11 +187,11 @@ + compatible = "nxp,pn547", "nxp,nxp-nci-i2c"; + reg = <0x2b>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + +- enable-gpios = <&msmgpio 20 GPIO_ACTIVE_HIGH>; +- firmware-gpios = <&msmgpio 49 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; ++ firmware-gpios = <&tlmm 49 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_default>; +@@ -206,7 +206,7 @@ + compatible = "st,lsm6ds3"; + reg = <0x6b>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; +@@ -230,7 +230,7 @@ + compatible = "richtek,rt5033-battery"; + reg = <0x35>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <121 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; +@@ -245,7 +245,7 @@ + compatible = "zinitix,bt541"; + reg = <0x20>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + touchscreen-size-x = <540>; +@@ -320,110 +320,7 @@ + compatible = "qcom,wcn3660b"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + fg_alert_default: fg-alert-default-state { + pins = "gpio121"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts b/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts +index 82e260375174d..6fe1850ba20e9 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts +@@ -10,19 +10,19 @@ + }; + + &button_restart { +- gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; + }; + + &led_r { +- gpios = <&msmgpio 82 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>; + }; + + &led_g { +- gpios = <&msmgpio 83 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>; + }; + + &led_b { +- gpios = <&msmgpio 81 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>; + }; + + &button_default { +diff --git a/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts b/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts +index 978f0abcdf8ff..16d4a91022be6 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts +@@ -10,19 +10,19 @@ + }; + + &button_restart { +- gpios = <&msmgpio 37 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; + }; + + &led_r { +- gpios = <&msmgpio 22 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>; + }; + + &led_g { +- gpios = <&msmgpio 21 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; + }; + + &led_b { +- gpios = <&msmgpio 20 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; + }; + + &mpss { +@@ -40,7 +40,7 @@ + }; + + /* This selects the external SIM card slot by default */ +-&msmgpio { ++&tlmm { + sim_ctrl_default: sim-ctrl-default-state { + esim-sel-pins { + pins = "gpio0", "gpio3"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-ufi.dtsi b/arch/arm64/boot/dts/qcom/msm8916-ufi.dtsi +index 50bae6f214f1f..cb5c228ba9f6b 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-ufi.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916-ufi.dtsi +@@ -126,110 +126,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- regulator-system-load = <200000>; +- regulator-allow-set-load; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + /* pins are board-specific */ + button_default: button-default-state { + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts +index ac56c7595f78a..12ce4dc236c63 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts +@@ -25,8 +25,8 @@ + + flash-led-controller { + compatible = "ocs,ocp8110"; +- enable-gpios = <&msmgpio 31 GPIO_ACTIVE_HIGH>; +- flash-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>; ++ flash-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&camera_flash_default>; +@@ -47,14 +47,14 @@ + + button-volume-up { + label = "Volume Up"; +- gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = <KEY_VOLUMEUP>; + }; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; +- id-gpio = <&msmgpio 110 GPIO_ACTIVE_HIGH>; ++ id-gpio = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +@@ -67,7 +67,7 @@ + compatible = "invensense,mpu6880"; + reg = <0x68>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <115 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&pm8916_l17>; +@@ -90,10 +90,10 @@ + compatible = "edt,edt-ft5506"; + reg = <0x38>; + +- interrupt-parent = <&msmgpio>; ++ interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + +- reset-gpios = <&msmgpio 12 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + vcc-supply = <&pm8916_l17>; + iovcc-supply = <&pm8916_l6>; +@@ -149,6 +149,22 @@ + linux,code = <KEY_VOLUMEDOWN>; + }; + ++&pm8916_rpm_regulators { ++ pm8916_l16: l16 { ++ /* ++ * L16 is only used for AW2013 which is fine with 2.5-3.3V. ++ * Use the recommended typical voltage of 2.8V as minimum. ++ */ ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ pm8916_l17: l17 { ++ regulator-min-microvolt = <2850000>; ++ regulator-max-microvolt = <2850000>; ++ }; ++}; ++ + &pm8916_vib { + status = "okay"; + }; +@@ -188,110 +204,7 @@ + compatible = "qcom,wcn3620"; + }; + +-&smd_rpm_regulators { +- vdd_l1_l2_l3-supply = <&pm8916_s3>; +- vdd_l4_l5_l6-supply = <&pm8916_s4>; +- vdd_l7-supply = <&pm8916_s4>; +- +- s3 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1300000>; +- }; +- +- s4 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2100000>; +- }; +- +- l1 { +- regulator-min-microvolt = <1225000>; +- regulator-max-microvolt = <1225000>; +- }; +- +- l2 { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- }; +- +- l4 { +- regulator-min-microvolt = <2050000>; +- regulator-max-microvolt = <2050000>; +- }; +- +- l5 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l6 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l7 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- }; +- +- l8 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2900000>; +- }; +- +- l9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l10 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2800000>; +- }; +- +- l11 { +- regulator-min-microvolt = <2950000>; +- regulator-max-microvolt = <2950000>; +- regulator-allow-set-load; +- regulator-system-load = <200000>; +- }; +- +- l12 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2950000>; +- }; +- +- l13 { +- regulator-min-microvolt = <3075000>; +- regulator-max-microvolt = <3075000>; +- }; +- +- l14 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l15 { +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l16 { +- regulator-min-microvolt = <2800000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- l17 { +- regulator-min-microvolt = <2850000>; +- regulator-max-microvolt = <2850000>; +- }; +- +- l18 { +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- }; +-}; +- +-&msmgpio { ++&tlmm { + camera_flash_default: camera-flash-default-state { + pins = "gpio31", "gpio32"; + function = "gpio"; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts b/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts +index 74ce6563be183..5e6ba8c58bb57 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts +@@ -10,19 +10,19 @@ + }; + + &button_restart { +- gpios = <&msmgpio 23 GPIO_ACTIVE_LOW>; ++ gpios = <&tlmm 23 GPIO_ACTIVE_LOW>; + }; + + &led_r { +- gpios = <&msmgpio 7 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; + }; + + &led_g { +- gpios = <&msmgpio 8 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>; + }; + + &led_b { +- gpios = <&msmgpio 6 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; + }; + + &button_default { +diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi +index bf88c10ff55b0..309ed76ec2d87 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi +@@ -993,12 +993,12 @@ + }; + }; + +- msmgpio: pinctrl@1000000 { ++ tlmm: pinctrl@1000000 { + compatible = "qcom,msm8916-pinctrl"; + reg = <0x01000000 0x300000>; + interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; +- gpio-ranges = <&msmgpio 0 0 122>; ++ gpio-ranges = <&tlmm 0 0 122>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +@@ -1552,6 +1552,7 @@ + <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "ahbix-clk", "mclk"; + #sound-dai-cells = <1>; ++ status = "disabled"; + }; + + sdhc_1: mmc@7824900 { +diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts +index 100123d514944..f1d990dd7f7c9 100644 +--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts ++++ b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts +@@ -82,7 +82,7 @@ + #size-cells = <0>; + interrupt-parent = <&tlmm>; + interrupts = <125 IRQ_TYPE_LEVEL_LOW>; +- vdda-supply = <&vreg_l6a_1p8>; ++ vio-supply = <&vreg_l6a_1p8>; + vdd-supply = <&vdd_3v2_tp>; + reset-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>; + +diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi +index 25fe2b8552fc7..61da7fc281b32 100644 +--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi +@@ -1075,7 +1075,7 @@ + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; +- interrupts = <4>; ++ interrupts = <5>; + + clocks = <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_BYTE1_CLK>, +@@ -3336,6 +3336,9 @@ + #size-cells = <1>; + ranges; + ++ interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "hs_phy_irq"; ++ + clocks = <&gcc GCC_PERIPH_NOC_USB20_AHB_CLK>, + <&gcc GCC_USB20_MASTER_CLK>, + <&gcc GCC_USB20_MOCK_UTMI_CLK>, +diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi +index 3ec941fed14fe..f7c2820b1aacb 100644 +--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi +@@ -2428,10 +2428,10 @@ + + clocks = <&mmcc MNOC_AHB_CLK>, + <&mmcc BIMC_SMMU_AHB_CLK>, +- <&rpmcc RPM_SMD_MMAXI_CLK>, + <&mmcc BIMC_SMMU_AXI_CLK>; +- clock-names = "iface-mm", "iface-smmu", +- "bus-mm", "bus-smmu"; ++ clock-names = "iface-mm", ++ "iface-smmu", ++ "bus-smmu"; + + #global-interrupts = <0>; + interrupts = +@@ -2455,6 +2455,8 @@ + <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>; ++ ++ power-domains = <&mmcc BIMC_SMMU_GDSC>; + }; + + remoteproc_adsp: remoteproc@17300000 { +diff --git a/arch/arm64/boot/dts/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi +index 6f7aa67501e27..0fdf440596c01 100644 +--- a/arch/arm64/boot/dts/qcom/pm6150l.dtsi ++++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi +@@ -121,8 +121,9 @@ + pm6150l_wled: leds@d800 { + compatible = "qcom,pm6150l-wled"; + reg = <0xd800>, <0xd900>; +- interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; +- interrupt-names = "ovp"; ++ interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, ++ <0x5 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; ++ interrupt-names = "ovp", "short"; + label = "backlight"; + + status = "disabled"; +diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi +index 87b71b7205b85..6fdbf507c262a 100644 +--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi ++++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi +@@ -74,8 +74,9 @@ + pm660l_wled: leds@d800 { + compatible = "qcom,pm660l-wled"; + reg = <0xd800>, <0xd900>; +- interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; +- interrupt-names = "ovp"; ++ interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, ++ <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; ++ interrupt-names = "ovp", "short"; + label = "backlight"; + + status = "disabled"; +diff --git a/arch/arm64/boot/dts/qcom/pm8350.dtsi b/arch/arm64/boot/dts/qcom/pm8350.dtsi +index 2dfeb99300d74..9ed9ba23e81e4 100644 +--- a/arch/arm64/boot/dts/qcom/pm8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/pm8350.dtsi +@@ -8,7 +8,7 @@ + + / { + thermal-zones { +- pm8350_thermal: pm8350c-thermal { ++ pm8350_thermal: pm8350-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm8350_temp_alarm>; +diff --git a/arch/arm64/boot/dts/qcom/pm8350b.dtsi b/arch/arm64/boot/dts/qcom/pm8350b.dtsi +index f1c7bd9d079c2..05c1058988927 100644 +--- a/arch/arm64/boot/dts/qcom/pm8350b.dtsi ++++ b/arch/arm64/boot/dts/qcom/pm8350b.dtsi +@@ -8,7 +8,7 @@ + + / { + thermal-zones { +- pm8350b_thermal: pm8350c-thermal { ++ pm8350b_thermal: pm8350b-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm8350b_temp_alarm>; +diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi +index f4fb1a92ab55a..33ca1002fb754 100644 +--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi ++++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi +@@ -178,6 +178,7 @@ + vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; + vdd-micbias-supply = <&pm8916_l13>; + #sound-dai-cells = <1>; ++ status = "disabled"; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi +index 4891be3cd68a3..c16adca4e93a9 100644 +--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi ++++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi +@@ -87,8 +87,9 @@ + pmi8950_wled: leds@d800 { + compatible = "qcom,pmi8950-wled"; + reg = <0xd800>, <0xd900>; +- interrupts = <0x3 0xd8 0x02 IRQ_TYPE_EDGE_RISING>; +- interrupt-names = "short"; ++ interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, ++ <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; ++ interrupt-names = "ovp", "short"; + label = "backlight"; + + status = "disabled"; +diff --git a/arch/arm64/boot/dts/qcom/pmi8994.dtsi b/arch/arm64/boot/dts/qcom/pmi8994.dtsi +index 0192968f4d9b3..36d6a1fb553ac 100644 +--- a/arch/arm64/boot/dts/qcom/pmi8994.dtsi ++++ b/arch/arm64/boot/dts/qcom/pmi8994.dtsi +@@ -54,8 +54,9 @@ + pmi8994_wled: wled@d800 { + compatible = "qcom,pmi8994-wled"; + reg = <0xd800>, <0xd900>; +- interrupts = <3 0xd8 0x02 IRQ_TYPE_EDGE_RISING>; +- interrupt-names = "short"; ++ interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, ++ <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; ++ interrupt-names = "ovp", "short"; + qcom,cabc; + qcom,external-pfet; + status = "disabled"; +diff --git a/arch/arm64/boot/dts/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/qcom/pmk8350.dtsi +index f26fb7d32faf2..767ab7f284608 100644 +--- a/arch/arm64/boot/dts/qcom/pmk8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/pmk8350.dtsi +@@ -49,7 +49,7 @@ + }; + + pmk8350_adc_tm: adc-tm@3400 { +- compatible = "qcom,adc-tm7"; ++ compatible = "qcom,spmi-adc-tm5-gen2"; + reg = <0x3400>; + interrupts = <PMK8350_SID 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; +diff --git a/arch/arm64/boot/dts/qcom/pmr735b.dtsi b/arch/arm64/boot/dts/qcom/pmr735b.dtsi +index ec24c4478005a..f7473e2473224 100644 +--- a/arch/arm64/boot/dts/qcom/pmr735b.dtsi ++++ b/arch/arm64/boot/dts/qcom/pmr735b.dtsi +@@ -8,7 +8,7 @@ + + / { + thermal-zones { +- pmr735a_thermal: pmr735a-thermal { ++ pmr735b_thermal: pmr735b-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pmr735b_temp_alarm>; +diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +index 5b25d54b95911..4fa9a4f242273 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts ++++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +@@ -167,7 +167,7 @@ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + +- gpio = <&pmc8280_1_gpios 1 GPIO_ACTIVE_HIGH>; ++ gpio = <&pmc8280_1_gpios 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; +@@ -696,7 +696,7 @@ + }; + + misc_3p3_reg_en: misc-3p3-reg-en-state { +- pins = "gpio1"; ++ pins = "gpio2"; + function = "normal"; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +index bdcba719fc385..9fa9b40b41b49 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts ++++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +@@ -1212,7 +1212,7 @@ + }; + + &tlmm { +- gpio-reserved-ranges = <70 2>, <74 6>, <83 4>, <125 2>, <128 2>, <154 7>; ++ gpio-reserved-ranges = <70 2>, <74 6>, <125 2>, <128 2>, <154 4>; + + bt_default: bt-default-state { + hstp-bt-en-pins { +diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +index cc4aef21e6172..9c3fb75e06005 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +@@ -296,6 +296,7 @@ + firmware { + scm: scm { + compatible = "qcom,scm-sc8280xp", "qcom,scm"; ++ interconnects = <&aggre2_noc MASTER_CRYPTO 0 &mc_virt SLAVE_EBI1 0>; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi +index 420ffede3e804..25e06add95652 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi +@@ -15,6 +15,15 @@ + qcom,msm-id = <321 0x20001>; /* SDM845 v2.1 */ + qcom,board-id = <8 0>; + ++ aliases { ++ serial0 = &uart6; ++ serial1 = &uart9; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ + gpio-keys { + compatible = "gpio-keys"; + +diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi +index 1bfb938e284fb..b73ce14ababd1 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi +@@ -1207,6 +1207,7 @@ + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; ++ power-domains = <&rpmhpd SDM845_CX>; + }; + + qfprom@784000 { +@@ -2613,7 +2614,7 @@ + <0 0>, + <0 0>, + <0 0>, +- <0 300000000>; ++ <75000000 300000000>; + + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi +index ad34301f6cddf..18dc3119eea10 100644 +--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi +@@ -473,11 +473,6 @@ + no-map; + }; + +- pil_gpu_mem: memory@8b715400 { +- reg = <0 0x8b715400 0 0x2000>; +- no-map; +- }; +- + pil_modem_mem: memory@8b800000 { + reg = <0 0x8b800000 0 0xf800000>; + no-map; +@@ -498,6 +493,11 @@ + no-map; + }; + ++ pil_gpu_mem: memory@f0d00000 { ++ reg = <0 0xf0d00000 0 0x1000>; ++ no-map; ++ }; ++ + debug_region: memory@ffb00000 { + reg = <0 0xffb00000 0 0xc0000>; + no-map; +diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi +index 27dcda0d4288f..c4d87092e6d9c 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi +@@ -1231,7 +1231,7 @@ + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_i2c7_default>; +- interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>; ++ interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -3805,7 +3805,7 @@ + }; + + mdss_dsi0_phy: phy@ae94400 { +- compatible = "qcom,dsi-phy-7nm"; ++ compatible = "qcom,dsi-phy-7nm-8150"; + reg = <0 0x0ae94400 0 0x200>, + <0 0x0ae94600 0 0x280>, + <0 0x0ae94900 0 0x260>; +@@ -3879,7 +3879,7 @@ + }; + + mdss_dsi1_phy: phy@ae96400 { +- compatible = "qcom,dsi-phy-7nm"; ++ compatible = "qcom,dsi-phy-7nm-8150"; + reg = <0 0x0ae96400 0 0x200>, + <0 0x0ae96600 0 0x280>, + <0 0x0ae96900 0 0x260>; +diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts +index 356a81698731a..62590c6bd3067 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts ++++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts +@@ -14,3 +14,236 @@ + }; + + /delete-node/ &vreg_l7f_1p8; ++ ++&pm8009_gpios { ++ gpio-line-names = "NC", /* GPIO_1 */ ++ "CAM_PWR_LD_EN", ++ "WIDEC_PWR_EN", ++ "NC"; ++}; ++ ++&pm8150_gpios { ++ gpio-line-names = "VOL_DOWN_N", /* GPIO_1 */ ++ "OPTION_2", ++ "NC", ++ "PM_SLP_CLK_IN", ++ "OPTION_1", ++ "NC", ++ "NC", ++ "SP_ARI_PWR_ALARM", ++ "NC", ++ "NC"; /* GPIO_10 */ ++}; ++ ++&pm8150b_gpios { ++ gpio-line-names = "SNAPSHOT_N", /* GPIO_1 */ ++ "FOCUS_N", ++ "NC", ++ "NC", ++ "RF_LCD_ID_EN", ++ "NC", ++ "NC", ++ "LCD_ID", ++ "NC", ++ "WLC_EN_N", /* GPIO_10 */ ++ "NC", ++ "RF_ID"; ++}; ++ ++&pm8150l_gpios { ++ gpio-line-names = "NC", /* GPIO_1 */ ++ "PM3003A_EN", ++ "NC", ++ "NC", ++ "NC", ++ "AUX2_THERM", ++ "BB_HP_EN", ++ "FP_LDO_EN", ++ "PMX_RESET_N", ++ "AUX3_THERM", /* GPIO_10 */ ++ "DTV_PWR_EN", ++ "PM3003A_MODE"; ++}; ++ ++&tlmm { ++ gpio-line-names = "AP_CTI_IN", /* GPIO_0 */ ++ "MDM2AP_ERR_FATAL", ++ "AP_CTI_OUT", ++ "MDM2AP_STATUS", ++ "NFC_I2C_SDA", ++ "NFC_I2C_SCL", ++ "NFC_EN", ++ "NFC_CLK_REQ", ++ "NFC_ESE_PWR_REQ", ++ "DVDT_WRT_DET_AND", ++ "SPK_AMP_RESET_N", /* GPIO_10 */ ++ "SPK_AMP_INT_N", ++ "APPS_I2C_1_SDA", ++ "APPS_I2C_1_SCL", ++ "NC", ++ "TX_GTR_THRES_IN", ++ "HST_BT_UART_CTS", ++ "HST_BT_UART_RFR", ++ "HST_BT_UART_TX", ++ "HST_BT_UART_RX", ++ "HST_WLAN_EN", /* GPIO_20 */ ++ "HST_BT_EN", ++ "RGBC_IR_PWR_EN", ++ "FP_INT_N", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NFC_ESE_SPI_MISO", ++ "NFC_ESE_SPI_MOSI", ++ "NFC_ESE_SPI_SCLK", /* GPIO_30 */ ++ "NFC_ESE_SPI_CS_N", ++ "WCD_RST_N", ++ "NC", ++ "SDM_DEBUG_UART_TX", ++ "SDM_DEBUG_UART_RX", ++ "TS_I2C_SDA", ++ "TS_I2C_SCL", ++ "TS_INT_N", ++ "FP_SPI_MISO", /* GPIO_40 */ ++ "FP_SPI_MOSI", ++ "FP_SPI_SCLK", ++ "FP_SPI_CS_N", ++ "APPS_I2C_0_SDA", ++ "APPS_I2C_0_SCL", ++ "DISP_ERR_FG", ++ "UIM2_DETECT_EN", ++ "NC", ++ "NC", ++ "NC", /* GPIO_50 */ ++ "NC", ++ "MDM_UART_CTS", ++ "MDM_UART_RFR", ++ "MDM_UART_TX", ++ "MDM_UART_RX", ++ "AP2MDM_STATUS", ++ "AP2MDM_ERR_FATAL", ++ "MDM_IPC_HS_UART_TX", ++ "MDM_IPC_HS_UART_RX", ++ "NC", /* GPIO_60 */ ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "USB_CC_DIR", ++ "DISP_VSYNC", ++ "NC", ++ "NC", ++ "CAM_PWR_B_CS", ++ "NC", /* GPIO_70 */ ++ "CAM_PWR_A_CS", ++ "SBU_SW_SEL", ++ "SBU_SW_OE", ++ "FP_RESET_N", ++ "FP_RESET_N", ++ "DISP_RESET_N", ++ "DEBUG_GPIO0", ++ "TRAY_DET", ++ "CAM2_RST_N", ++ "PCIE0_RST_N", ++ "PCIE0_CLK_REQ_N", /* GPIO_80 */ ++ "PCIE0_WAKE_N", ++ "DVDT_ENABLE", ++ "DVDT_WRT_DET_OR", ++ "NC", ++ "PCIE2_RST_N", ++ "PCIE2_CLK_REQ_N", ++ "PCIE2_WAKE_N", ++ "MDM_VFR_IRQ0", ++ "MDM_VFR_IRQ1", ++ "SW_SERVICE", /* GPIO_90 */ ++ "CAM_SOF", ++ "CAM1_RST_N", ++ "CAM0_RST_N", ++ "CAM0_MCLK", ++ "CAM1_MCLK", ++ "CAM2_MCLK", ++ "CAM3_MCLK", ++ "CAM4_MCLK", ++ "TOF_RST_N", ++ "NC", /* GPIO_100 */ ++ "CCI0_I2C_SDA", ++ "CCI0_I2C_SCL", ++ "CCI1_I2C_SDA", ++ "CCI1_I2C_SCL_", ++ "CCI2_I2C_SDA", ++ "CCI2_I2C_SCL", ++ "CCI3_I2C_SDA", ++ "CCI3_I2C_SCL", ++ "CAM3_RST_N", ++ "NFC_DWL_REQ", /* GPIO_110 */ ++ "NFC_IRQ", ++ "XVS", ++ "NC", ++ "RF_ID_EXTENSION", ++ "SPK_AMP_I2C_SDA", ++ "SPK_AMP_I2C_SCL", ++ "NC", ++ "NC", ++ "WLC_I2C_SDA", ++ "WLC_I2C_SCL", /* GPIO_120 */ ++ "ACC_COVER_OPEN", ++ "ALS_PROX_INT_N", ++ "ACCEL_INT", ++ "WLAN_SW_CTRL", ++ "CAMSENSOR_I2C_SDA", ++ "CAMSENSOR_I2C_SCL", ++ "UDON_SWITCH_SEL", ++ "WDOG_DISABLE", ++ "BAROMETER_INT", ++ "NC", /* GPIO_130 */ ++ "NC", ++ "FORCED_USB_BOOT", ++ "NC", ++ "NC", ++ "WLC_INT_N", ++ "NC", ++ "NC", ++ "RGBC_IR_INT", ++ "NC", ++ "NC", /* GPIO_140 */ ++ "NC", ++ "BT_SLIMBUS_CLK", ++ "BT_SLIMBUS_DATA", ++ "HW_ID_0", ++ "HW_ID_1", ++ "WCD_SWR_TX_CLK", ++ "WCD_SWR_TX_DATA0", ++ "WCD_SWR_TX_DATA1", ++ "WCD_SWR_RX_CLK", ++ "WCD_SWR_RX_DATA0", /* GPIO_150 */ ++ "WCD_SWR_RX_DATA1", ++ "SDM_DMIC_CLK1", ++ "SDM_DMIC_DATA1", ++ "SDM_DMIC_CLK2", ++ "SDM_DMIC_DATA2", ++ "SPK_AMP_I2S_CLK", ++ "SPK_AMP_I2S_WS", ++ "SPK_AMP_I2S_ASP_DIN", ++ "SPK_AMP_I2S_ASP_DOUT", ++ "COMPASS_I2C_SDA", /* GPIO_160 */ ++ "COMPASS_I2C_SCL", ++ "NC", ++ "NC", ++ "SSC_SPI_1_MISO", ++ "SSC_SPI_1_MOSI", ++ "SSC_SPI_1_CLK", ++ "SSC_SPI_1_CS_N", ++ "NC", ++ "NC", ++ "SSC_SENSOR_I2C_SDA", /* GPIO_170 */ ++ "SSC_SENSOR_I2C_SCL", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "HST_BLE_SNS_UART6_TX", ++ "HST_BLE_SNS_UART6_RX", ++ "HST_WLAN_UART_TX", ++ "HST_WLAN_UART_RX"; ++}; +diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts +index 01fe3974ee720..58a521046f5f5 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts ++++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts +@@ -20,6 +20,8 @@ + }; + + &gpio_keys { ++ pinctrl-0 = <&focus_n &snapshot_n &vol_down_n &g_assist_n>; ++ + g-assist-key { + label = "Google Assistant Key"; + linux,code = <KEY_LEFTMETA>; +@@ -30,6 +32,247 @@ + }; + }; + ++&pm8009_gpios { ++ gpio-line-names = "NC", /* GPIO_1 */ ++ "NC", ++ "WIDEC_PWR_EN", ++ "NC"; ++}; ++ ++&pm8150_gpios { ++ gpio-line-names = "VOL_DOWN_N", /* GPIO_1 */ ++ "OPTION_2", ++ "NC", ++ "PM_SLP_CLK_IN", ++ "OPTION_1", ++ "G_ASSIST_N", ++ "NC", ++ "SP_ARI_PWR_ALARM", ++ "NC", ++ "NC"; /* GPIO_10 */ ++ ++ g_assist_n: g-assist-n-state { ++ pins = "gpio6"; ++ function = "normal"; ++ power-source = <1>; ++ bias-pull-up; ++ input-enable; ++ }; ++}; ++ ++&pm8150b_gpios { ++ gpio-line-names = "SNAPSHOT_N", /* GPIO_1 */ ++ "FOCUS_N", ++ "NC", ++ "NC", ++ "RF_LCD_ID_EN", ++ "NC", ++ "NC", ++ "LCD_ID", ++ "NC", ++ "NC", /* GPIO_10 */ ++ "NC", ++ "RF_ID"; ++}; ++ ++&pm8150l_gpios { ++ gpio-line-names = "NC", /* GPIO_1 */ ++ "PM3003A_EN", ++ "NC", ++ "NC", ++ "NC", ++ "AUX2_THERM", ++ "BB_HP_EN", ++ "FP_LDO_EN", ++ "PMX_RESET_N", ++ "NC", /* GPIO_10 */ ++ "NC", ++ "PM3003A_MODE"; ++}; ++ ++&tlmm { ++ gpio-line-names = "AP_CTI_IN", /* GPIO_0 */ ++ "MDM2AP_ERR_FATAL", ++ "AP_CTI_OUT", ++ "MDM2AP_STATUS", ++ "NFC_I2C_SDA", ++ "NFC_I2C_SCL", ++ "NFC_EN", ++ "NFC_CLK_REQ", ++ "NFC_ESE_PWR_REQ", ++ "DVDT_WRT_DET_AND", ++ "SPK_AMP_RESET_N", /* GPIO_10 */ ++ "SPK_AMP_INT_N", ++ "APPS_I2C_1_SDA", ++ "APPS_I2C_1_SCL", ++ "NC", ++ "TX_GTR_THRES_IN", ++ "HST_BT_UART_CTS", ++ "HST_BT_UART_RFR", ++ "HST_BT_UART_TX", ++ "HST_BT_UART_RX", ++ "HST_WLAN_EN", /* GPIO_20 */ ++ "HST_BT_EN", ++ "RGBC_IR_PWR_EN", ++ "FP_INT_N", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NFC_ESE_SPI_MISO", ++ "NFC_ESE_SPI_MOSI", ++ "NFC_ESE_SPI_SCLK", /* GPIO_30 */ ++ "NFC_ESE_SPI_CS_N", ++ "WCD_RST_N", ++ "NC", ++ "SDM_DEBUG_UART_TX", ++ "SDM_DEBUG_UART_RX", ++ "TS_I2C_SDA", ++ "TS_I2C_SCL", ++ "TS_INT_N", ++ "FP_SPI_MISO", /* GPIO_40 */ ++ "FP_SPI_MOSI", ++ "FP_SPI_SCLK", ++ "FP_SPI_CS_N", ++ "APPS_I2C_0_SDA", ++ "APPS_I2C_0_SCL", ++ "DISP_ERR_FG", ++ "UIM2_DETECT_EN", ++ "NC", ++ "NC", ++ "NC", /* GPIO_50 */ ++ "NC", ++ "MDM_UART_CTS", ++ "MDM_UART_RFR", ++ "MDM_UART_TX", ++ "MDM_UART_RX", ++ "AP2MDM_STATUS", ++ "AP2MDM_ERR_FATAL", ++ "MDM_IPC_HS_UART_TX", ++ "MDM_IPC_HS_UART_RX", ++ "NC", /* GPIO_60 */ ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "USB_CC_DIR", ++ "DISP_VSYNC", ++ "NC", ++ "NC", ++ "CAM_PWR_B_CS", ++ "NC", /* GPIO_70 */ ++ "FRONTC_PWR_EN", ++ "SBU_SW_SEL", ++ "SBU_SW_OE", ++ "FP_RESET_N", ++ "FP_RESET_N", ++ "DISP_RESET_N", ++ "DEBUG_GPIO0", ++ "TRAY_DET", ++ "CAM2_RST_N", ++ "PCIE0_RST_N", ++ "PCIE0_CLK_REQ_N", /* GPIO_80 */ ++ "PCIE0_WAKE_N", ++ "DVDT_ENABLE", ++ "DVDT_WRT_DET_OR", ++ "NC", ++ "PCIE2_RST_N", ++ "PCIE2_CLK_REQ_N", ++ "PCIE2_WAKE_N", ++ "MDM_VFR_IRQ0", ++ "MDM_VFR_IRQ1", ++ "SW_SERVICE", /* GPIO_90 */ ++ "CAM_SOF", ++ "CAM1_RST_N", ++ "CAM0_RST_N", ++ "CAM0_MCLK", ++ "CAM1_MCLK", ++ "CAM2_MCLK", ++ "CAM3_MCLK", ++ "NC", ++ "NC", ++ "NC", /* GPIO_100 */ ++ "CCI0_I2C_SDA", ++ "CCI0_I2C_SCL", ++ "CCI1_I2C_SDA", ++ "CCI1_I2C_SCL_", ++ "CCI2_I2C_SDA", ++ "CCI2_I2C_SCL", ++ "CCI3_I2C_SDA", ++ "CCI3_I2C_SCL", ++ "CAM3_RST_N", ++ "NFC_DWL_REQ", /* GPIO_110 */ ++ "NFC_IRQ", ++ "XVS", ++ "NC", ++ "RF_ID_EXTENSION", ++ "SPK_AMP_I2C_SDA", ++ "SPK_AMP_I2C_SCL", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "ACC_COVER_OPEN", ++ "ALS_PROX_INT_N", ++ "ACCEL_INT", ++ "WLAN_SW_CTRL", ++ "CAMSENSOR_I2C_SDA", ++ "CAMSENSOR_I2C_SCL", ++ "UDON_SWITCH_SEL", ++ "WDOG_DISABLE", ++ "BAROMETER_INT", ++ "NC", /* GPIO_130 */ ++ "NC", ++ "FORCED_USB_BOOT", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "RGBC_IR_INT", ++ "NC", ++ "NC", /* GPIO_140 */ ++ "NC", ++ "BT_SLIMBUS_CLK", ++ "BT_SLIMBUS_DATA", ++ "HW_ID_0", ++ "HW_ID_1", ++ "WCD_SWR_TX_CLK", ++ "WCD_SWR_TX_DATA0", ++ "WCD_SWR_TX_DATA1", ++ "WCD_SWR_RX_CLK", ++ "WCD_SWR_RX_DATA0", /* GPIO_150 */ ++ "WCD_SWR_RX_DATA1", ++ "SDM_DMIC_CLK1", ++ "SDM_DMIC_DATA1", ++ "SDM_DMIC_CLK2", ++ "SDM_DMIC_DATA2", ++ "SPK_AMP_I2S_CLK", ++ "SPK_AMP_I2S_WS", ++ "SPK_AMP_I2S_ASP_DIN", ++ "SPK_AMP_I2S_ASP_DOUT", ++ "COMPASS_I2C_SDA", /* GPIO_160 */ ++ "COMPASS_I2C_SCL", ++ "NC", ++ "NC", ++ "SSC_SPI_1_MISO", ++ "SSC_SPI_1_MOSI", ++ "SSC_SPI_1_CLK", ++ "SSC_SPI_1_CS_N", ++ "NC", ++ "NC", ++ "SSC_SENSOR_I2C_SDA", /* GPIO_170 */ ++ "SSC_SENSOR_I2C_SCL", ++ "NC", ++ "NC", ++ "NC", ++ "NC", ++ "HST_BLE_SNS_UART6_TX", ++ "HST_BLE_SNS_UART6_RX", ++ "HST_WLAN_UART_TX", ++ "HST_WLAN_UART_RX"; ++}; ++ + &vreg_l2f_1p3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; +diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi +index dcabb714f0f35..0268d80248e5c 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi +@@ -51,12 +51,26 @@ + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + +- /* +- * Camera focus (light press) and camera snapshot (full press) +- * seem not to work properly.. Adding the former one stalls the CPU +- * and the latter kills the volume down key for whatever reason. In any +- * case, they are both on &pm8150b_gpios: camera focus(2), camera snapshot(1). +- */ ++ pinctrl-0 = <&focus_n &snapshot_n &vol_down_n>; ++ pinctrl-names = "default"; ++ ++ key-camera-focus { ++ label = "Camera Focus"; ++ linux,code = <KEY_CAMERA_FOCUS>; ++ gpios = <&pm8150b_gpios 2 GPIO_ACTIVE_LOW>; ++ debounce-interval = <15>; ++ linux,can-disable; ++ wakeup-source; ++ }; ++ ++ key-camera-snapshot { ++ label = "Camera Snapshot"; ++ linux,code = <KEY_CAMERA>; ++ gpios = <&pm8150b_gpios 1 GPIO_ACTIVE_LOW>; ++ debounce-interval = <15>; ++ linux,can-disable; ++ wakeup-source; ++ }; + + key-vol-down { + label = "Volume Down"; +@@ -551,6 +565,34 @@ + vdda-pll-supply = <&vreg_l9a_1p2>; + }; + ++&pm8150_gpios { ++ vol_down_n: vol-down-n-state { ++ pins = "gpio1"; ++ function = "normal"; ++ power-source = <0>; ++ bias-pull-up; ++ input-enable; ++ }; ++}; ++ ++&pm8150b_gpios { ++ snapshot_n: snapshot-n-state { ++ pins = "gpio1"; ++ function = "normal"; ++ power-source = <0>; ++ bias-pull-up; ++ input-enable; ++ }; ++ ++ focus_n: focus-n-state { ++ pins = "gpio2"; ++ function = "normal"; ++ power-source = <0>; ++ bias-pull-up; ++ input-enable; ++ }; ++}; ++ + &pon_pwrkey { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index 7bea916900e29..29f0b0381b278 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -100,7 +100,7 @@ + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; + capacity-dmips-mhz = <448>; +- dynamic-power-coefficient = <205>; ++ dynamic-power-coefficient = <105>; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD0>; + power-domain-names = "psci"; +@@ -131,7 +131,7 @@ + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; + capacity-dmips-mhz = <448>; +- dynamic-power-coefficient = <205>; ++ dynamic-power-coefficient = <105>; + next-level-cache = <&L2_100>; + power-domains = <&CPU_PD1>; + power-domain-names = "psci"; +@@ -156,7 +156,7 @@ + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; + capacity-dmips-mhz = <448>; +- dynamic-power-coefficient = <205>; ++ dynamic-power-coefficient = <105>; + next-level-cache = <&L2_200>; + power-domains = <&CPU_PD2>; + power-domain-names = "psci"; +@@ -181,7 +181,7 @@ + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; + capacity-dmips-mhz = <448>; +- dynamic-power-coefficient = <205>; ++ dynamic-power-coefficient = <105>; + next-level-cache = <&L2_300>; + power-domains = <&CPU_PD3>; + power-domain-names = "psci"; +@@ -1905,6 +1905,7 @@ + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_default_state>; ++ dma-coherent; + + status = "disabled"; + }; +@@ -2011,6 +2012,7 @@ + + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_default_state>; ++ dma-coherent; + + status = "disabled"; + }; +@@ -2119,6 +2121,7 @@ + + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_default_state>; ++ dma-coherent; + + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi +index 425af2c38a37f..f375d960ba85c 100644 +--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi +@@ -48,7 +48,7 @@ + + CPU0: cpu@0 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; +@@ -72,7 +72,7 @@ + + CPU1: cpu@100 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; +@@ -91,7 +91,7 @@ + + CPU2: cpu@200 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; +@@ -110,7 +110,7 @@ + + CPU3: cpu@300 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + clocks = <&cpufreq_hw 0>; + enable-method = "psci"; +@@ -129,7 +129,7 @@ + + CPU4: cpu@400 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a78"; + reg = <0x0 0x400>; + clocks = <&cpufreq_hw 1>; + enable-method = "psci"; +@@ -148,7 +148,7 @@ + + CPU5: cpu@500 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a78"; + reg = <0x0 0x500>; + clocks = <&cpufreq_hw 1>; + enable-method = "psci"; +@@ -167,7 +167,7 @@ + + CPU6: cpu@600 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-a78"; + reg = <0x0 0x600>; + clocks = <&cpufreq_hw 1>; + enable-method = "psci"; +@@ -186,7 +186,7 @@ + + CPU7: cpu@700 { + device_type = "cpu"; +- compatible = "qcom,kryo685"; ++ compatible = "arm,cortex-x1"; + reg = <0x0 0x700>; + clocks = <&cpufreq_hw 2>; + enable-method = "psci"; +@@ -246,8 +246,8 @@ + compatible = "arm,idle-state"; + idle-state-name = "silver-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; +- entry-latency-us = <355>; +- exit-latency-us = <909>; ++ entry-latency-us = <360>; ++ exit-latency-us = <531>; + min-residency-us = <3934>; + local-timer-stop; + }; +@@ -256,8 +256,8 @@ + compatible = "arm,idle-state"; + idle-state-name = "gold-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; +- entry-latency-us = <241>; +- exit-latency-us = <1461>; ++ entry-latency-us = <702>; ++ exit-latency-us = <1061>; + min-residency-us = <4488>; + local-timer-stop; + }; +@@ -3339,6 +3339,13 @@ + <0 0x18593000 0 0x1000>; + reg-names = "freq-domain0", "freq-domain1", "freq-domain2"; + ++ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "dcvsh-irq-0", ++ "dcvsh-irq-1", ++ "dcvsh-irq-2"; ++ + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + +diff --git a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts +index e931545a2cac4..50306d070883d 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts ++++ b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts +@@ -14,7 +14,6 @@ + #include "pm8450.dtsi" + #include "pmk8350.dtsi" + #include "pmr735a.dtsi" +-#include "pmr735b.dtsi" + + / { + model = "Qualcomm Technologies, Inc. SM8450 HDK"; +diff --git a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts +index e2b9bb6b1e279..ea304d1e6f8f6 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts ++++ b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts +@@ -79,6 +79,7 @@ + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; ++ vdd-l1-l4-l10-supply = <&vreg_s6g_1p8>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l3-supply = <&vreg_s4g_1p3>; + vdd-l5-l16-supply = <&vreg_bob1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts +index d1f343345f674..6464ef4d113dd 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts +@@ -773,7 +773,7 @@ + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio0>; +- interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>; ++ interrupts = <RK_PA3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host-wake"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_l>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts +index cec3b7b1b9474..8a17c1eaae15e 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts +@@ -31,7 +31,7 @@ + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio0>; +- interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>; ++ interrupts = <RK_PA3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host-wake"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_l>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts b/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts +index 410cd3e5e7bca..538db870993d4 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts +@@ -416,7 +416,7 @@ + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio2>; +- interrupts = <RK_PB2 GPIO_ACTIVE_HIGH>; ++ interrupts = <RK_PB2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "host-wake"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_h>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts b/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts +index 63c4bd873188e..72ad74c38a2b4 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts +@@ -47,6 +47,9 @@ + vin-supply = <&vcc5v0_sys>; + }; + ++ /* actually fed by vcc5v0_sys, dependent ++ * on pi6c clock generator ++ */ + vcc3v3_minipcie: vcc3v3-minipcie-regulator { + compatible = "regulator-fixed"; + enable-active-high; +@@ -54,9 +57,9 @@ + pinctrl-names = "default"; + pinctrl-0 = <&minipcie_enable_h>; + regulator-name = "vcc3v3_minipcie"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- vin-supply = <&vcc5v0_sys>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vcc3v3_pi6c_05>; + }; + + vcc3v3_ngff: vcc3v3-ngff-regulator { +@@ -71,9 +74,6 @@ + vin-supply = <&vcc5v0_sys>; + }; + +- /* actually fed by vcc5v0_sys, dependent +- * on pi6c clock generator +- */ + vcc3v3_pcie30x1: vcc3v3-pcie30x1-regulator { + compatible = "regulator-fixed"; + enable-active-high; +@@ -83,7 +83,7 @@ + regulator-name = "vcc3v3_pcie30x1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +- vin-supply = <&vcc3v3_pi6c_05>; ++ vin-supply = <&vcc5v0_sys>; + }; + + vcc3v3_pi6c_05: vcc3v3-pi6c-05-regulator { +@@ -99,6 +99,10 @@ + }; + }; + ++&combphy1 { ++ phy-supply = <&vcc3v3_pcie30x1>; ++}; ++ + &pcie2x1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie20_reset_h>; +@@ -117,7 +121,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pcie30x1m0_pins>; + reset-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>; +- vpcie3v3-supply = <&vcc3v3_pcie30x1>; ++ vpcie3v3-supply = <&vcc3v3_minipcie>; + status = "okay"; + }; + +@@ -178,6 +182,10 @@ + status = "okay"; + }; + ++&sata1 { ++ status = "okay"; ++}; ++ + &sdmmc0 { + bus-width = <4>; + cap-sd-highspeed; +diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +index 976f8303c84f4..5629a13d9fc43 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +@@ -248,7 +248,7 @@ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; +- clock-frequency = <400000>; ++ clock-frequency = <100000>; + + tlv320aic3106: audio-codec@1b { + #sound-dai-cells = <0>; +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index e9169eb358c16..320c31cba0a43 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -60,7 +60,7 @@ + #interrupt-cells = <1>; + ti,sci = <&sms>; + ti,sci-dev-id = <10>; +- ti,interrupt-ranges = <8 360 56>; ++ ti,interrupt-ranges = <8 392 56>; + }; + + main_pmx0: pinctrl@11c000 { +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +index ed2b40369c59a..77208349eb22b 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +@@ -92,7 +92,7 @@ + #interrupt-cells = <1>; + ti,sci = <&sms>; + ti,sci-dev-id = <177>; +- ti,interrupt-ranges = <16 928 16>; ++ ti,interrupt-ranges = <16 960 16>; + }; + + mcu_conf: syscon@40f00000 { +diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig +index a24609e14d50e..fdfe54f35cf8e 100644 +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -1107,7 +1107,6 @@ CONFIG_XEN_GNTDEV=y + CONFIG_XEN_GRANT_DEV_ALLOC=y + CONFIG_STAGING=y + CONFIG_STAGING_MEDIA=y +-CONFIG_VIDEO_IMX_MEDIA=m + CONFIG_VIDEO_MAX96712=m + CONFIG_CHROME_PLATFORMS=y + CONFIG_CROS_EC=y +@@ -1159,6 +1158,7 @@ CONFIG_IPQ_GCC_8074=y + CONFIG_IPQ_GCC_9574=y + CONFIG_MSM_GCC_8916=y + CONFIG_MSM_GCC_8994=y ++CONFIG_MSM_GCC_8996=y + CONFIG_MSM_MMCC_8994=m + CONFIG_MSM_MMCC_8996=m + CONFIG_MSM_MMCC_8998=m +diff --git a/arch/arm64/include/asm/sdei.h b/arch/arm64/include/asm/sdei.h +index 4292d9bafb9d2..484cb6972e99a 100644 +--- a/arch/arm64/include/asm/sdei.h ++++ b/arch/arm64/include/asm/sdei.h +@@ -17,6 +17,9 @@ + + #include <asm/virt.h> + ++DECLARE_PER_CPU(struct sdei_registered_event *, sdei_active_normal_event); ++DECLARE_PER_CPU(struct sdei_registered_event *, sdei_active_critical_event); ++ + extern unsigned long sdei_exit_mode; + + /* Software Delegated Exception entry point from firmware*/ +@@ -29,6 +32,9 @@ asmlinkage void __sdei_asm_entry_trampoline(unsigned long event_num, + unsigned long pc, + unsigned long pstate); + ++/* Abort a running handler. Context is discarded. */ ++void __sdei_handler_abort(void); ++ + /* + * The above entry point does the minimum to call C code. This function does + * anything else, before calling the driver. +diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S +index ab2a6e33c0528..1b4a65a33186d 100644 +--- a/arch/arm64/kernel/entry.S ++++ b/arch/arm64/kernel/entry.S +@@ -1003,9 +1003,13 @@ SYM_CODE_START(__sdei_asm_handler) + + mov x19, x1 + +-#if defined(CONFIG_VMAP_STACK) || defined(CONFIG_SHADOW_CALL_STACK) ++ /* Store the registered-event for crash_smp_send_stop() */ + ldrb w4, [x19, #SDEI_EVENT_PRIORITY] +-#endif ++ cbnz w4, 1f ++ adr_this_cpu dst=x5, sym=sdei_active_normal_event, tmp=x6 ++ b 2f ++1: adr_this_cpu dst=x5, sym=sdei_active_critical_event, tmp=x6 ++2: str x19, [x5] + + #ifdef CONFIG_VMAP_STACK + /* +@@ -1072,6 +1076,14 @@ SYM_CODE_START(__sdei_asm_handler) + + ldr_l x2, sdei_exit_mode + ++ /* Clear the registered-event seen by crash_smp_send_stop() */ ++ ldrb w3, [x4, #SDEI_EVENT_PRIORITY] ++ cbnz w3, 1f ++ adr_this_cpu dst=x5, sym=sdei_active_normal_event, tmp=x6 ++ b 2f ++1: adr_this_cpu dst=x5, sym=sdei_active_critical_event, tmp=x6 ++2: str xzr, [x5] ++ + alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0 + sdei_handler_exit exit_mode=x2 + alternative_else_nop_endif +@@ -1082,4 +1094,15 @@ alternative_else_nop_endif + #endif + SYM_CODE_END(__sdei_asm_handler) + NOKPROBE(__sdei_asm_handler) ++ ++SYM_CODE_START(__sdei_handler_abort) ++ mov_q x0, SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME ++ adr x1, 1f ++ ldr_l x2, sdei_exit_mode ++ sdei_handler_exit exit_mode=x2 ++ // exit the handler and jump to the next instruction. ++ // Exit will stomp x0-x17, PSTATE, ELR_ELx, and SPSR_ELx. ++1: ret ++SYM_CODE_END(__sdei_handler_abort) ++NOKPROBE(__sdei_handler_abort) + #endif /* CONFIG_ARM_SDE_INTERFACE */ +diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c +index 087c05aa960ea..91e44ac7150f9 100644 +--- a/arch/arm64/kernel/fpsimd.c ++++ b/arch/arm64/kernel/fpsimd.c +@@ -1179,9 +1179,6 @@ void sve_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p) + */ + u64 read_zcr_features(void) + { +- u64 zcr; +- unsigned int vq_max; +- + /* + * Set the maximum possible VL, and write zeroes to all other + * bits to see if they stick. +@@ -1189,12 +1186,8 @@ u64 read_zcr_features(void) + sve_kernel_enable(NULL); + write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL1); + +- zcr = read_sysreg_s(SYS_ZCR_EL1); +- zcr &= ~(u64)ZCR_ELx_LEN_MASK; /* find sticky 1s outside LEN field */ +- vq_max = sve_vq_from_vl(sve_get_vl()); +- zcr |= vq_max - 1; /* set LEN field to maximum effective value */ +- +- return zcr; ++ /* Return LEN value that would be written to get the maximum VL */ ++ return sve_vq_from_vl(sve_get_vl()) - 1; + } + + void __init sve_setup(void) +@@ -1349,9 +1342,6 @@ void fa64_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p) + */ + u64 read_smcr_features(void) + { +- u64 smcr; +- unsigned int vq_max; +- + sme_kernel_enable(NULL); + + /* +@@ -1360,12 +1350,8 @@ u64 read_smcr_features(void) + write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_LEN_MASK, + SYS_SMCR_EL1); + +- smcr = read_sysreg_s(SYS_SMCR_EL1); +- smcr &= ~(u64)SMCR_ELx_LEN_MASK; /* Only the LEN field */ +- vq_max = sve_vq_from_vl(sme_get_vl()); +- smcr |= vq_max - 1; /* set LEN field to maximum effective value */ +- +- return smcr; ++ /* Return LEN value that would be written to get the maximum VL */ ++ return sve_vq_from_vl(sme_get_vl()) - 1; + } + + void __init sme_setup(void) +diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c +index 187aa2b175b4f..20d7ef82de90a 100644 +--- a/arch/arm64/kernel/ptrace.c ++++ b/arch/arm64/kernel/ptrace.c +@@ -891,7 +891,8 @@ static int sve_set_common(struct task_struct *target, + break; + default: + WARN_ON_ONCE(1); +- return -EINVAL; ++ ret = -EINVAL; ++ goto out; + } + + /* +diff --git a/arch/arm64/kernel/sdei.c b/arch/arm64/kernel/sdei.c +index 830be01af32db..255d12f881c26 100644 +--- a/arch/arm64/kernel/sdei.c ++++ b/arch/arm64/kernel/sdei.c +@@ -47,6 +47,9 @@ DEFINE_PER_CPU(unsigned long *, sdei_shadow_call_stack_normal_ptr); + DEFINE_PER_CPU(unsigned long *, sdei_shadow_call_stack_critical_ptr); + #endif + ++DEFINE_PER_CPU(struct sdei_registered_event *, sdei_active_normal_event); ++DEFINE_PER_CPU(struct sdei_registered_event *, sdei_active_critical_event); ++ + static void _free_sdei_stack(unsigned long * __percpu *ptr, int cpu) + { + unsigned long *p; +diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c +index d00d4cbb31b16..c6b882e589e69 100644 +--- a/arch/arm64/kernel/smp.c ++++ b/arch/arm64/kernel/smp.c +@@ -1048,10 +1048,8 @@ void crash_smp_send_stop(void) + * If this cpu is the only one alive at this point in time, online or + * not, there are no stop messages to be sent around, so just back out. + */ +- if (num_other_online_cpus() == 0) { +- sdei_mask_local_cpu(); +- return; +- } ++ if (num_other_online_cpus() == 0) ++ goto skip_ipi; + + cpumask_copy(&mask, cpu_online_mask); + cpumask_clear_cpu(smp_processor_id(), &mask); +@@ -1070,7 +1068,9 @@ void crash_smp_send_stop(void) + pr_warn("SMP: failed to stop secondary CPUs %*pbl\n", + cpumask_pr_args(&mask)); + ++skip_ipi: + sdei_mask_local_cpu(); ++ sdei_handler_abort(); + } + + bool smp_crash_stop_failed(void) +diff --git a/arch/arm64/lib/csum.c b/arch/arm64/lib/csum.c +index 78b87a64ca0a3..2432683e48a61 100644 +--- a/arch/arm64/lib/csum.c ++++ b/arch/arm64/lib/csum.c +@@ -24,7 +24,7 @@ unsigned int __no_sanitize_address do_csum(const unsigned char *buff, int len) + const u64 *ptr; + u64 data, sum64 = 0; + +- if (unlikely(len == 0)) ++ if (unlikely(len <= 0)) + return 0; + + offset = (unsigned long)buff & 7; +diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c +index 95364e8bdc194..50a8e7ab5fa94 100644 +--- a/arch/arm64/mm/hugetlbpage.c ++++ b/arch/arm64/mm/hugetlbpage.c +@@ -236,7 +236,7 @@ static void clear_flush(struct mm_struct *mm, + unsigned long i, saddr = addr; + + for (i = 0; i < ncontig; i++, addr += pgsize, ptep++) +- pte_clear(mm, addr, ptep); ++ ptep_clear(mm, addr, ptep); + + flush_tlb_range(&vma, saddr, addr); + } +diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile +index 63a637fdf6c28..95629322241f5 100644 +--- a/arch/loongarch/Makefile ++++ b/arch/loongarch/Makefile +@@ -106,7 +106,7 @@ KBUILD_CFLAGS += -isystem $(shell $(CC) -print-file-name=include) + + KBUILD_LDFLAGS += -m $(ld-emul) + +-ifdef CONFIG_LOONGARCH ++ifdef need-compiler + CHECKFLAGS += $(shell $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ + grep -E -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \ + sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g') +diff --git a/arch/loongarch/include/asm/fpu.h b/arch/loongarch/include/asm/fpu.h +index 192f8e35d9126..b1dc4200ae6a4 100644 +--- a/arch/loongarch/include/asm/fpu.h ++++ b/arch/loongarch/include/asm/fpu.h +@@ -117,16 +117,30 @@ static inline void restore_fp(struct task_struct *tsk) + _restore_fp(&tsk->thread.fpu); + } + +-static inline union fpureg *get_fpu_regs(struct task_struct *tsk) ++static inline void save_fpu_regs(struct task_struct *tsk) + { ++ unsigned int euen; ++ + if (tsk == current) { + preempt_disable(); +- if (is_fpu_owner()) ++ ++ euen = csr_read32(LOONGARCH_CSR_EUEN); ++ ++#ifdef CONFIG_CPU_HAS_LASX ++ if (euen & CSR_EUEN_LASXEN) ++ _save_lasx(¤t->thread.fpu); ++ else ++#endif ++#ifdef CONFIG_CPU_HAS_LSX ++ if (euen & CSR_EUEN_LSXEN) ++ _save_lsx(¤t->thread.fpu); ++ else ++#endif ++ if (euen & CSR_EUEN_FPEN) + _save_fp(¤t->thread.fpu); ++ + preempt_enable(); + } +- +- return tsk->thread.fpu.fpr; + } + + #endif /* _ASM_FPU_H */ +diff --git a/arch/loongarch/include/asm/local.h b/arch/loongarch/include/asm/local.h +index 83e995b30e472..c49675852bdcd 100644 +--- a/arch/loongarch/include/asm/local.h ++++ b/arch/loongarch/include/asm/local.h +@@ -63,8 +63,8 @@ static inline long local_cmpxchg(local_t *l, long old, long new) + + static inline bool local_try_cmpxchg(local_t *l, long *old, long new) + { +- typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; +- return try_cmpxchg_local(&l->a.counter, __old, new); ++ return try_cmpxchg_local(&l->a.counter, ++ (typeof(l->a.counter) *) old, new); + } + + #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) +diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h +index 9a9f9ff9b7098..5f71e789dcf68 100644 +--- a/arch/loongarch/include/asm/pgtable.h ++++ b/arch/loongarch/include/asm/pgtable.h +@@ -593,6 +593,9 @@ static inline long pmd_protnone(pmd_t pmd) + } + #endif /* CONFIG_NUMA_BALANCING */ + ++#define pmd_leaf(pmd) ((pmd_val(pmd) & _PAGE_HUGE) != 0) ++#define pud_leaf(pud) ((pud_val(pud) & _PAGE_HUGE) != 0) ++ + /* + * We provide our own get_unmapped area to cope with the virtual aliasing + * constraints placed on us by the cache architecture. +diff --git a/arch/loongarch/kernel/ptrace.c b/arch/loongarch/kernel/ptrace.c +index 5fcffb4523676..286c0ca39eae0 100644 +--- a/arch/loongarch/kernel/ptrace.c ++++ b/arch/loongarch/kernel/ptrace.c +@@ -147,6 +147,8 @@ static int fpr_get(struct task_struct *target, + { + int r; + ++ save_fpu_regs(target); ++ + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + r = gfpr_get(target, &to); + else +diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c +index 78a00359bde3c..9d830ab4e3025 100644 +--- a/arch/loongarch/kernel/setup.c ++++ b/arch/loongarch/kernel/setup.c +@@ -332,9 +332,25 @@ static void __init bootcmdline_init(char **cmdline_p) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + + strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE); ++ goto out; + } + #endif + ++ /* ++ * Append built-in command line to the bootloader command line if ++ * CONFIG_CMDLINE_EXTEND is enabled. ++ */ ++ if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) && CONFIG_CMDLINE[0]) { ++ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); ++ strlcat(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); ++ } ++ ++ /* ++ * Use built-in command line if the bootloader command line is empty. ++ */ ++ if (IS_ENABLED(CONFIG_CMDLINE_BOOTLOADER) && !boot_command_line[0]) ++ strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); ++ + out: + *cmdline_p = boot_command_line; + } +diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S +index 439395aa6fb42..081922c72daaa 100644 +--- a/arch/m68k/fpsp040/skeleton.S ++++ b/arch/m68k/fpsp040/skeleton.S +@@ -499,13 +499,13 @@ in_ea: + dbf %d0,morein + rts + +- .section .fixup,#alloc,#execinstr ++ .section .fixup,"ax" + .even + 1: + jbsr fpsp040_die + jbra .Lnotkern + +- .section __ex_table,#alloc ++ .section __ex_table,"a" + .align 4 + + .long in_ea,1b +diff --git a/arch/m68k/ifpsp060/os.S b/arch/m68k/ifpsp060/os.S +index 7a0d6e4280665..89e2ec224ab6c 100644 +--- a/arch/m68k/ifpsp060/os.S ++++ b/arch/m68k/ifpsp060/os.S +@@ -379,11 +379,11 @@ _060_real_access: + + + | Execption handling for movs access to illegal memory +- .section .fixup,#alloc,#execinstr ++ .section .fixup,"ax" + .even + 1: moveq #-1,%d1 + rts +-.section __ex_table,#alloc ++.section __ex_table,"a" + .align 4 + .long dmrbuae,1b + .long dmrwuae,1b +diff --git a/arch/m68k/kernel/relocate_kernel.S b/arch/m68k/kernel/relocate_kernel.S +index ab0f1e7d46535..f7667079e08e9 100644 +--- a/arch/m68k/kernel/relocate_kernel.S ++++ b/arch/m68k/kernel/relocate_kernel.S +@@ -26,7 +26,7 @@ ENTRY(relocate_new_kernel) + lea %pc@(.Lcopy),%a4 + 2: addl #0x00000000,%a4 /* virt_to_phys() */ + +- .section ".m68k_fixup","aw" ++ .section .m68k_fixup,"aw" + .long M68K_FIXUP_MEMOFFSET, 2b+2 + .previous + +@@ -49,7 +49,7 @@ ENTRY(relocate_new_kernel) + lea %pc@(.Lcont040),%a4 + 5: addl #0x00000000,%a4 /* virt_to_phys() */ + +- .section ".m68k_fixup","aw" ++ .section .m68k_fixup,"aw" + .long M68K_FIXUP_MEMOFFSET, 5b+2 + .previous + +diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h +index 5daf6fe8e3e9a..e6ae3df0349d2 100644 +--- a/arch/mips/include/asm/local.h ++++ b/arch/mips/include/asm/local.h +@@ -101,8 +101,8 @@ static __inline__ long local_cmpxchg(local_t *l, long old, long new) + + static __inline__ bool local_try_cmpxchg(local_t *l, long *old, long new) + { +- typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; +- return try_cmpxchg_local(&l->a.counter, __old, new); ++ return try_cmpxchg_local(&l->a.counter, ++ (typeof(l->a.counter) *) old, new); + } + + #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) +diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c +index ba07e760d3c76..25db0f8836f76 100644 +--- a/arch/parisc/kernel/processor.c ++++ b/arch/parisc/kernel/processor.c +@@ -377,10 +377,18 @@ int + show_cpuinfo (struct seq_file *m, void *v) + { + unsigned long cpu; ++ char cpu_name[60], *p; ++ ++ /* strip PA path from CPU name to not confuse lscpu */ ++ strlcpy(cpu_name, per_cpu(cpu_data, 0).dev->name, sizeof(cpu_name)); ++ p = strrchr(cpu_name, '['); ++ if (p) ++ *(--p) = 0; + + for_each_online_cpu(cpu) { +- const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); + #ifdef CONFIG_SMP ++ const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); ++ + if (0 == cpuinfo->hpa) + continue; + #endif +@@ -425,8 +433,7 @@ show_cpuinfo (struct seq_file *m, void *v) + + seq_printf(m, "model\t\t: %s - %s\n", + boot_cpu_data.pdc.sys_model_name, +- cpuinfo->dev ? +- cpuinfo->dev->name : "Unknown"); ++ cpu_name); + + seq_printf(m, "hversion\t: 0x%08x\n" + "sversion\t: 0x%08x\n", +diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h +index 91c049d51d0e1..2edc6269b1a35 100644 +--- a/arch/powerpc/include/asm/ftrace.h ++++ b/arch/powerpc/include/asm/ftrace.h +@@ -12,7 +12,7 @@ + + /* Ignore unused weak functions which will have larger offsets */ + #ifdef CONFIG_MPROFILE_KERNEL +-#define FTRACE_MCOUNT_MAX_OFFSET 12 ++#define FTRACE_MCOUNT_MAX_OFFSET 16 + #elif defined(CONFIG_PPC32) + #define FTRACE_MCOUNT_MAX_OFFSET 8 + #endif +diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h +index 34d44cb17c874..ee1488d38fdc1 100644 +--- a/arch/powerpc/include/asm/lppaca.h ++++ b/arch/powerpc/include/asm/lppaca.h +@@ -45,6 +45,7 @@ + #include <asm/types.h> + #include <asm/mmu.h> + #include <asm/firmware.h> ++#include <asm/paca.h> + + /* + * The lppaca is the "virtual processor area" registered with the hypervisor, +@@ -127,13 +128,23 @@ struct lppaca { + */ + #define LPPACA_OLD_SHARED_PROC 2 + +-static inline bool lppaca_shared_proc(struct lppaca *l) ++#ifdef CONFIG_PPC_PSERIES ++/* ++ * All CPUs should have the same shared proc value, so directly access the PACA ++ * to avoid false positives from DEBUG_PREEMPT. ++ */ ++static inline bool lppaca_shared_proc(void) + { ++ struct lppaca *l = local_paca->lppaca_ptr; ++ + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) + return false; + return !!(l->__old_status & LPPACA_OLD_SHARED_PROC); + } + ++#define get_lppaca() (get_paca()->lppaca_ptr) ++#endif ++ + /* + * SLB shadow buffer structure as defined in the PAPR. The save_area + * contains adjacent ESID and VSID pairs for each shadowed SLB. The +diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h +index da0377f465973..46ac4647b5fb9 100644 +--- a/arch/powerpc/include/asm/paca.h ++++ b/arch/powerpc/include/asm/paca.h +@@ -15,7 +15,6 @@ + #include <linux/cache.h> + #include <linux/string.h> + #include <asm/types.h> +-#include <asm/lppaca.h> + #include <asm/mmu.h> + #include <asm/page.h> + #ifdef CONFIG_PPC_BOOK3E_64 +@@ -47,14 +46,11 @@ extern unsigned int debug_smp_processor_id(void); /* from linux/smp.h */ + #define get_paca() local_paca + #endif + +-#ifdef CONFIG_PPC_PSERIES +-#define get_lppaca() (get_paca()->lppaca_ptr) +-#endif +- + #define get_slb_shadow() (get_paca()->slb_shadow_ptr) + + struct task_struct; + struct rtas_args; ++struct lppaca; + + /* + * Defines the layout of the paca. +diff --git a/arch/powerpc/include/asm/paravirt.h b/arch/powerpc/include/asm/paravirt.h +index f5ba1a3c41f8e..e08513d731193 100644 +--- a/arch/powerpc/include/asm/paravirt.h ++++ b/arch/powerpc/include/asm/paravirt.h +@@ -6,6 +6,7 @@ + #include <asm/smp.h> + #ifdef CONFIG_PPC64 + #include <asm/paca.h> ++#include <asm/lppaca.h> + #include <asm/hvcall.h> + #endif + +diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h +index 8239c0af5eb2b..fe3d0ea0058ac 100644 +--- a/arch/powerpc/include/asm/plpar_wrappers.h ++++ b/arch/powerpc/include/asm/plpar_wrappers.h +@@ -9,6 +9,7 @@ + + #include <asm/hvcall.h> + #include <asm/paca.h> ++#include <asm/lppaca.h> + #include <asm/page.h> + + static inline long poll_pending(void) +diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c +index ea0a073abd969..3ff2da7b120b5 100644 +--- a/arch/powerpc/kernel/fadump.c ++++ b/arch/powerpc/kernel/fadump.c +@@ -654,6 +654,7 @@ int __init fadump_reserve_mem(void) + return ret; + error_out: + fw_dump.fadump_enabled = 0; ++ fw_dump.reserve_dump_area_size = 0; + return 0; + } + +diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c +index 67f0b01e6ff57..400831307cd7b 100644 +--- a/arch/powerpc/kernel/iommu.c ++++ b/arch/powerpc/kernel/iommu.c +@@ -172,17 +172,28 @@ static int fail_iommu_bus_notify(struct notifier_block *nb, + return 0; + } + +-static struct notifier_block fail_iommu_bus_notifier = { ++/* ++ * PCI and VIO buses need separate notifier_block structs, since they're linked ++ * list nodes. Sharing a notifier_block would mean that any notifiers later ++ * registered for PCI buses would also get called by VIO buses and vice versa. ++ */ ++static struct notifier_block fail_iommu_pci_bus_notifier = { + .notifier_call = fail_iommu_bus_notify + }; + ++#ifdef CONFIG_IBMVIO ++static struct notifier_block fail_iommu_vio_bus_notifier = { ++ .notifier_call = fail_iommu_bus_notify ++}; ++#endif ++ + static int __init fail_iommu_setup(void) + { + #ifdef CONFIG_PCI +- bus_register_notifier(&pci_bus_type, &fail_iommu_bus_notifier); ++ bus_register_notifier(&pci_bus_type, &fail_iommu_pci_bus_notifier); + #endif + #ifdef CONFIG_IBMVIO +- bus_register_notifier(&vio_bus_type, &fail_iommu_bus_notifier); ++ bus_register_notifier(&vio_bus_type, &fail_iommu_vio_bus_notifier); + #endif + + return 0; +diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c +index ccfd969656306..82be6d87514b7 100644 +--- a/arch/powerpc/kvm/book3s_hv_ras.c ++++ b/arch/powerpc/kvm/book3s_hv_ras.c +@@ -9,6 +9,7 @@ + #include <linux/kvm.h> + #include <linux/kvm_host.h> + #include <linux/kernel.h> ++#include <asm/lppaca.h> + #include <asm/opal.h> + #include <asm/mce.h> + #include <asm/machdep.h> +diff --git a/arch/powerpc/mm/book3s64/radix_tlb.c b/arch/powerpc/mm/book3s64/radix_tlb.c +index 0bd4866d98241..9383606c5e6e0 100644 +--- a/arch/powerpc/mm/book3s64/radix_tlb.c ++++ b/arch/powerpc/mm/book3s64/radix_tlb.c +@@ -127,21 +127,6 @@ static __always_inline void __tlbie_pid(unsigned long pid, unsigned long ric) + trace_tlbie(0, 0, rb, rs, ric, prs, r); + } + +-static __always_inline void __tlbie_pid_lpid(unsigned long pid, +- unsigned long lpid, +- unsigned long ric) +-{ +- unsigned long rb, rs, prs, r; +- +- rb = PPC_BIT(53); /* IS = 1 */ +- rs = (pid << PPC_BITLSHIFT(31)) | (lpid & ~(PPC_BITMASK(0, 31))); +- prs = 1; /* process scoped */ +- r = 1; /* radix format */ +- +- asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) +- : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); +- trace_tlbie(0, 0, rb, rs, ric, prs, r); +-} + static __always_inline void __tlbie_lpid(unsigned long lpid, unsigned long ric) + { + unsigned long rb,rs,prs,r; +@@ -202,23 +187,6 @@ static __always_inline void __tlbie_va(unsigned long va, unsigned long pid, + trace_tlbie(0, 0, rb, rs, ric, prs, r); + } + +-static __always_inline void __tlbie_va_lpid(unsigned long va, unsigned long pid, +- unsigned long lpid, +- unsigned long ap, unsigned long ric) +-{ +- unsigned long rb, rs, prs, r; +- +- rb = va & ~(PPC_BITMASK(52, 63)); +- rb |= ap << PPC_BITLSHIFT(58); +- rs = (pid << PPC_BITLSHIFT(31)) | (lpid & ~(PPC_BITMASK(0, 31))); +- prs = 1; /* process scoped */ +- r = 1; /* radix format */ +- +- asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) +- : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); +- trace_tlbie(0, 0, rb, rs, ric, prs, r); +-} +- + static __always_inline void __tlbie_lpid_va(unsigned long va, unsigned long lpid, + unsigned long ap, unsigned long ric) + { +@@ -264,22 +232,6 @@ static inline void fixup_tlbie_va_range(unsigned long va, unsigned long pid, + } + } + +-static inline void fixup_tlbie_va_range_lpid(unsigned long va, +- unsigned long pid, +- unsigned long lpid, +- unsigned long ap) +-{ +- if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { +- asm volatile("ptesync" : : : "memory"); +- __tlbie_pid_lpid(0, lpid, RIC_FLUSH_TLB); +- } +- +- if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { +- asm volatile("ptesync" : : : "memory"); +- __tlbie_va_lpid(va, pid, lpid, ap, RIC_FLUSH_TLB); +- } +-} +- + static inline void fixup_tlbie_pid(unsigned long pid) + { + /* +@@ -299,26 +251,6 @@ static inline void fixup_tlbie_pid(unsigned long pid) + } + } + +-static inline void fixup_tlbie_pid_lpid(unsigned long pid, unsigned long lpid) +-{ +- /* +- * We can use any address for the invalidation, pick one which is +- * probably unused as an optimisation. +- */ +- unsigned long va = ((1UL << 52) - 1); +- +- if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { +- asm volatile("ptesync" : : : "memory"); +- __tlbie_pid_lpid(0, lpid, RIC_FLUSH_TLB); +- } +- +- if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { +- asm volatile("ptesync" : : : "memory"); +- __tlbie_va_lpid(va, pid, lpid, mmu_get_ap(MMU_PAGE_64K), +- RIC_FLUSH_TLB); +- } +-} +- + static inline void fixup_tlbie_lpid_va(unsigned long va, unsigned long lpid, + unsigned long ap) + { +@@ -416,31 +348,6 @@ static inline void _tlbie_pid(unsigned long pid, unsigned long ric) + asm volatile("eieio; tlbsync; ptesync": : :"memory"); + } + +-static inline void _tlbie_pid_lpid(unsigned long pid, unsigned long lpid, +- unsigned long ric) +-{ +- asm volatile("ptesync" : : : "memory"); +- +- /* +- * Workaround the fact that the "ric" argument to __tlbie_pid +- * must be a compile-time contraint to match the "i" constraint +- * in the asm statement. +- */ +- switch (ric) { +- case RIC_FLUSH_TLB: +- __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_TLB); +- fixup_tlbie_pid_lpid(pid, lpid); +- break; +- case RIC_FLUSH_PWC: +- __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC); +- break; +- case RIC_FLUSH_ALL: +- default: +- __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_ALL); +- fixup_tlbie_pid_lpid(pid, lpid); +- } +- asm volatile("eieio; tlbsync; ptesync" : : : "memory"); +-} + struct tlbiel_pid { + unsigned long pid; + unsigned long ric; +@@ -566,20 +473,6 @@ static inline void __tlbie_va_range(unsigned long start, unsigned long end, + fixup_tlbie_va_range(addr - page_size, pid, ap); + } + +-static inline void __tlbie_va_range_lpid(unsigned long start, unsigned long end, +- unsigned long pid, unsigned long lpid, +- unsigned long page_size, +- unsigned long psize) +-{ +- unsigned long addr; +- unsigned long ap = mmu_get_ap(psize); +- +- for (addr = start; addr < end; addr += page_size) +- __tlbie_va_lpid(addr, pid, lpid, ap, RIC_FLUSH_TLB); +- +- fixup_tlbie_va_range_lpid(addr - page_size, pid, lpid, ap); +-} +- + static __always_inline void _tlbie_va(unsigned long va, unsigned long pid, + unsigned long psize, unsigned long ric) + { +@@ -660,18 +553,6 @@ static inline void _tlbie_va_range(unsigned long start, unsigned long end, + asm volatile("eieio; tlbsync; ptesync": : :"memory"); + } + +-static inline void _tlbie_va_range_lpid(unsigned long start, unsigned long end, +- unsigned long pid, unsigned long lpid, +- unsigned long page_size, +- unsigned long psize, bool also_pwc) +-{ +- asm volatile("ptesync" : : : "memory"); +- if (also_pwc) +- __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC); +- __tlbie_va_range_lpid(start, end, pid, lpid, page_size, psize); +- asm volatile("eieio; tlbsync; ptesync" : : : "memory"); +-} +- + static inline void _tlbiel_va_range_multicast(struct mm_struct *mm, + unsigned long start, unsigned long end, + unsigned long pid, unsigned long page_size, +@@ -1486,6 +1367,127 @@ void radix__flush_tlb_all(void) + } + + #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE ++static __always_inline void __tlbie_pid_lpid(unsigned long pid, ++ unsigned long lpid, ++ unsigned long ric) ++{ ++ unsigned long rb, rs, prs, r; ++ ++ rb = PPC_BIT(53); /* IS = 1 */ ++ rs = (pid << PPC_BITLSHIFT(31)) | (lpid & ~(PPC_BITMASK(0, 31))); ++ prs = 1; /* process scoped */ ++ r = 1; /* radix format */ ++ ++ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) ++ : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); ++ trace_tlbie(0, 0, rb, rs, ric, prs, r); ++} ++ ++static __always_inline void __tlbie_va_lpid(unsigned long va, unsigned long pid, ++ unsigned long lpid, ++ unsigned long ap, unsigned long ric) ++{ ++ unsigned long rb, rs, prs, r; ++ ++ rb = va & ~(PPC_BITMASK(52, 63)); ++ rb |= ap << PPC_BITLSHIFT(58); ++ rs = (pid << PPC_BITLSHIFT(31)) | (lpid & ~(PPC_BITMASK(0, 31))); ++ prs = 1; /* process scoped */ ++ r = 1; /* radix format */ ++ ++ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) ++ : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); ++ trace_tlbie(0, 0, rb, rs, ric, prs, r); ++} ++ ++static inline void fixup_tlbie_pid_lpid(unsigned long pid, unsigned long lpid) ++{ ++ /* ++ * We can use any address for the invalidation, pick one which is ++ * probably unused as an optimisation. ++ */ ++ unsigned long va = ((1UL << 52) - 1); ++ ++ if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { ++ asm volatile("ptesync" : : : "memory"); ++ __tlbie_pid_lpid(0, lpid, RIC_FLUSH_TLB); ++ } ++ ++ if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { ++ asm volatile("ptesync" : : : "memory"); ++ __tlbie_va_lpid(va, pid, lpid, mmu_get_ap(MMU_PAGE_64K), ++ RIC_FLUSH_TLB); ++ } ++} ++ ++static inline void _tlbie_pid_lpid(unsigned long pid, unsigned long lpid, ++ unsigned long ric) ++{ ++ asm volatile("ptesync" : : : "memory"); ++ ++ /* ++ * Workaround the fact that the "ric" argument to __tlbie_pid ++ * must be a compile-time contraint to match the "i" constraint ++ * in the asm statement. ++ */ ++ switch (ric) { ++ case RIC_FLUSH_TLB: ++ __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_TLB); ++ fixup_tlbie_pid_lpid(pid, lpid); ++ break; ++ case RIC_FLUSH_PWC: ++ __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC); ++ break; ++ case RIC_FLUSH_ALL: ++ default: ++ __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_ALL); ++ fixup_tlbie_pid_lpid(pid, lpid); ++ } ++ asm volatile("eieio; tlbsync; ptesync" : : : "memory"); ++} ++ ++static inline void fixup_tlbie_va_range_lpid(unsigned long va, ++ unsigned long pid, ++ unsigned long lpid, ++ unsigned long ap) ++{ ++ if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { ++ asm volatile("ptesync" : : : "memory"); ++ __tlbie_pid_lpid(0, lpid, RIC_FLUSH_TLB); ++ } ++ ++ if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { ++ asm volatile("ptesync" : : : "memory"); ++ __tlbie_va_lpid(va, pid, lpid, ap, RIC_FLUSH_TLB); ++ } ++} ++ ++static inline void __tlbie_va_range_lpid(unsigned long start, unsigned long end, ++ unsigned long pid, unsigned long lpid, ++ unsigned long page_size, ++ unsigned long psize) ++{ ++ unsigned long addr; ++ unsigned long ap = mmu_get_ap(psize); ++ ++ for (addr = start; addr < end; addr += page_size) ++ __tlbie_va_lpid(addr, pid, lpid, ap, RIC_FLUSH_TLB); ++ ++ fixup_tlbie_va_range_lpid(addr - page_size, pid, lpid, ap); ++} ++ ++static inline void _tlbie_va_range_lpid(unsigned long start, unsigned long end, ++ unsigned long pid, unsigned long lpid, ++ unsigned long page_size, ++ unsigned long psize, bool also_pwc) ++{ ++ asm volatile("ptesync" : : : "memory"); ++ if (also_pwc) ++ __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC); ++ __tlbie_va_range_lpid(start, end, pid, lpid, page_size, psize); ++ asm volatile("eieio; tlbsync; ptesync" : : : "memory"); ++} ++ + /* + * Performs process-scoped invalidations for a given LPID + * as part of H_RPT_INVALIDATE hcall. +diff --git a/arch/powerpc/mm/book3s64/slb.c b/arch/powerpc/mm/book3s64/slb.c +index 6956f637a38c1..f2708c8629a52 100644 +--- a/arch/powerpc/mm/book3s64/slb.c ++++ b/arch/powerpc/mm/book3s64/slb.c +@@ -13,6 +13,7 @@ + #include <asm/mmu.h> + #include <asm/mmu_context.h> + #include <asm/paca.h> ++#include <asm/lppaca.h> + #include <asm/ppc-opcode.h> + #include <asm/cputable.h> + #include <asm/cacheflush.h> +diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c +index ee721f420a7ba..1a53ab08447cb 100644 +--- a/arch/powerpc/perf/core-fsl-emb.c ++++ b/arch/powerpc/perf/core-fsl-emb.c +@@ -645,7 +645,6 @@ static void perf_event_interrupt(struct pt_regs *regs) + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct perf_event *event; + unsigned long val; +- int found = 0; + + for (i = 0; i < ppmu->n_counter; ++i) { + event = cpuhw->event[i]; +@@ -654,7 +653,6 @@ static void perf_event_interrupt(struct pt_regs *regs) + if ((int)val < 0) { + if (event) { + /* event has overflowed */ +- found = 1; + record_and_restart(event, val, regs); + } else { + /* +@@ -672,11 +670,13 @@ static void perf_event_interrupt(struct pt_regs *regs) + isync(); + } + +-void hw_perf_event_setup(int cpu) ++static int fsl_emb_pmu_prepare_cpu(unsigned int cpu) + { + struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu); + + memset(cpuhw, 0, sizeof(*cpuhw)); ++ ++ return 0; + } + + int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu) +@@ -689,6 +689,8 @@ int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu) + pmu->name); + + perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW); ++ cpuhp_setup_state(CPUHP_PERF_POWER, "perf/powerpc:prepare", ++ fsl_emb_pmu_prepare_cpu, NULL); + + return 0; + } +diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c +index 4c5790aff1b54..8633891b7aa58 100644 +--- a/arch/powerpc/platforms/powermac/time.c ++++ b/arch/powerpc/platforms/powermac/time.c +@@ -26,8 +26,8 @@ + #include <linux/rtc.h> + #include <linux/of_address.h> + ++#include <asm/early_ioremap.h> + #include <asm/sections.h> +-#include <asm/io.h> + #include <asm/machdep.h> + #include <asm/time.h> + #include <asm/nvram.h> +@@ -182,7 +182,7 @@ static int __init via_calibrate_decr(void) + return 0; + } + of_node_put(vias); +- via = ioremap(rsrc.start, resource_size(&rsrc)); ++ via = early_ioremap(rsrc.start, resource_size(&rsrc)); + if (via == NULL) { + printk(KERN_ERR "Failed to map VIA for timer calibration !\n"); + return 0; +@@ -207,7 +207,7 @@ static int __init via_calibrate_decr(void) + + ppc_tb_freq = (dstart - dend) * 100 / 6; + +- iounmap(via); ++ early_iounmap((void *)via, resource_size(&rsrc)); + + return 1; + } +diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S +index 35254ac7af5ee..ca0674b0b683e 100644 +--- a/arch/powerpc/platforms/pseries/hvCall.S ++++ b/arch/powerpc/platforms/pseries/hvCall.S +@@ -91,6 +91,7 @@ BEGIN_FTR_SECTION; \ + b 1f; \ + END_FTR_SECTION(0, 1); \ + LOAD_REG_ADDR(r12, hcall_tracepoint_refcount) ; \ ++ ld r12,0(r12); \ + std r12,32(r1); \ + cmpdi r12,0; \ + bne- LABEL; \ +diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c +index 2eab323f69706..cb2f1211f7ebf 100644 +--- a/arch/powerpc/platforms/pseries/lpar.c ++++ b/arch/powerpc/platforms/pseries/lpar.c +@@ -639,16 +639,8 @@ static const struct proc_ops vcpudispatch_stats_freq_proc_ops = { + + static int __init vcpudispatch_stats_procfs_init(void) + { +- /* +- * Avoid smp_processor_id while preemptible. All CPUs should have +- * the same value for lppaca_shared_proc. +- */ +- preempt_disable(); +- if (!lppaca_shared_proc(get_lppaca())) { +- preempt_enable(); ++ if (!lppaca_shared_proc()) + return 0; +- } +- preempt_enable(); + + if (!proc_create("powerpc/vcpudispatch_stats", 0600, NULL, + &vcpudispatch_stats_proc_ops)) +diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c +index 8acc705095209..1c151d77e74b3 100644 +--- a/arch/powerpc/platforms/pseries/lparcfg.c ++++ b/arch/powerpc/platforms/pseries/lparcfg.c +@@ -206,7 +206,7 @@ static void parse_ppp_data(struct seq_file *m) + ppp_data.active_system_procs); + + /* pool related entries are appropriate for shared configs */ +- if (lppaca_shared_proc(get_lppaca())) { ++ if (lppaca_shared_proc()) { + unsigned long pool_idle_time, pool_procs; + + seq_printf(m, "pool=%d\n", ppp_data.pool_num); +@@ -560,7 +560,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) + partition_potential_processors); + + seq_printf(m, "shared_processor_mode=%d\n", +- lppaca_shared_proc(get_lppaca())); ++ lppaca_shared_proc()); + + #ifdef CONFIG_PPC_64S_HASH_MMU + if (!radix_enabled()) +diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c +index e2a57cfa6c837..0ef2a7e014aa1 100644 +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -847,7 +847,7 @@ static void __init pSeries_setup_arch(void) + if (firmware_has_feature(FW_FEATURE_LPAR)) { + vpa_init(boot_cpuid); + +- if (lppaca_shared_proc(get_lppaca())) { ++ if (lppaca_shared_proc()) { + static_branch_enable(&shared_processor); + pv_spinlocks_init(); + #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING +diff --git a/arch/powerpc/sysdev/mpc5xxx_clocks.c b/arch/powerpc/sysdev/mpc5xxx_clocks.c +index c5bf7e1b37804..58cee28e23992 100644 +--- a/arch/powerpc/sysdev/mpc5xxx_clocks.c ++++ b/arch/powerpc/sysdev/mpc5xxx_clocks.c +@@ -25,8 +25,10 @@ unsigned long mpc5xxx_fwnode_get_bus_frequency(struct fwnode_handle *fwnode) + + fwnode_for_each_parent_node(fwnode, parent) { + ret = fwnode_property_read_u32(parent, "bus-frequency", &bus_freq); +- if (!ret) ++ if (!ret) { ++ fwnode_handle_put(parent); + return bus_freq; ++ } + } + + return 0; +diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c +index 70c4c59a1a8f4..70ce51b8a9291 100644 +--- a/arch/powerpc/xmon/xmon.c ++++ b/arch/powerpc/xmon/xmon.c +@@ -58,6 +58,7 @@ + #ifdef CONFIG_PPC64 + #include <asm/hvcall.h> + #include <asm/paca.h> ++#include <asm/lppaca.h> + #endif + + #include "nonstdio.h" +diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c +index a01bc15dce244..5e39dcf23fdbc 100644 +--- a/arch/riscv/mm/kasan_init.c ++++ b/arch/riscv/mm/kasan_init.c +@@ -22,9 +22,9 @@ + * region is not and then we have to go down to the PUD level. + */ + +-pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss; +-p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss; +-pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss; ++static pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss; ++static p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss; ++static pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss; + + static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end) + { +@@ -438,7 +438,7 @@ static void __init kasan_shallow_populate(void *start, void *end) + kasan_shallow_populate_pgd(vaddr, vend); + } + +-static void create_tmp_mapping(void) ++static void __init create_tmp_mapping(void) + { + void *ptr; + p4d_t *base_p4d; +diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c +index 29dc827e0fe81..143ae4d4284db 100644 +--- a/arch/s390/crypto/paes_s390.c ++++ b/arch/s390/crypto/paes_s390.c +@@ -35,7 +35,7 @@ + * and padding is also possible, the limits need to be generous. + */ + #define PAES_MIN_KEYSIZE 16 +-#define PAES_MAX_KEYSIZE 320 ++#define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE + + static u8 *ctrblk; + static DEFINE_MUTEX(ctrblk_lock); +diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h +index 924b876f992c1..29c6fd369761e 100644 +--- a/arch/s390/include/uapi/asm/pkey.h ++++ b/arch/s390/include/uapi/asm/pkey.h +@@ -26,7 +26,7 @@ + #define MAXCLRKEYSIZE 32 /* a clear key value may be up to 32 bytes */ + #define MAXAESCIPHERKEYSIZE 136 /* our aes cipher keys have always 136 bytes */ + #define MINEP11AESKEYBLOBSIZE 256 /* min EP11 AES key blob size */ +-#define MAXEP11AESKEYBLOBSIZE 320 /* max EP11 AES key blob size */ ++#define MAXEP11AESKEYBLOBSIZE 336 /* max EP11 AES key blob size */ + + /* Minimum size of a key blob */ + #define MINKEYBLOBSIZE SECKEYBLOBSIZE +diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c +index f44f70de96611..9d74b037b3a3b 100644 +--- a/arch/s390/kernel/ipl.c ++++ b/arch/s390/kernel/ipl.c +@@ -638,6 +638,8 @@ static struct attribute_group ipl_ccw_attr_group_lpar = { + + static struct attribute *ipl_unknown_attrs[] = { + &sys_ipl_type_attr.attr, ++ &sys_ipl_secure_attr.attr, ++ &sys_ipl_has_secure_attr.attr, + NULL, + }; + +diff --git a/arch/um/configs/i386_defconfig b/arch/um/configs/i386_defconfig +index c0162286d68b7..c33a6880a437a 100644 +--- a/arch/um/configs/i386_defconfig ++++ b/arch/um/configs/i386_defconfig +@@ -35,6 +35,7 @@ CONFIG_TTY_CHAN=y + CONFIG_XTERM_CHAN=y + CONFIG_CON_CHAN="pts" + CONFIG_SSL_CHAN="pts" ++CONFIG_SOUND=m + CONFIG_UML_SOUND=m + CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y +diff --git a/arch/um/configs/x86_64_defconfig b/arch/um/configs/x86_64_defconfig +index bec6e5d956873..df29f282b6ac2 100644 +--- a/arch/um/configs/x86_64_defconfig ++++ b/arch/um/configs/x86_64_defconfig +@@ -33,6 +33,7 @@ CONFIG_TTY_CHAN=y + CONFIG_XTERM_CHAN=y + CONFIG_CON_CHAN="pts" + CONFIG_SSL_CHAN="pts" ++CONFIG_SOUND=m + CONFIG_UML_SOUND=m + CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y +diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig +index 36911b1fddcf0..b94b2618e7d84 100644 +--- a/arch/um/drivers/Kconfig ++++ b/arch/um/drivers/Kconfig +@@ -111,24 +111,14 @@ config SSL_CHAN + + config UML_SOUND + tristate "Sound support" ++ depends on SOUND ++ select SOUND_OSS_CORE + help + This option enables UML sound support. If enabled, it will pull in +- soundcore and the UML hostaudio relay, which acts as a intermediary ++ the UML hostaudio relay, which acts as a intermediary + between the host's dsp and mixer devices and the UML sound system. + It is safe to say 'Y' here. + +-config SOUND +- tristate +- default UML_SOUND +- +-config SOUND_OSS_CORE +- bool +- default UML_SOUND +- +-config HOSTAUDIO +- tristate +- default UML_SOUND +- + endmenu + + menu "UML Network Devices" +diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile +index a461a950f0518..0e6af81096fd5 100644 +--- a/arch/um/drivers/Makefile ++++ b/arch/um/drivers/Makefile +@@ -54,7 +54,7 @@ obj-$(CONFIG_UML_NET) += net.o + obj-$(CONFIG_MCONSOLE) += mconsole.o + obj-$(CONFIG_MMAPPER) += mmapper_kern.o + obj-$(CONFIG_BLK_DEV_UBD) += ubd.o +-obj-$(CONFIG_HOSTAUDIO) += hostaudio.o ++obj-$(CONFIG_UML_SOUND) += hostaudio.o + obj-$(CONFIG_NULL_CHAN) += null.o + obj-$(CONFIG_PORT_CHAN) += port.o + obj-$(CONFIG_PTY_CHAN) += pty.o +diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c +index 7699ca5f35d48..ffe2ee8a02465 100644 +--- a/arch/um/drivers/virt-pci.c ++++ b/arch/um/drivers/virt-pci.c +@@ -544,6 +544,7 @@ static void um_pci_irq_vq_cb(struct virtqueue *vq) + } + } + ++#ifdef CONFIG_OF + /* Copied from arch/x86/kernel/devicetree.c */ + struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) + { +@@ -562,6 +563,7 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) + } + return NULL; + } ++#endif + + static int um_pci_init_vqs(struct um_pci_device *dev) + { +diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S +index 03c4328a88cbd..f732426d3b483 100644 +--- a/arch/x86/boot/compressed/head_64.S ++++ b/arch/x86/boot/compressed/head_64.S +@@ -459,11 +459,25 @@ SYM_CODE_START(startup_64) + /* Save the trampoline address in RCX */ + movq %rax, %rcx + ++ /* Set up 32-bit addressable stack */ ++ leaq TRAMPOLINE_32BIT_STACK_END(%rcx), %rsp ++ ++ /* ++ * Preserve live 64-bit registers on the stack: this is necessary ++ * because the architecture does not guarantee that GPRs will retain ++ * their full 64-bit values across a 32-bit mode switch. ++ */ ++ pushq %rbp ++ pushq %rbx ++ pushq %rsi ++ + /* +- * Load the address of trampoline_return() into RDI. +- * It will be used by the trampoline to return to the main code. ++ * Push the 64-bit address of trampoline_return() onto the new stack. ++ * It will be used by the trampoline to return to the main code. Due to ++ * the 32-bit mode switch, it cannot be kept it in a register either. + */ + leaq trampoline_return(%rip), %rdi ++ pushq %rdi + + /* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */ + pushq $__KERNEL32_CS +@@ -471,6 +485,11 @@ SYM_CODE_START(startup_64) + pushq %rax + lretq + trampoline_return: ++ /* Restore live 64-bit registers */ ++ popq %rsi ++ popq %rbx ++ popq %rbp ++ + /* Restore the stack, the 32-bit trampoline uses its own stack */ + leaq rva(boot_stack_end)(%rbx), %rsp + +@@ -582,7 +601,7 @@ SYM_FUNC_END(.Lrelocated) + /* + * This is the 32-bit trampoline that will be copied over to low memory. + * +- * RDI contains the return address (might be above 4G). ++ * Return address is at the top of the stack (might be above 4G). + * ECX contains the base address of the trampoline memory. + * Non zero RDX means trampoline needs to enable 5-level paging. + */ +@@ -592,9 +611,6 @@ SYM_CODE_START(trampoline_32bit_src) + movl %eax, %ds + movl %eax, %ss + +- /* Set up new stack */ +- leal TRAMPOLINE_32BIT_STACK_END(%ecx), %esp +- + /* Disable paging */ + movl %cr0, %eax + btrl $X86_CR0_PG_BIT, %eax +@@ -671,7 +687,7 @@ SYM_CODE_END(trampoline_32bit_src) + .code64 + SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled) + /* Return from the trampoline */ +- jmp *%rdi ++ retq + SYM_FUNC_END(.Lpaging_enabled) + + /* +diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c +index d49e90dc04a4c..847740c08c97d 100644 +--- a/arch/x86/events/intel/uncore_snbep.c ++++ b/arch/x86/events/intel/uncore_snbep.c +@@ -6474,8 +6474,18 @@ void spr_uncore_cpu_init(void) + + type = uncore_find_type_by_id(uncore_msr_uncores, UNCORE_SPR_CHA); + if (type) { ++ /* ++ * The value from the discovery table (stored in the type->num_boxes ++ * of UNCORE_SPR_CHA) is incorrect on some SPR variants because of a ++ * firmware bug. Using the value from SPR_MSR_UNC_CBO_CONFIG to replace it. ++ */ + rdmsrl(SPR_MSR_UNC_CBO_CONFIG, num_cbo); +- type->num_boxes = num_cbo; ++ /* ++ * The MSR doesn't work on the EMR XCC, but the firmware bug doesn't impact ++ * the EMR XCC. Don't let the value from the MSR replace the existing value. ++ */ ++ if (num_cbo) ++ type->num_boxes = num_cbo; + } + spr_uncore_iio_free_running.num_boxes = uncore_type_max_boxes(uncore_msr_uncores, UNCORE_SPR_IIO); + } +diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c +index 85d38b9f35861..db5d2ea39fc0d 100644 +--- a/arch/x86/hyperv/hv_vtl.c ++++ b/arch/x86/hyperv/hv_vtl.c +@@ -25,6 +25,10 @@ void __init hv_vtl_init_platform(void) + x86_init.irqs.pre_vector_init = x86_init_noop; + x86_init.timers.timer_init = x86_init_noop; + ++ /* Avoid searching for BIOS MP tables */ ++ x86_init.mpparse.find_smp_config = x86_init_noop; ++ x86_init.mpparse.get_smp_config = x86_init_uint_noop; ++ + x86_platform.get_wallclock = get_rtc_noop; + x86_platform.set_wallclock = set_rtc_noop; + x86_platform.get_nmi_reason = hv_get_nmi_reason; +diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h +index 56d4ef604b919..635132a127782 100644 +--- a/arch/x86/include/asm/local.h ++++ b/arch/x86/include/asm/local.h +@@ -127,8 +127,8 @@ static inline long local_cmpxchg(local_t *l, long old, long new) + + static inline bool local_try_cmpxchg(local_t *l, long *old, long new) + { +- typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; +- return try_cmpxchg_local(&l->a.counter, __old, new); ++ return try_cmpxchg_local(&l->a.counter, ++ (typeof(l->a.counter) *) old, new); + } + + /* Always has a lock prefix */ +diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h +index 7f97a8a97e24a..473b16d73b471 100644 +--- a/arch/x86/include/asm/mem_encrypt.h ++++ b/arch/x86/include/asm/mem_encrypt.h +@@ -50,8 +50,8 @@ void __init sme_enable(struct boot_params *bp); + + int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size); + int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size); +-void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, +- bool enc); ++void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, ++ unsigned long size, bool enc); + + void __init mem_encrypt_free_decrypted_mem(void); + +@@ -85,7 +85,7 @@ early_set_memory_decrypted(unsigned long vaddr, unsigned long size) { return 0; + static inline int __init + early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; } + static inline void __init +-early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) {} ++early_set_mem_enc_dec_hypercall(unsigned long vaddr, unsigned long size, bool enc) {} + + static inline void mem_encrypt_free_decrypted_mem(void) { } + +diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h +index 447d4bee25c48..97533e6b1c61b 100644 +--- a/arch/x86/include/asm/pgtable_types.h ++++ b/arch/x86/include/asm/pgtable_types.h +@@ -125,11 +125,12 @@ + * instance, and is *not* included in this mask since + * pte_modify() does modify it. + */ +-#define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ +- _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \ +- _PAGE_SOFT_DIRTY | _PAGE_DEVMAP | _PAGE_ENC | \ +- _PAGE_UFFD_WP) +-#define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE) ++#define _COMMON_PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ ++ _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY |\ ++ _PAGE_SOFT_DIRTY | _PAGE_DEVMAP | _PAGE_ENC | \ ++ _PAGE_UFFD_WP) ++#define _PAGE_CHG_MASK (_COMMON_PAGE_CHG_MASK | _PAGE_PAT) ++#define _HPAGE_CHG_MASK (_COMMON_PAGE_CHG_MASK | _PAGE_PSE | _PAGE_PAT_LARGE) + + /* + * The cache modes defined here are used to translate between pure SW usage +diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c +index c6c15ce1952fb..5934ee5bc087e 100644 +--- a/arch/x86/kernel/apm_32.c ++++ b/arch/x86/kernel/apm_32.c +@@ -238,12 +238,6 @@ + extern int (*console_blank_hook)(int); + #endif + +-/* +- * The apm_bios device is one of the misc char devices. +- * This is its minor number. +- */ +-#define APM_MINOR_DEV 134 +- + /* + * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index 19c74e68c0a21..aa26c2bb70259 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -1282,11 +1282,11 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(BROADWELL_G, X86_STEPPING_ANY, SRBDS), + VULNBL_INTEL_STEPPINGS(BROADWELL_X, X86_STEPPING_ANY, MMIO), + VULNBL_INTEL_STEPPINGS(BROADWELL, X86_STEPPING_ANY, SRBDS), +- VULNBL_INTEL_STEPPINGS(SKYLAKE_L, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED), + VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(SKYLAKE, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED), +- VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(SKYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(SKYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), + VULNBL_INTEL_STEPPINGS(CANNONLAKE_L, X86_STEPPING_ANY, RETBLEED), + VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), + VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO | GDS), +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index 2eec60f50057a..00a7fdac7f89d 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -842,6 +842,26 @@ static noinstr bool quirk_skylake_repmov(void) + return false; + } + ++/* ++ * Some Zen-based Instruction Fetch Units set EIPV=RIPV=0 on poison consumption ++ * errors. This means mce_gather_info() will not save the "ip" and "cs" registers. ++ * ++ * However, the context is still valid, so save the "cs" register for later use. ++ * ++ * The "ip" register is truly unknown, so don't save it or fixup EIPV/RIPV. ++ * ++ * The Instruction Fetch Unit is at MCA bank 1 for all affected systems. ++ */ ++static __always_inline void quirk_zen_ifu(int bank, struct mce *m, struct pt_regs *regs) ++{ ++ if (bank != 1) ++ return; ++ if (!(m->status & MCI_STATUS_POISON)) ++ return; ++ ++ m->cs = regs->cs; ++} ++ + /* + * Do a quick check if any of the events requires a panic. + * This decides if we keep the events around or clear them. +@@ -861,6 +881,9 @@ static __always_inline int mce_no_way_out(struct mce *m, char **msg, unsigned lo + if (mce_flags.snb_ifu_quirk) + quirk_sandybridge_ifu(i, m, regs); + ++ if (mce_flags.zen_ifu_quirk) ++ quirk_zen_ifu(i, m, regs); ++ + m->bank = i; + if (mce_severity(m, regs, &tmp, true) >= MCE_PANIC_SEVERITY) { + mce_read_aux(m, i); +@@ -1842,6 +1865,9 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) + if (c->x86 == 0x15 && c->x86_model <= 0xf) + mce_flags.overflow_recov = 1; + ++ if (c->x86 >= 0x17 && c->x86 <= 0x1A) ++ mce_flags.zen_ifu_quirk = 1; ++ + } + + if (c->x86_vendor == X86_VENDOR_INTEL) { +diff --git a/arch/x86/kernel/cpu/mce/internal.h b/arch/x86/kernel/cpu/mce/internal.h +index d2412ce2d312f..d5946fcdcd5de 100644 +--- a/arch/x86/kernel/cpu/mce/internal.h ++++ b/arch/x86/kernel/cpu/mce/internal.h +@@ -157,6 +157,9 @@ struct mce_vendor_flags { + */ + smca : 1, + ++ /* Zen IFU quirk */ ++ zen_ifu_quirk : 1, ++ + /* AMD-style error thresholding banks present. */ + amd_threshold : 1, + +@@ -172,7 +175,7 @@ struct mce_vendor_flags { + /* Skylake, Cascade Lake, Cooper Lake REP;MOVS* quirk */ + skx_repmov_quirk : 1, + +- __reserved_0 : 56; ++ __reserved_0 : 55; + }; + + extern struct mce_vendor_flags mce_flags; +diff --git a/arch/x86/kernel/cpu/sgx/virt.c b/arch/x86/kernel/cpu/sgx/virt.c +index c3e37eaec8ecd..7aaa3652e31d1 100644 +--- a/arch/x86/kernel/cpu/sgx/virt.c ++++ b/arch/x86/kernel/cpu/sgx/virt.c +@@ -204,6 +204,7 @@ static int sgx_vepc_release(struct inode *inode, struct file *file) + continue; + + xa_erase(&vepc->page_array, index); ++ cond_resched(); + } + + /* +@@ -222,6 +223,7 @@ static int sgx_vepc_release(struct inode *inode, struct file *file) + list_add_tail(&epc_page->list, &secs_pages); + + xa_erase(&vepc->page_array, index); ++ cond_resched(); + } + + /* +@@ -243,6 +245,7 @@ static int sgx_vepc_release(struct inode *inode, struct file *file) + + if (sgx_vepc_free_page(epc_page)) + list_add_tail(&epc_page->list, &secs_pages); ++ cond_resched(); + } + + if (!list_empty(&secs_pages)) +diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c +index 1cceac5984daa..526d4da3dcd46 100644 +--- a/arch/x86/kernel/kvm.c ++++ b/arch/x86/kernel/kvm.c +@@ -966,10 +966,8 @@ static void __init kvm_init_platform(void) + * Ensure that _bss_decrypted section is marked as decrypted in the + * shared pages list. + */ +- nr_pages = DIV_ROUND_UP(__end_bss_decrypted - __start_bss_decrypted, +- PAGE_SIZE); + early_set_mem_enc_dec_hypercall((unsigned long)__start_bss_decrypted, +- nr_pages, 0); ++ __end_bss_decrypted - __start_bss_decrypted, 0); + + /* + * If not booted using EFI, enable Live migration support. +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 83d41c2601d7b..f15fb71f280e2 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -156,7 +156,7 @@ SECTIONS + ALIGN_ENTRY_TEXT_END + *(.gnu.warning) + +- } :text =0xcccc ++ } :text = 0xcccccccc + + /* End of text section, which should occupy whole number of pages */ + _etext = .; +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index 6eaa3d6994aeb..11c050f40d828 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -58,6 +58,8 @@ + + extern bool itlb_multihit_kvm_mitigation; + ++static bool nx_hugepage_mitigation_hard_disabled; ++ + int __read_mostly nx_huge_pages = -1; + static uint __read_mostly nx_huge_pages_recovery_period_ms; + #ifdef CONFIG_PREEMPT_RT +@@ -67,12 +69,13 @@ static uint __read_mostly nx_huge_pages_recovery_ratio = 0; + static uint __read_mostly nx_huge_pages_recovery_ratio = 60; + #endif + ++static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp); + static int set_nx_huge_pages(const char *val, const struct kernel_param *kp); + static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel_param *kp); + + static const struct kernel_param_ops nx_huge_pages_ops = { + .set = set_nx_huge_pages, +- .get = param_get_bool, ++ .get = get_nx_huge_pages, + }; + + static const struct kernel_param_ops nx_huge_pages_recovery_param_ops = { +@@ -6844,6 +6847,14 @@ static void mmu_destroy_caches(void) + kmem_cache_destroy(mmu_page_header_cache); + } + ++static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp) ++{ ++ if (nx_hugepage_mitigation_hard_disabled) ++ return sprintf(buffer, "never\n"); ++ ++ return param_get_bool(buffer, kp); ++} ++ + static bool get_nx_auto_mode(void) + { + /* Return true when CPU has the bug, and mitigations are ON */ +@@ -6860,15 +6871,29 @@ static int set_nx_huge_pages(const char *val, const struct kernel_param *kp) + bool old_val = nx_huge_pages; + bool new_val; + ++ if (nx_hugepage_mitigation_hard_disabled) ++ return -EPERM; ++ + /* In "auto" mode deploy workaround only if CPU has the bug. */ +- if (sysfs_streq(val, "off")) ++ if (sysfs_streq(val, "off")) { + new_val = 0; +- else if (sysfs_streq(val, "force")) ++ } else if (sysfs_streq(val, "force")) { + new_val = 1; +- else if (sysfs_streq(val, "auto")) ++ } else if (sysfs_streq(val, "auto")) { + new_val = get_nx_auto_mode(); +- else if (kstrtobool(val, &new_val) < 0) ++ } else if (sysfs_streq(val, "never")) { ++ new_val = 0; ++ ++ mutex_lock(&kvm_lock); ++ if (!list_empty(&vm_list)) { ++ mutex_unlock(&kvm_lock); ++ return -EBUSY; ++ } ++ nx_hugepage_mitigation_hard_disabled = true; ++ mutex_unlock(&kvm_lock); ++ } else if (kstrtobool(val, &new_val) < 0) { + return -EINVAL; ++ } + + __set_nx_huge_pages(new_val); + +@@ -7006,6 +7031,9 @@ static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel + uint old_period, new_period; + int err; + ++ if (nx_hugepage_mitigation_hard_disabled) ++ return -EPERM; ++ + was_recovery_enabled = calc_nx_huge_pages_recovery_period(&old_period); + + err = param_set_uint(val, kp); +@@ -7164,6 +7192,9 @@ int kvm_mmu_post_init_vm(struct kvm *kvm) + { + int err; + ++ if (nx_hugepage_mitigation_hard_disabled) ++ return 0; ++ + err = kvm_vm_create_worker_thread(kvm, kvm_nx_huge_page_recovery_worker, 0, + "kvm-nx-lpage-recovery", + &kvm->arch.nx_huge_page_recovery_thread); +diff --git a/arch/x86/mm/mem_encrypt_amd.c b/arch/x86/mm/mem_encrypt_amd.c +index 4f95c449a406e..bff4201c9db7c 100644 +--- a/arch/x86/mm/mem_encrypt_amd.c ++++ b/arch/x86/mm/mem_encrypt_amd.c +@@ -288,11 +288,10 @@ static bool amd_enc_cache_flush_required(void) + return !cpu_feature_enabled(X86_FEATURE_SME_COHERENT); + } + +-static void enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) ++static void enc_dec_hypercall(unsigned long vaddr, unsigned long size, bool enc) + { + #ifdef CONFIG_PARAVIRT +- unsigned long sz = npages << PAGE_SHIFT; +- unsigned long vaddr_end = vaddr + sz; ++ unsigned long vaddr_end = vaddr + size; + + while (vaddr < vaddr_end) { + int psize, pmask, level; +@@ -342,7 +341,7 @@ static bool amd_enc_status_change_finish(unsigned long vaddr, int npages, bool e + snp_set_memory_private(vaddr, npages); + + if (!cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) +- enc_dec_hypercall(vaddr, npages, enc); ++ enc_dec_hypercall(vaddr, npages << PAGE_SHIFT, enc); + + return true; + } +@@ -466,7 +465,7 @@ static int __init early_set_memory_enc_dec(unsigned long vaddr, + + ret = 0; + +- early_set_mem_enc_dec_hypercall(start, PAGE_ALIGN(size) >> PAGE_SHIFT, enc); ++ early_set_mem_enc_dec_hypercall(start, size, enc); + out: + __flush_tlb_all(); + return ret; +@@ -482,9 +481,9 @@ int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size) + return early_set_memory_enc_dec(vaddr, size, true); + } + +-void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) ++void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, unsigned long size, bool enc) + { +- enc_dec_hypercall(vaddr, npages, enc); ++ enc_dec_hypercall(vaddr, size, enc); + } + + void __init sme_early_init(void) +diff --git a/arch/xtensa/include/asm/core.h b/arch/xtensa/include/asm/core.h +index f856d2bcb9f36..7cef85ad9741a 100644 +--- a/arch/xtensa/include/asm/core.h ++++ b/arch/xtensa/include/asm/core.h +@@ -44,4 +44,13 @@ + #define XTENSA_STACK_ALIGNMENT 16 + #endif + ++#ifndef XCHAL_HW_MIN_VERSION ++#if defined(XCHAL_HW_MIN_VERSION_MAJOR) && defined(XCHAL_HW_MIN_VERSION_MINOR) ++#define XCHAL_HW_MIN_VERSION (XCHAL_HW_MIN_VERSION_MAJOR * 100 + \ ++ XCHAL_HW_MIN_VERSION_MINOR) ++#else ++#define XCHAL_HW_MIN_VERSION 0 ++#endif ++#endif ++ + #endif +diff --git a/arch/xtensa/kernel/perf_event.c b/arch/xtensa/kernel/perf_event.c +index a0d05c8598d0f..183618090d05b 100644 +--- a/arch/xtensa/kernel/perf_event.c ++++ b/arch/xtensa/kernel/perf_event.c +@@ -13,17 +13,26 @@ + #include <linux/perf_event.h> + #include <linux/platform_device.h> + ++#include <asm/core.h> + #include <asm/processor.h> + #include <asm/stacktrace.h> + ++#define XTENSA_HWVERSION_RG_2015_0 260000 ++ ++#if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RG_2015_0 ++#define XTENSA_PMU_ERI_BASE 0x00101000 ++#else ++#define XTENSA_PMU_ERI_BASE 0x00001000 ++#endif ++ + /* Global control/status for all perf counters */ +-#define XTENSA_PMU_PMG 0x1000 ++#define XTENSA_PMU_PMG XTENSA_PMU_ERI_BASE + /* Perf counter values */ +-#define XTENSA_PMU_PM(i) (0x1080 + (i) * 4) ++#define XTENSA_PMU_PM(i) (XTENSA_PMU_ERI_BASE + 0x80 + (i) * 4) + /* Perf counter control registers */ +-#define XTENSA_PMU_PMCTRL(i) (0x1100 + (i) * 4) ++#define XTENSA_PMU_PMCTRL(i) (XTENSA_PMU_ERI_BASE + 0x100 + (i) * 4) + /* Perf counter status registers */ +-#define XTENSA_PMU_PMSTAT(i) (0x1180 + (i) * 4) ++#define XTENSA_PMU_PMSTAT(i) (XTENSA_PMU_ERI_BASE + 0x180 + (i) * 4) + + #define XTENSA_PMU_PMG_PMEN 0x1 + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 9faafcd10e177..4a42ea2972ad8 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -1511,7 +1511,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol) + retry: + spin_lock_irq(&q->queue_lock); + +- /* blkg_list is pushed at the head, reverse walk to allocate parents first */ ++ /* blkg_list is pushed at the head, reverse walk to initialize parents first */ + list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) { + struct blkg_policy_data *pd; + +@@ -1549,21 +1549,20 @@ retry: + goto enomem; + } + +- blkg->pd[pol->plid] = pd; ++ spin_lock(&blkg->blkcg->lock); ++ + pd->blkg = blkg; + pd->plid = pol->plid; +- pd->online = false; +- } ++ blkg->pd[pol->plid] = pd; + +- /* all allocated, init in the same order */ +- if (pol->pd_init_fn) +- list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) +- pol->pd_init_fn(blkg->pd[pol->plid]); ++ if (pol->pd_init_fn) ++ pol->pd_init_fn(pd); + +- list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) { + if (pol->pd_online_fn) +- pol->pd_online_fn(blkg->pd[pol->plid]); +- blkg->pd[pol->plid]->online = true; ++ pol->pd_online_fn(pd); ++ pd->online = true; ++ ++ spin_unlock(&blkg->blkcg->lock); + } + + __set_bit(pol->plid, q->blkcg_pols); +@@ -1580,14 +1579,19 @@ out: + return ret; + + enomem: +- /* alloc failed, nothing's initialized yet, free everything */ ++ /* alloc failed, take down everything */ + spin_lock_irq(&q->queue_lock); + list_for_each_entry(blkg, &q->blkg_list, q_node) { + struct blkcg *blkcg = blkg->blkcg; ++ struct blkg_policy_data *pd; + + spin_lock(&blkcg->lock); +- if (blkg->pd[pol->plid]) { +- pol->pd_free_fn(blkg->pd[pol->plid]); ++ pd = blkg->pd[pol->plid]; ++ if (pd) { ++ if (pd->online && pol->pd_offline_fn) ++ pol->pd_offline_fn(pd); ++ pd->online = false; ++ pol->pd_free_fn(pd); + blkg->pd[pol->plid] = NULL; + } + spin_unlock(&blkcg->lock); +diff --git a/block/blk-settings.c b/block/blk-settings.c +index 4dd59059b788e..0046b447268f9 100644 +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -830,10 +830,13 @@ EXPORT_SYMBOL(blk_set_queue_depth); + */ + void blk_queue_write_cache(struct request_queue *q, bool wc, bool fua) + { +- if (wc) ++ if (wc) { ++ blk_queue_flag_set(QUEUE_FLAG_HW_WC, q); + blk_queue_flag_set(QUEUE_FLAG_WC, q); +- else ++ } else { ++ blk_queue_flag_clear(QUEUE_FLAG_HW_WC, q); + blk_queue_flag_clear(QUEUE_FLAG_WC, q); ++ } + if (fua) + blk_queue_flag_set(QUEUE_FLAG_FUA, q); + else +diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c +index a642085838531..b7fc4cf3f992c 100644 +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -517,21 +517,16 @@ static ssize_t queue_wc_show(struct request_queue *q, char *page) + static ssize_t queue_wc_store(struct request_queue *q, const char *page, + size_t count) + { +- int set = -1; +- +- if (!strncmp(page, "write back", 10)) +- set = 1; +- else if (!strncmp(page, "write through", 13) || +- !strncmp(page, "none", 4)) +- set = 0; +- +- if (set == -1) +- return -EINVAL; +- +- if (set) ++ if (!strncmp(page, "write back", 10)) { ++ if (!test_bit(QUEUE_FLAG_HW_WC, &q->queue_flags)) ++ return -EINVAL; + blk_queue_flag_set(QUEUE_FLAG_WC, q); +- else ++ } else if (!strncmp(page, "write through", 13) || ++ !strncmp(page, "none", 4)) { + blk_queue_flag_clear(QUEUE_FLAG_WC, q); ++ } else { ++ return -EINVAL; ++ } + + return count; + } +diff --git a/block/ioctl.c b/block/ioctl.c +index 9c5f637ff153f..3c475e4166e9f 100644 +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -20,6 +20,8 @@ static int blkpg_do_ioctl(struct block_device *bdev, + struct blkpg_partition p; + long long start, length; + ++ if (disk->flags & GENHD_FL_NO_PART) ++ return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (copy_from_user(&p, upart, sizeof(struct blkpg_partition))) +diff --git a/block/mq-deadline.c b/block/mq-deadline.c +index 5839a027e0f05..7e043d4a78f84 100644 +--- a/block/mq-deadline.c ++++ b/block/mq-deadline.c +@@ -620,8 +620,9 @@ static void dd_depth_updated(struct blk_mq_hw_ctx *hctx) + struct request_queue *q = hctx->queue; + struct deadline_data *dd = q->elevator->elevator_data; + struct blk_mq_tags *tags = hctx->sched_tags; ++ unsigned int shift = tags->bitmap_tags.sb.shift; + +- dd->async_depth = max(1UL, 3 * q->nr_requests / 4); ++ dd->async_depth = max(1U, 3 * (1U << shift) / 4); + + sbitmap_queue_min_shallow_depth(&tags->bitmap_tags, dd->async_depth); + } +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index 5f7252a5b7b44..703fb426ff5d1 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -320,18 +320,21 @@ static int alg_setkey_by_key_serial(struct alg_sock *ask, sockptr_t optval, + + if (IS_ERR(ret)) { + up_read(&key->sem); ++ key_put(key); + return PTR_ERR(ret); + } + + key_data = sock_kmalloc(&ask->sk, key_datalen, GFP_KERNEL); + if (!key_data) { + up_read(&key->sem); ++ key_put(key); + return -ENOMEM; + } + + memcpy(key_data, ret, key_datalen); + + up_read(&key->sem); ++ key_put(key); + + err = type->setkey(ask->private, key_data, key_datalen); + +diff --git a/crypto/algapi.c b/crypto/algapi.c +index 5e7cd603d489c..4fe95c4480473 100644 +--- a/crypto/algapi.c ++++ b/crypto/algapi.c +@@ -17,6 +17,7 @@ + #include <linux/rtnetlink.h> + #include <linux/slab.h> + #include <linux/string.h> ++#include <linux/workqueue.h> + + #include "internal.h" + +@@ -74,15 +75,26 @@ static void crypto_free_instance(struct crypto_instance *inst) + inst->alg.cra_type->free(inst); + } + +-static void crypto_destroy_instance(struct crypto_alg *alg) ++static void crypto_destroy_instance_workfn(struct work_struct *w) + { +- struct crypto_instance *inst = (void *)alg; ++ struct crypto_instance *inst = container_of(w, struct crypto_instance, ++ free_work); + struct crypto_template *tmpl = inst->tmpl; + + crypto_free_instance(inst); + crypto_tmpl_put(tmpl); + } + ++static void crypto_destroy_instance(struct crypto_alg *alg) ++{ ++ struct crypto_instance *inst = container_of(alg, ++ struct crypto_instance, ++ alg); ++ ++ INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn); ++ schedule_work(&inst->free_work); ++} ++ + /* + * This function adds a spawn to the list secondary_spawns which + * will be used at the end of crypto_remove_spawns to unregister +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 0b4943a4592b7..1815024bead38 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -117,6 +117,11 @@ int x509_check_for_self_signed(struct x509_certificate *cert) + goto out; + } + ++ if (cert->unsupported_sig) { ++ ret = 0; ++ goto out; ++ } ++ + ret = public_key_verify_signature(cert->pub, cert->sig); + if (ret < 0) { + if (ret == -ENOPKG) { +diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c +index e499c60c45791..ec84da6cc1bff 100644 +--- a/drivers/acpi/x86/s2idle.c ++++ b/drivers/acpi/x86/s2idle.c +@@ -122,17 +122,16 @@ static void lpi_device_get_constraints_amd(void) + acpi_handle_debug(lps0_device_handle, + "LPI: constraints list begin:\n"); + +- for (j = 0; j < package->package.count; ++j) { ++ for (j = 0; j < package->package.count; j++) { + union acpi_object *info_obj = &package->package.elements[j]; + struct lpi_device_constraint_amd dev_info = {}; + struct lpi_constraints *list; + acpi_status status; + +- for (k = 0; k < info_obj->package.count; ++k) { +- union acpi_object *obj = &info_obj->package.elements[k]; ++ list = &lpi_constraints_table[lpi_constraints_table_size]; + +- list = &lpi_constraints_table[lpi_constraints_table_size]; +- list->min_dstate = -1; ++ for (k = 0; k < info_obj->package.count; k++) { ++ union acpi_object *obj = &info_obj->package.elements[k]; + + switch (k) { + case 0: +@@ -148,27 +147,21 @@ static void lpi_device_get_constraints_amd(void) + dev_info.min_dstate = obj->integer.value; + break; + } ++ } + +- if (!dev_info.enabled || !dev_info.name || +- !dev_info.min_dstate) +- continue; ++ if (!dev_info.enabled || !dev_info.name || ++ !dev_info.min_dstate) ++ continue; + +- status = acpi_get_handle(NULL, dev_info.name, +- &list->handle); +- if (ACPI_FAILURE(status)) +- continue; ++ status = acpi_get_handle(NULL, dev_info.name, &list->handle); ++ if (ACPI_FAILURE(status)) ++ continue; + +- acpi_handle_debug(lps0_device_handle, +- "Name:%s\n", dev_info.name); ++ acpi_handle_debug(lps0_device_handle, ++ "Name:%s\n", dev_info.name); + +- list->min_dstate = dev_info.min_dstate; ++ list->min_dstate = dev_info.min_dstate; + +- if (list->min_dstate < 0) { +- acpi_handle_debug(lps0_device_handle, +- "Incomplete constraint defined\n"); +- continue; +- } +- } + lpi_constraints_table_size++; + } + } +@@ -213,7 +206,7 @@ static void lpi_device_get_constraints(void) + if (!package) + continue; + +- for (j = 0; j < package->package.count; ++j) { ++ for (j = 0; j < package->package.count; j++) { + union acpi_object *element = + &(package->package.elements[j]); + +@@ -245,7 +238,7 @@ static void lpi_device_get_constraints(void) + + constraint->min_dstate = -1; + +- for (j = 0; j < package_count; ++j) { ++ for (j = 0; j < package_count; j++) { + union acpi_object *info_obj = &info.package[j]; + union acpi_object *cnstr_pkg; + union acpi_object *obj; +diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c +index ce88af9eb562f..09e72967b8abf 100644 +--- a/drivers/amba/bus.c ++++ b/drivers/amba/bus.c +@@ -528,6 +528,7 @@ static void amba_device_release(struct device *dev) + { + struct amba_device *d = to_amba_device(dev); + ++ of_node_put(d->dev.of_node); + if (d->res.parent) + release_resource(&d->res); + mutex_destroy(&d->periphid_lock); +diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c +index 6ab294322e792..314eaa1679540 100644 +--- a/drivers/ata/pata_arasan_cf.c ++++ b/drivers/ata/pata_arasan_cf.c +@@ -529,7 +529,8 @@ static void data_xfer(struct work_struct *work) + /* dma_request_channel may sleep, so calling from process context */ + acdev->dma_chan = dma_request_chan(acdev->host->dev, "data"); + if (IS_ERR(acdev->dma_chan)) { +- dev_err(acdev->host->dev, "Unable to get dma_chan\n"); ++ dev_err_probe(acdev->host->dev, PTR_ERR(acdev->dma_chan), ++ "Unable to get dma_chan\n"); + acdev->dma_chan = NULL; + goto chan_request_fail; + } +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 3dff5037943e0..6ceaf50f5a671 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -3817,6 +3817,17 @@ void device_del(struct device *dev) + device_platform_notify_remove(dev); + device_links_purge(dev); + ++ /* ++ * If a device does not have a driver attached, we need to clean ++ * up any managed resources. We do this in device_release(), but ++ * it's never called (and we leak the device) if a managed ++ * resource holds a reference to the device. So release all ++ * managed resources here, like we do in driver_detach(). We ++ * still need to do so again in device_release() in case someone ++ * adds a new resource after this point, though. ++ */ ++ devres_release_all(dev); ++ + bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE); + kobject_uevent(&dev->kobj, KOBJ_REMOVE); + glue_dir = get_glue_dir(dev); +diff --git a/drivers/base/dd.c b/drivers/base/dd.c +index 9c09ca5c4ab68..7145d9b940b14 100644 +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -693,6 +693,8 @@ re_probe: + + device_remove(dev); + driver_sysfs_remove(dev); ++ if (dev->bus && dev->bus->dma_cleanup) ++ dev->bus->dma_cleanup(dev); + device_unbind_cleanup(dev); + + goto re_probe; +diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c +index c2e3a0f6c2183..08316d578be23 100644 +--- a/drivers/base/regmap/regcache-maple.c ++++ b/drivers/base/regmap/regcache-maple.c +@@ -74,7 +74,7 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg, + rcu_read_unlock(); + + entry = kmalloc((last - index + 1) * sizeof(unsigned long), +- GFP_KERNEL); ++ map->alloc_flags); + if (!entry) + return -ENOMEM; + +@@ -92,7 +92,7 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg, + mas_lock(&mas); + + mas_set_range(&mas, index, last); +- ret = mas_store_gfp(&mas, entry, GFP_KERNEL); ++ ret = mas_store_gfp(&mas, entry, map->alloc_flags); + + mas_unlock(&mas); + +@@ -134,7 +134,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, + + lower = kmemdup(entry, ((min - mas.index) * + sizeof(unsigned long)), +- GFP_KERNEL); ++ map->alloc_flags); + if (!lower) { + ret = -ENOMEM; + goto out_unlocked; +@@ -148,7 +148,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, + upper = kmemdup(&entry[max + 1], + ((mas.last - max) * + sizeof(unsigned long)), +- GFP_KERNEL); ++ map->alloc_flags); + if (!upper) { + ret = -ENOMEM; + goto out_unlocked; +@@ -162,7 +162,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, + /* Insert new nodes with the saved data */ + if (lower) { + mas_set_range(&mas, lower_index, lower_last); +- ret = mas_store_gfp(&mas, lower, GFP_KERNEL); ++ ret = mas_store_gfp(&mas, lower, map->alloc_flags); + if (ret != 0) + goto out; + lower = NULL; +@@ -170,7 +170,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, + + if (upper) { + mas_set_range(&mas, upper_index, upper_last); +- ret = mas_store_gfp(&mas, upper, GFP_KERNEL); ++ ret = mas_store_gfp(&mas, upper, map->alloc_flags); + if (ret != 0) + goto out; + upper = NULL; +@@ -242,11 +242,41 @@ static int regcache_maple_exit(struct regmap *map) + return 0; + } + ++static int regcache_maple_insert_block(struct regmap *map, int first, ++ int last) ++{ ++ struct maple_tree *mt = map->cache; ++ MA_STATE(mas, mt, first, last); ++ unsigned long *entry; ++ int i, ret; ++ ++ entry = kcalloc(last - first + 1, sizeof(unsigned long), map->alloc_flags); ++ if (!entry) ++ return -ENOMEM; ++ ++ for (i = 0; i < last - first + 1; i++) ++ entry[i] = map->reg_defaults[first + i].def; ++ ++ mas_lock(&mas); ++ ++ mas_set_range(&mas, map->reg_defaults[first].reg, ++ map->reg_defaults[last].reg); ++ ret = mas_store_gfp(&mas, entry, map->alloc_flags); ++ ++ mas_unlock(&mas); ++ ++ if (ret) ++ kfree(entry); ++ ++ return ret; ++} ++ + static int regcache_maple_init(struct regmap *map) + { + struct maple_tree *mt; + int i; + int ret; ++ int range_start; + + mt = kmalloc(sizeof(*mt), GFP_KERNEL); + if (!mt) +@@ -255,14 +285,30 @@ static int regcache_maple_init(struct regmap *map) + + mt_init(mt); + +- for (i = 0; i < map->num_reg_defaults; i++) { +- ret = regcache_maple_write(map, +- map->reg_defaults[i].reg, +- map->reg_defaults[i].def); +- if (ret) +- goto err; ++ if (!map->num_reg_defaults) ++ return 0; ++ ++ range_start = 0; ++ ++ /* Scan for ranges of contiguous registers */ ++ for (i = 1; i < map->num_reg_defaults; i++) { ++ if (map->reg_defaults[i].reg != ++ map->reg_defaults[i - 1].reg + 1) { ++ ret = regcache_maple_insert_block(map, range_start, ++ i - 1); ++ if (ret != 0) ++ goto err; ++ ++ range_start = i; ++ } + } + ++ /* Add the last block */ ++ ret = regcache_maple_insert_block(map, range_start, ++ map->num_reg_defaults - 1); ++ if (ret != 0) ++ goto err; ++ + return 0; + + err: +diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c +index fabf87058d80b..ae6b8788d5f3f 100644 +--- a/drivers/base/regmap/regcache-rbtree.c ++++ b/drivers/base/regmap/regcache-rbtree.c +@@ -277,7 +277,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, + + blk = krealloc(rbnode->block, + blklen * map->cache_word_size, +- GFP_KERNEL); ++ map->alloc_flags); + if (!blk) + return -ENOMEM; + +@@ -286,7 +286,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, + if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) { + present = krealloc(rbnode->cache_present, + BITS_TO_LONGS(blklen) * sizeof(*present), +- GFP_KERNEL); ++ map->alloc_flags); + if (!present) + return -ENOMEM; + +@@ -320,7 +320,7 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg) + const struct regmap_range *range; + int i; + +- rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL); ++ rbnode = kzalloc(sizeof(*rbnode), map->alloc_flags); + if (!rbnode) + return NULL; + +@@ -346,13 +346,13 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg) + } + + rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size, +- GFP_KERNEL); ++ map->alloc_flags); + if (!rbnode->block) + goto err_free; + + rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen), + sizeof(*rbnode->cache_present), +- GFP_KERNEL); ++ map->alloc_flags); + if (!rbnode->cache_present) + goto err_free_block; + +diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c +index 929410d0dd6fe..3465800baa6c8 100644 +--- a/drivers/base/test/test_async_driver_probe.c ++++ b/drivers/base/test/test_async_driver_probe.c +@@ -84,7 +84,7 @@ test_platform_device_register_node(char *name, int id, int nid) + + pdev = platform_device_alloc(name, id); + if (!pdev) +- return NULL; ++ return ERR_PTR(-ENOMEM); + + if (nid != NUMA_NO_NODE) + set_dev_node(&pdev->dev, nid); +diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c +index d9349ba48281e..7ba60151a16a6 100644 +--- a/drivers/bluetooth/btintel.c ++++ b/drivers/bluetooth/btintel.c +@@ -2658,6 +2658,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) + set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, + &hdev->quirks); + ++ /* These variants don't seem to support LE Coded PHY */ ++ set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); ++ + /* Setup MSFT Extension support */ + btintel_set_msft_opcode(hdev, ver.hw_variant); + +@@ -2729,6 +2732,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) + */ + set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + ++ /* These variants don't seem to support LE Coded PHY */ ++ set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); ++ + /* Set Valid LE States quirk */ + set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); + +diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c +index 2915c82d719d8..03a20d617deee 100644 +--- a/drivers/bluetooth/btrtl.c ++++ b/drivers/bluetooth/btrtl.c +@@ -101,21 +101,21 @@ static const struct id_table ic_id_table[] = { + { IC_INFO(RTL_ROM_LMP_8723A, 0xb, 0x6, HCI_USB), + .config_needed = false, + .has_rom_version = false, +- .fw_name = "rtl_bt/rtl8723a_fw.bin", ++ .fw_name = "rtl_bt/rtl8723a_fw", + .cfg_name = NULL }, + + /* 8723BS */ + { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART), + .config_needed = true, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723bs_fw.bin", ++ .fw_name = "rtl_bt/rtl8723bs_fw", + .cfg_name = "rtl_bt/rtl8723bs_config" }, + + /* 8723B */ + { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB), + .config_needed = false, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723b_fw.bin", ++ .fw_name = "rtl_bt/rtl8723b_fw", + .cfg_name = "rtl_bt/rtl8723b_config" }, + + /* 8723CS-CG */ +@@ -126,7 +126,7 @@ static const struct id_table ic_id_table[] = { + .hci_bus = HCI_UART, + .config_needed = true, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723cs_cg_fw.bin", ++ .fw_name = "rtl_bt/rtl8723cs_cg_fw", + .cfg_name = "rtl_bt/rtl8723cs_cg_config" }, + + /* 8723CS-VF */ +@@ -137,7 +137,7 @@ static const struct id_table ic_id_table[] = { + .hci_bus = HCI_UART, + .config_needed = true, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723cs_vf_fw.bin", ++ .fw_name = "rtl_bt/rtl8723cs_vf_fw", + .cfg_name = "rtl_bt/rtl8723cs_vf_config" }, + + /* 8723CS-XX */ +@@ -148,28 +148,28 @@ static const struct id_table ic_id_table[] = { + .hci_bus = HCI_UART, + .config_needed = true, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723cs_xx_fw.bin", ++ .fw_name = "rtl_bt/rtl8723cs_xx_fw", + .cfg_name = "rtl_bt/rtl8723cs_xx_config" }, + + /* 8723D */ + { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB), + .config_needed = true, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723d_fw.bin", ++ .fw_name = "rtl_bt/rtl8723d_fw", + .cfg_name = "rtl_bt/rtl8723d_config" }, + + /* 8723DS */ + { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART), + .config_needed = true, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8723ds_fw.bin", ++ .fw_name = "rtl_bt/rtl8723ds_fw", + .cfg_name = "rtl_bt/rtl8723ds_config" }, + + /* 8821A */ + { IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB), + .config_needed = false, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8821a_fw.bin", ++ .fw_name = "rtl_bt/rtl8821a_fw", + .cfg_name = "rtl_bt/rtl8821a_config" }, + + /* 8821C */ +@@ -177,7 +177,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8821c_fw.bin", ++ .fw_name = "rtl_bt/rtl8821c_fw", + .cfg_name = "rtl_bt/rtl8821c_config" }, + + /* 8821CS */ +@@ -185,14 +185,14 @@ static const struct id_table ic_id_table[] = { + .config_needed = true, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8821cs_fw.bin", ++ .fw_name = "rtl_bt/rtl8821cs_fw", + .cfg_name = "rtl_bt/rtl8821cs_config" }, + + /* 8761A */ + { IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB), + .config_needed = false, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8761a_fw.bin", ++ .fw_name = "rtl_bt/rtl8761a_fw", + .cfg_name = "rtl_bt/rtl8761a_config" }, + + /* 8761B */ +@@ -200,14 +200,14 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8761b_fw.bin", ++ .fw_name = "rtl_bt/rtl8761b_fw", + .cfg_name = "rtl_bt/rtl8761b_config" }, + + /* 8761BU */ + { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB), + .config_needed = false, + .has_rom_version = true, +- .fw_name = "rtl_bt/rtl8761bu_fw.bin", ++ .fw_name = "rtl_bt/rtl8761bu_fw", + .cfg_name = "rtl_bt/rtl8761bu_config" }, + + /* 8822C with UART interface */ +@@ -215,7 +215,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = true, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8822cs_fw.bin", ++ .fw_name = "rtl_bt/rtl8822cs_fw", + .cfg_name = "rtl_bt/rtl8822cs_config" }, + + /* 8822C with UART interface */ +@@ -223,7 +223,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = true, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8822cs_fw.bin", ++ .fw_name = "rtl_bt/rtl8822cs_fw", + .cfg_name = "rtl_bt/rtl8822cs_config" }, + + /* 8822C with USB interface */ +@@ -231,7 +231,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8822cu_fw.bin", ++ .fw_name = "rtl_bt/rtl8822cu_fw", + .cfg_name = "rtl_bt/rtl8822cu_config" }, + + /* 8822B */ +@@ -239,7 +239,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = true, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8822b_fw.bin", ++ .fw_name = "rtl_bt/rtl8822b_fw", + .cfg_name = "rtl_bt/rtl8822b_config" }, + + /* 8852A */ +@@ -247,7 +247,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8852au_fw.bin", ++ .fw_name = "rtl_bt/rtl8852au_fw", + .cfg_name = "rtl_bt/rtl8852au_config" }, + + /* 8852B with UART interface */ +@@ -255,7 +255,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = true, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8852bs_fw.bin", ++ .fw_name = "rtl_bt/rtl8852bs_fw", + .cfg_name = "rtl_bt/rtl8852bs_config" }, + + /* 8852B */ +@@ -263,7 +263,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8852bu_fw.bin", ++ .fw_name = "rtl_bt/rtl8852bu_fw", + .cfg_name = "rtl_bt/rtl8852bu_config" }, + + /* 8852C */ +@@ -271,7 +271,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = true, +- .fw_name = "rtl_bt/rtl8852cu_fw.bin", ++ .fw_name = "rtl_bt/rtl8852cu_fw", + .cfg_name = "rtl_bt/rtl8852cu_config" }, + + /* 8851B */ +@@ -279,7 +279,7 @@ static const struct id_table ic_id_table[] = { + .config_needed = false, + .has_rom_version = true, + .has_msft_ext = false, +- .fw_name = "rtl_bt/rtl8851bu_fw.bin", ++ .fw_name = "rtl_bt/rtl8851bu_fw", + .cfg_name = "rtl_bt/rtl8851bu_config" }, + }; + +@@ -967,6 +967,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, + struct btrtl_device_info *btrtl_dev; + struct sk_buff *skb; + struct hci_rp_read_local_version *resp; ++ char fw_name[40]; + char cfg_name[40]; + u16 hci_rev, lmp_subver; + u8 hci_ver, lmp_ver, chip_type = 0; +@@ -1079,8 +1080,26 @@ next: + goto err_free; + } + +- btrtl_dev->fw_len = rtl_load_file(hdev, btrtl_dev->ic_info->fw_name, +- &btrtl_dev->fw_data); ++ if (!btrtl_dev->ic_info->fw_name) { ++ ret = -ENOMEM; ++ goto err_free; ++ } ++ ++ btrtl_dev->fw_len = -EIO; ++ if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) { ++ snprintf(fw_name, sizeof(fw_name), "%s_v2.bin", ++ btrtl_dev->ic_info->fw_name); ++ btrtl_dev->fw_len = rtl_load_file(hdev, fw_name, ++ &btrtl_dev->fw_data); ++ } ++ ++ if (btrtl_dev->fw_len < 0) { ++ snprintf(fw_name, sizeof(fw_name), "%s.bin", ++ btrtl_dev->ic_info->fw_name); ++ btrtl_dev->fw_len = rtl_load_file(hdev, fw_name, ++ &btrtl_dev->fw_data); ++ } ++ + if (btrtl_dev->fw_len < 0) { + rtl_dev_err(hdev, "firmware file %s not found", + btrtl_dev->ic_info->fw_name); +@@ -1180,6 +1199,10 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) + if (btrtl_dev->project_id == CHIP_ID_8852C) + btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP); + ++ if (btrtl_dev->project_id == CHIP_ID_8852A || ++ btrtl_dev->project_id == CHIP_ID_8852C) ++ set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks); ++ + hci_set_aosp_capable(hdev); + break; + default: +@@ -1382,6 +1405,7 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bs_config.bin"); + MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin"); + MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin"); + MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin"); ++MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin"); + MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin"); + MODULE_FIRMWARE("rtl_bt/rtl8851bu_fw.bin"); + MODULE_FIRMWARE("rtl_bt/rtl8851bu_config.bin"); +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 025e803ba55c2..5559d6d8ae8b2 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -2077,7 +2077,7 @@ static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts) + * alternate setting. + */ + spin_lock_irqsave(&data->rxlock, flags); +- kfree_skb(data->sco_skb); ++ dev_kfree_skb_irq(data->sco_skb); + data->sco_skb = NULL; + spin_unlock_irqrestore(&data->rxlock, flags); + +diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c +index 05f7f6de6863d..97da0b2bfd17e 100644 +--- a/drivers/bluetooth/hci_nokia.c ++++ b/drivers/bluetooth/hci_nokia.c +@@ -734,7 +734,11 @@ static int nokia_bluetooth_serdev_probe(struct serdev_device *serdev) + return err; + } + +- clk_prepare_enable(sysclk); ++ err = clk_prepare_enable(sysclk); ++ if (err) { ++ dev_err(dev, "could not enable sysclk: %d", err); ++ return err; ++ } + btdev->sysclk_speed = clk_get_rate(sysclk); + clk_disable_unprepare(sysclk); + +diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c +index 4cb23b9e06ea4..c95fa4335fee2 100644 +--- a/drivers/bus/ti-sysc.c ++++ b/drivers/bus/ti-sysc.c +@@ -3106,7 +3106,7 @@ static int sysc_init_static_data(struct sysc *ddata) + + match = soc_device_match(sysc_soc_match); + if (match && match->data) +- sysc_soc->soc = (int)match->data; ++ sysc_soc->soc = (enum sysc_soc)(uintptr_t)match->data; + + /* + * Check and warn about possible old incomplete dtb. We now want to see +diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c +index 06bc060534d81..c0df053cbe4b2 100644 +--- a/drivers/char/hw_random/iproc-rng200.c ++++ b/drivers/char/hw_random/iproc-rng200.c +@@ -182,6 +182,8 @@ static int iproc_rng200_probe(struct platform_device *pdev) + return PTR_ERR(priv->base); + } + ++ dev_set_drvdata(dev, priv); ++ + priv->rng.name = "iproc-rng200"; + priv->rng.read = iproc_rng200_read; + priv->rng.init = iproc_rng200_init; +@@ -199,6 +201,28 @@ static int iproc_rng200_probe(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused iproc_rng200_suspend(struct device *dev) ++{ ++ struct iproc_rng200_dev *priv = dev_get_drvdata(dev); ++ ++ iproc_rng200_cleanup(&priv->rng); ++ ++ return 0; ++} ++ ++static int __maybe_unused iproc_rng200_resume(struct device *dev) ++{ ++ struct iproc_rng200_dev *priv = dev_get_drvdata(dev); ++ ++ iproc_rng200_init(&priv->rng); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops iproc_rng200_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(iproc_rng200_suspend, iproc_rng200_resume) ++}; ++ + static const struct of_device_id iproc_rng200_of_match[] = { + { .compatible = "brcm,bcm2711-rng200", }, + { .compatible = "brcm,bcm7211-rng200", }, +@@ -212,6 +236,7 @@ static struct platform_driver iproc_rng200_driver = { + .driver = { + .name = "iproc-rng200", + .of_match_table = iproc_rng200_of_match, ++ .pm = &iproc_rng200_pm_ops, + }, + .probe = iproc_rng200_probe, + }; +diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c +index e8f9621e79541..3774adf903a83 100644 +--- a/drivers/char/hw_random/nomadik-rng.c ++++ b/drivers/char/hw_random/nomadik-rng.c +@@ -13,8 +13,6 @@ + #include <linux/clk.h> + #include <linux/err.h> + +-static struct clk *rng_clk; +- + static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) + { + void __iomem *base = (void __iomem *)rng->priv; +@@ -36,21 +34,20 @@ static struct hwrng nmk_rng = { + + static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) + { ++ struct clk *rng_clk; + void __iomem *base; + int ret; + +- rng_clk = devm_clk_get(&dev->dev, NULL); ++ rng_clk = devm_clk_get_enabled(&dev->dev, NULL); + if (IS_ERR(rng_clk)) { + dev_err(&dev->dev, "could not get rng clock\n"); + ret = PTR_ERR(rng_clk); + return ret; + } + +- clk_prepare_enable(rng_clk); +- + ret = amba_request_regions(dev, dev->dev.init_name); + if (ret) +- goto out_clk; ++ return ret; + ret = -ENOMEM; + base = devm_ioremap(&dev->dev, dev->res.start, + resource_size(&dev->res)); +@@ -64,15 +61,12 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) + + out_release: + amba_release_regions(dev); +-out_clk: +- clk_disable_unprepare(rng_clk); + return ret; + } + + static void nmk_rng_remove(struct amba_device *dev) + { + amba_release_regions(dev); +- clk_disable_unprepare(rng_clk); + } + + static const struct amba_id nmk_rng_ids[] = { +diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c +index 99c8bd0859a14..e04a054e89307 100644 +--- a/drivers/char/hw_random/pic32-rng.c ++++ b/drivers/char/hw_random/pic32-rng.c +@@ -36,7 +36,6 @@ + struct pic32_rng { + void __iomem *base; + struct hwrng rng; +- struct clk *clk; + }; + + /* +@@ -70,6 +69,7 @@ static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max, + static int pic32_rng_probe(struct platform_device *pdev) + { + struct pic32_rng *priv; ++ struct clk *clk; + u32 v; + int ret; + +@@ -81,13 +81,9 @@ static int pic32_rng_probe(struct platform_device *pdev) + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + +- priv->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(priv->clk)) +- return PTR_ERR(priv->clk); +- +- ret = clk_prepare_enable(priv->clk); +- if (ret) +- return ret; ++ clk = devm_clk_get_enabled(&pdev->dev, NULL); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); + + /* enable TRNG in enhanced mode */ + v = TRNGEN | TRNGMOD; +@@ -98,15 +94,11 @@ static int pic32_rng_probe(struct platform_device *pdev) + + ret = devm_hwrng_register(&pdev->dev, &priv->rng); + if (ret) +- goto err_register; ++ return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +- +-err_register: +- clk_disable_unprepare(priv->clk); +- return ret; + } + + static int pic32_rng_remove(struct platform_device *pdev) +@@ -114,7 +106,6 @@ static int pic32_rng_remove(struct platform_device *pdev) + struct pic32_rng *rng = platform_get_drvdata(pdev); + + writel(0, rng->base + RNGCON); +- clk_disable_unprepare(rng->clk); + return 0; + } + +diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c +index abddd7e43a9a6..5cd031f3fc970 100644 +--- a/drivers/char/ipmi/ipmi_si_intf.c ++++ b/drivers/char/ipmi/ipmi_si_intf.c +@@ -2082,6 +2082,11 @@ static int try_smi_init(struct smi_info *new_smi) + new_smi->io.io_cleanup = NULL; + } + ++ if (rv && new_smi->si_sm) { ++ kfree(new_smi->si_sm); ++ new_smi->si_sm = NULL; ++ } ++ + return rv; + } + +diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c +index 3b921c78ba083..faf1f2ad584bf 100644 +--- a/drivers/char/ipmi/ipmi_ssif.c ++++ b/drivers/char/ipmi/ipmi_ssif.c +@@ -1400,7 +1400,7 @@ static struct ssif_addr_info *ssif_info_find(unsigned short addr, + restart: + list_for_each_entry(info, &ssif_infos, link) { + if (info->binfo.addr == addr) { +- if (info->addr_src == SI_SMBIOS) ++ if (info->addr_src == SI_SMBIOS && !info->adapter_name) + info->adapter_name = kstrdup(adapter_name, + GFP_KERNEL); + +@@ -1600,6 +1600,11 @@ static int ssif_add_infos(struct i2c_client *client) + info->addr_src = SI_ACPI; + info->client = client; + info->adapter_name = kstrdup(client->adapter->name, GFP_KERNEL); ++ if (!info->adapter_name) { ++ kfree(info); ++ return -ENOMEM; ++ } ++ + info->binfo.addr = client->addr; + list_add_tail(&info->link, &ssif_infos); + return 0; +diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c +index 9eb1a18590123..a5dbebb1acfcf 100644 +--- a/drivers/char/tpm/tpm_crb.c ++++ b/drivers/char/tpm/tpm_crb.c +@@ -463,28 +463,6 @@ static bool crb_req_canceled(struct tpm_chip *chip, u8 status) + return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE; + } + +-static int crb_check_flags(struct tpm_chip *chip) +-{ +- u32 val; +- int ret; +- +- ret = crb_request_locality(chip, 0); +- if (ret) +- return ret; +- +- ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val, NULL); +- if (ret) +- goto release; +- +- if (val == 0x414D4400U /* AMD */) +- chip->flags |= TPM_CHIP_FLAG_HWRNG_DISABLED; +- +-release: +- crb_relinquish_locality(chip, 0); +- +- return ret; +-} +- + static const struct tpm_class_ops tpm_crb = { + .flags = TPM_OPS_AUTO_STARTUP, + .status = crb_status, +@@ -826,9 +804,14 @@ static int crb_acpi_add(struct acpi_device *device) + if (rc) + goto out; + +- rc = crb_check_flags(chip); +- if (rc) +- goto out; ++#ifdef CONFIG_X86 ++ /* A quirk for https://www.amd.com/en/support/kb/faq/pa-410 */ ++ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && ++ priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) { ++ dev_info(dev, "Disabling hwrng\n"); ++ chip->flags |= TPM_CHIP_FLAG_HWRNG_DISABLED; ++ } ++#endif /* CONFIG_X86 */ + + rc = tpm_chip_register(chip); + +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +index 016814e15536a..52dfbae4f361c 100644 +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -444,6 +444,7 @@ config COMMON_CLK_BD718XX + config COMMON_CLK_FIXED_MMIO + bool "Clock driver for Memory Mapped Fixed values" + depends on COMMON_CLK && OF ++ depends on HAS_IOMEM + help + Support for Memory Mapped IO Fixed clocks + +diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c +index 7a6e3ce97133b..27a08c50ac1d8 100644 +--- a/drivers/clk/imx/clk-composite-8m.c ++++ b/drivers/clk/imx/clk-composite-8m.c +@@ -97,7 +97,7 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, + int prediv_value; + int div_value; + int ret; +- u32 val; ++ u32 orig, val; + + ret = imx8m_clk_composite_compute_dividers(rate, parent_rate, + &prediv_value, &div_value); +@@ -106,13 +106,15 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, + + spin_lock_irqsave(divider->lock, flags); + +- val = readl(divider->reg); +- val &= ~((clk_div_mask(divider->width) << divider->shift) | +- (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); ++ orig = readl(divider->reg); ++ val = orig & ~((clk_div_mask(divider->width) << divider->shift) | ++ (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)(prediv_value - 1) << divider->shift; + val |= (u32)(div_value - 1) << PCG_DIV_SHIFT; +- writel(val, divider->reg); ++ ++ if (val != orig) ++ writel(val, divider->reg); + + spin_unlock_irqrestore(divider->lock, flags); + +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 1469249386dd8..670aa2bab3017 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -178,10 +178,6 @@ static const char * const imx8mp_sai3_sels[] = {"osc_24m", "audio_pll1_out", "au + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext3", "clk_ext4", }; + +-static const char * const imx8mp_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", +- "video_pll1_out", "sys_pll1_133m", "osc_hdmi", +- "clk_ext1", "clk_ext2", }; +- + static const char * const imx8mp_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext2", "clk_ext3", }; +@@ -567,7 +563,6 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + hws[IMX8MP_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mp_sai1_sels, ccm_base + 0xa580); + hws[IMX8MP_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mp_sai2_sels, ccm_base + 0xa600); + hws[IMX8MP_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mp_sai3_sels, ccm_base + 0xa680); +- hws[IMX8MP_CLK_SAI4] = imx8m_clk_hw_composite("sai4", imx8mp_sai4_sels, ccm_base + 0xa700); + hws[IMX8MP_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mp_sai5_sels, ccm_base + 0xa780); + hws[IMX8MP_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mp_sai6_sels, ccm_base + 0xa800); + hws[IMX8MP_CLK_ENET_QOS] = imx8m_clk_hw_composite("enet_qos", imx8mp_enet_qos_sels, ccm_base + 0xa880); +diff --git a/drivers/clk/imx/clk-imx8ulp.c b/drivers/clk/imx/clk-imx8ulp.c +index e308c88cb801c..1b04e2fc78ad5 100644 +--- a/drivers/clk/imx/clk-imx8ulp.c ++++ b/drivers/clk/imx/clk-imx8ulp.c +@@ -167,7 +167,7 @@ static int imx8ulp_clk_cgc1_init(struct platform_device *pdev) + clks[IMX8ULP_CLK_SPLL2_PRE_SEL] = imx_clk_hw_mux_flags("spll2_pre_sel", base + 0x510, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); + clks[IMX8ULP_CLK_SPLL3_PRE_SEL] = imx_clk_hw_mux_flags("spll3_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); + +- clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll2", "spll2_pre_sel", base + 0x500); ++ clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP_1GHZ, "spll2", "spll2_pre_sel", base + 0x500); + clks[IMX8ULP_CLK_SPLL3] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll3", "spll3_pre_sel", base + 0x600); + clks[IMX8ULP_CLK_SPLL3_VCODIV] = imx_clk_hw_divider("spll3_vcodiv", "spll3", base + 0x604, 0, 6); + +diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c +index 6e7e34571fc8d..9b136c951762c 100644 +--- a/drivers/clk/imx/clk-pllv4.c ++++ b/drivers/clk/imx/clk-pllv4.c +@@ -44,11 +44,15 @@ struct clk_pllv4 { + u32 cfg_offset; + u32 num_offset; + u32 denom_offset; ++ bool use_mult_range; + }; + + /* Valid PLL MULT Table */ + static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + ++/* Valid PLL MULT range, (max, min) */ ++static const int pllv4_mult_range[] = {54, 27}; ++ + #define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + + #define LOCK_TIMEOUT_US USEC_PER_MSEC +@@ -94,17 +98,30 @@ static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) + { ++ struct clk_pllv4 *pll = to_clk_pllv4(hw); + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + u32 mfn, mfd = DEFAULT_MFD; + bool found = false; + u64 temp64; +- +- for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { +- round_rate = parent_rate * pllv4_mult_table[i]; +- if (rate >= round_rate) { ++ u32 mult; ++ ++ if (pll->use_mult_range) { ++ temp64 = (u64)rate; ++ do_div(temp64, parent_rate); ++ mult = temp64; ++ if (mult >= pllv4_mult_range[1] && ++ mult <= pllv4_mult_range[0]) { ++ round_rate = parent_rate * mult; + found = true; +- break; ++ } ++ } else { ++ for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { ++ round_rate = parent_rate * pllv4_mult_table[i]; ++ if (rate >= round_rate) { ++ found = true; ++ break; ++ } + } + } + +@@ -138,14 +155,20 @@ static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, + return round_rate + (u32)temp64; + } + +-static bool clk_pllv4_is_valid_mult(unsigned int mult) ++static bool clk_pllv4_is_valid_mult(struct clk_pllv4 *pll, unsigned int mult) + { + int i; + + /* check if mult is in valid MULT table */ +- for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { +- if (pllv4_mult_table[i] == mult) ++ if (pll->use_mult_range) { ++ if (mult >= pllv4_mult_range[1] && ++ mult <= pllv4_mult_range[0]) + return true; ++ } else { ++ for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { ++ if (pllv4_mult_table[i] == mult) ++ return true; ++ } + } + + return false; +@@ -160,7 +183,7 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + + mult = rate / parent_rate; + +- if (!clk_pllv4_is_valid_mult(mult)) ++ if (!clk_pllv4_is_valid_mult(pll, mult)) + return -EINVAL; + + if (parent_rate <= MAX_MFD) +@@ -227,10 +250,13 @@ struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name, + + pll->base = base; + +- if (type == IMX_PLLV4_IMX8ULP) { ++ if (type == IMX_PLLV4_IMX8ULP || ++ type == IMX_PLLV4_IMX8ULP_1GHZ) { + pll->cfg_offset = IMX8ULP_PLL_CFG_OFFSET; + pll->num_offset = IMX8ULP_PLL_NUM_OFFSET; + pll->denom_offset = IMX8ULP_PLL_DENOM_OFFSET; ++ if (type == IMX_PLLV4_IMX8ULP_1GHZ) ++ pll->use_mult_range = true; + } else { + pll->cfg_offset = PLL_CFG_OFFSET; + pll->num_offset = PLL_NUM_OFFSET; +diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h +index 1031468701d7f..6f752f07d125d 100644 +--- a/drivers/clk/imx/clk.h ++++ b/drivers/clk/imx/clk.h +@@ -46,6 +46,7 @@ enum imx_pll14xx_type { + enum imx_pllv4_type { + IMX_PLLV4_IMX7ULP, + IMX_PLLV4_IMX8ULP, ++ IMX_PLLV4_IMX8ULP_1GHZ, + }; + + enum imx_pfdv2_type { +diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c +index d59a7621bb204..ee5c72369334f 100644 +--- a/drivers/clk/keystone/pll.c ++++ b/drivers/clk/keystone/pll.c +@@ -209,7 +209,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl) + } + + clk = clk_register_pll(NULL, node->name, parent_name, pll_data); +- if (clk) { ++ if (!IS_ERR_OR_NULL(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } +diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c +index 167470beb3691..30f636b9f0ec8 100644 +--- a/drivers/clk/qcom/dispcc-sc8280xp.c ++++ b/drivers/clk/qcom/dispcc-sc8280xp.c +@@ -3057,7 +3057,7 @@ static struct gdsc disp0_mdss_gdsc = { + .name = "disp0_mdss_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL, ++ .flags = HW_CTRL | RETAIN_FF_ENABLE, + }; + + static struct gdsc disp1_mdss_gdsc = { +@@ -3069,7 +3069,7 @@ static struct gdsc disp1_mdss_gdsc = { + .name = "disp1_mdss_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL, ++ .flags = HW_CTRL | RETAIN_FF_ENABLE, + }; + + static struct gdsc disp0_mdss_int2_gdsc = { +@@ -3081,7 +3081,7 @@ static struct gdsc disp0_mdss_int2_gdsc = { + .name = "disp0_mdss_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL, ++ .flags = HW_CTRL | RETAIN_FF_ENABLE, + }; + + static struct gdsc disp1_mdss_int2_gdsc = { +@@ -3093,7 +3093,7 @@ static struct gdsc disp1_mdss_int2_gdsc = { + .name = "disp1_mdss_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL, ++ .flags = HW_CTRL | RETAIN_FF_ENABLE, + }; + + static struct gdsc *disp0_cc_sc8280xp_gdscs[] = { +diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c +index 5051769ad90c7..626c5afed7806 100644 +--- a/drivers/clk/qcom/gcc-qdu1000.c ++++ b/drivers/clk/qcom/gcc-qdu1000.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include <linux/clk-provider.h> +@@ -370,16 +370,6 @@ static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_TCXO_IDX }, + }; + +-static const struct parent_map gcc_parent_map_7[] = { +- { P_PCIE_0_PIPE_CLK, 0 }, +- { P_BI_TCXO, 2 }, +-}; +- +-static const struct clk_parent_data gcc_parent_data_7[] = { +- { .index = DT_PCIE_0_PIPE_CLK_IDX }, +- { .index = DT_TCXO_IDX }, +-}; +- + static const struct parent_map gcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, +@@ -439,16 +429,15 @@ static struct clk_regmap_mux gcc_pcie_0_phy_aux_clk_src = { + }, + }; + +-static struct clk_regmap_mux gcc_pcie_0_pipe_clk_src = { ++static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0x9d064, +- .shift = 0, +- .width = 2, +- .parent_map = gcc_parent_map_7, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk_src", +- .parent_data = gcc_parent_data_7, +- .num_parents = ARRAY_SIZE(gcc_parent_data_7), ++ .parent_data = &(const struct clk_parent_data){ ++ .index = DT_PCIE_0_PIPE_CLK_IDX, ++ }, ++ .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +@@ -1458,14 +1447,13 @@ static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + + static struct clk_branch gcc_pcie_0_clkref_en = { + .halt_reg = 0x9c004, +- .halt_bit = 31, +- .halt_check = BRANCH_HALT_ENABLE, ++ .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9c004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_clkref_en", +- .ops = &clk_branch_ops, ++ .ops = &clk_branch2_ops, + }, + }, + }; +@@ -2285,14 +2273,13 @@ static struct clk_branch gcc_tsc_etu_clk = { + + static struct clk_branch gcc_usb2_clkref_en = { + .halt_reg = 0x9c008, +- .halt_bit = 31, +- .halt_check = BRANCH_HALT_ENABLE, ++ .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9c008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb2_clkref_en", +- .ops = &clk_branch_ops, ++ .ops = &clk_branch2_ops, + }, + }, + }; +@@ -2534,6 +2521,7 @@ static struct clk_regmap *gcc_qdu1000_clocks[] = { + [GCC_AGGRE_NOC_ECPRI_GSI_CLK] = &gcc_aggre_noc_ecpri_gsi_clk.clkr, + [GCC_PCIE_0_PHY_AUX_CLK_SRC] = &gcc_pcie_0_phy_aux_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr, ++ [GCC_GPLL1_OUT_EVEN] = &gcc_gpll1_out_even.clkr, + }; + + static const struct qcom_reset_map gcc_qdu1000_resets[] = { +diff --git a/drivers/clk/qcom/gcc-sc7180.c b/drivers/clk/qcom/gcc-sc7180.c +index cef3c77564cfd..49f36e1df4fa8 100644 +--- a/drivers/clk/qcom/gcc-sc7180.c ++++ b/drivers/clk/qcom/gcc-sc7180.c +@@ -651,6 +651,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), ++ .flags = CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_floor_ops, + }, + }; +diff --git a/drivers/clk/qcom/gcc-sc8280xp.c b/drivers/clk/qcom/gcc-sc8280xp.c +index 04a99dbaa57e0..57bbd609151cd 100644 +--- a/drivers/clk/qcom/gcc-sc8280xp.c ++++ b/drivers/clk/qcom/gcc-sc8280xp.c +@@ -6760,7 +6760,7 @@ static struct gdsc pcie_0_tunnel_gdsc = { + .name = "pcie_0_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE, ++ .flags = VOTABLE | RETAIN_FF_ENABLE, + }; + + static struct gdsc pcie_1_tunnel_gdsc = { +@@ -6771,7 +6771,7 @@ static struct gdsc pcie_1_tunnel_gdsc = { + .name = "pcie_1_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE, ++ .flags = VOTABLE | RETAIN_FF_ENABLE, + }; + + /* +@@ -6786,7 +6786,7 @@ static struct gdsc pcie_2a_gdsc = { + .name = "pcie_2a_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE | ALWAYS_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, + }; + + static struct gdsc pcie_2b_gdsc = { +@@ -6797,7 +6797,7 @@ static struct gdsc pcie_2b_gdsc = { + .name = "pcie_2b_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE | ALWAYS_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, + }; + + static struct gdsc pcie_3a_gdsc = { +@@ -6808,7 +6808,7 @@ static struct gdsc pcie_3a_gdsc = { + .name = "pcie_3a_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE | ALWAYS_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, + }; + + static struct gdsc pcie_3b_gdsc = { +@@ -6819,7 +6819,7 @@ static struct gdsc pcie_3b_gdsc = { + .name = "pcie_3b_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE | ALWAYS_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, + }; + + static struct gdsc pcie_4_gdsc = { +@@ -6830,7 +6830,7 @@ static struct gdsc pcie_4_gdsc = { + .name = "pcie_4_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE | ALWAYS_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, + }; + + static struct gdsc ufs_card_gdsc = { +@@ -6839,6 +6839,7 @@ static struct gdsc ufs_card_gdsc = { + .name = "ufs_card_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE, + }; + + static struct gdsc ufs_phy_gdsc = { +@@ -6847,6 +6848,7 @@ static struct gdsc ufs_phy_gdsc = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE, + }; + + static struct gdsc usb30_mp_gdsc = { +@@ -6855,6 +6857,7 @@ static struct gdsc usb30_mp_gdsc = { + .name = "usb30_mp_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, ++ .flags = RETAIN_FF_ENABLE, + }; + + static struct gdsc usb30_prim_gdsc = { +@@ -6863,6 +6866,7 @@ static struct gdsc usb30_prim_gdsc = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, ++ .flags = RETAIN_FF_ENABLE, + }; + + static struct gdsc usb30_sec_gdsc = { +@@ -6871,6 +6875,7 @@ static struct gdsc usb30_sec_gdsc = { + .name = "usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, ++ .flags = RETAIN_FF_ENABLE, + }; + + static struct gdsc emac_0_gdsc = { +@@ -6879,6 +6884,7 @@ static struct gdsc emac_0_gdsc = { + .name = "emac_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE, + }; + + static struct gdsc emac_1_gdsc = { +@@ -6887,6 +6893,97 @@ static struct gdsc emac_1_gdsc = { + .name = "emac_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE, ++}; ++ ++static struct gdsc usb4_1_gdsc = { ++ .gdscr = 0xb8004, ++ .pd = { ++ .name = "usb4_1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE, ++}; ++ ++static struct gdsc usb4_gdsc = { ++ .gdscr = 0x2a004, ++ .pd = { ++ .name = "usb4_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc = { ++ .gdscr = 0x7d06c, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu2_gdsc = { ++ .gdscr = 0x7d0a0, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu2_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu3_gdsc = { ++ .gdscr = 0x7d0a4, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu3_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, + }; + + static struct clk_regmap *gcc_sc8280xp_clocks[] = { +@@ -7369,6 +7466,16 @@ static struct gdsc *gcc_sc8280xp_gdscs[] = { + [USB30_SEC_GDSC] = &usb30_sec_gdsc, + [EMAC_0_GDSC] = &emac_0_gdsc, + [EMAC_1_GDSC] = &emac_1_gdsc, ++ [USB4_1_GDSC] = &usb4_1_gdsc, ++ [USB4_GDSC] = &usb4_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU2_GDSC] = &hlos1_vote_turing_mmu_tbu2_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU3_GDSC] = &hlos1_vote_turing_mmu_tbu3_gdsc, + }; + + static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { +diff --git a/drivers/clk/qcom/gcc-sm6350.c b/drivers/clk/qcom/gcc-sm6350.c +index 9b4e4bb059635..cf4a7b6e0b23a 100644 +--- a/drivers/clk/qcom/gcc-sm6350.c ++++ b/drivers/clk/qcom/gcc-sm6350.c +@@ -641,6 +641,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), ++ .flags = CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_floor_ops, + }, + }; +diff --git a/drivers/clk/qcom/gcc-sm7150.c b/drivers/clk/qcom/gcc-sm7150.c +index 6b628178f62c4..6da87f0436d0c 100644 +--- a/drivers/clk/qcom/gcc-sm7150.c ++++ b/drivers/clk/qcom/gcc-sm7150.c +@@ -739,6 +739,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .ops = &clk_rcg2_floor_ops, ++ .flags = CLK_OPS_PARENT_ENABLE, + }, + }; + +diff --git a/drivers/clk/qcom/gcc-sm8250.c b/drivers/clk/qcom/gcc-sm8250.c +index b6cf4bc88d4d4..d3c75bb55946a 100644 +--- a/drivers/clk/qcom/gcc-sm8250.c ++++ b/drivers/clk/qcom/gcc-sm8250.c +@@ -721,6 +721,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), ++ .flags = CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_floor_ops, + }, + }; +diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c +index 84764cc3db4ff..1d912f8a7243c 100644 +--- a/drivers/clk/qcom/gcc-sm8450.c ++++ b/drivers/clk/qcom/gcc-sm8450.c +@@ -904,7 +904,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_floor_ops, + }, + }; + +@@ -926,7 +926,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_floor_ops, + }, + }; + +diff --git a/drivers/clk/qcom/gpucc-sm6350.c b/drivers/clk/qcom/gpucc-sm6350.c +index ef15185a99c31..0bcbba2a29436 100644 +--- a/drivers/clk/qcom/gpucc-sm6350.c ++++ b/drivers/clk/qcom/gpucc-sm6350.c +@@ -24,6 +24,12 @@ + #define CX_GMU_CBCR_WAKE_MASK 0xF + #define CX_GMU_CBCR_WAKE_SHIFT 8 + ++enum { ++ DT_BI_TCXO, ++ DT_GPLL0_OUT_MAIN, ++ DT_GPLL0_OUT_MAIN_DIV, ++}; ++ + enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, +@@ -61,6 +67,7 @@ static struct clk_alpha_pll gpu_cc_pll0 = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_data = &(const struct clk_parent_data){ ++ .index = DT_BI_TCXO, + .fw_name = "bi_tcxo", + }, + .num_parents = 1, +@@ -104,6 +111,7 @@ static struct clk_alpha_pll gpu_cc_pll1 = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_data = &(const struct clk_parent_data){ ++ .index = DT_BI_TCXO, + .fw_name = "bi_tcxo", + }, + .num_parents = 1, +@@ -121,11 +129,11 @@ static const struct parent_map gpu_cc_parent_map_0[] = { + }; + + static const struct clk_parent_data gpu_cc_parent_data_0[] = { +- { .fw_name = "bi_tcxo" }, ++ { .index = DT_BI_TCXO, .fw_name = "bi_tcxo" }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, +- { .fw_name = "gcc_gpu_gpll0_clk" }, +- { .fw_name = "gcc_gpu_gpll0_div_clk" }, ++ { .index = DT_GPLL0_OUT_MAIN, .fw_name = "gcc_gpu_gpll0_clk_src" }, ++ { .index = DT_GPLL0_OUT_MAIN_DIV, .fw_name = "gcc_gpu_gpll0_div_clk_src" }, + }; + + static const struct parent_map gpu_cc_parent_map_1[] = { +@@ -138,12 +146,12 @@ static const struct parent_map gpu_cc_parent_map_1[] = { + }; + + static const struct clk_parent_data gpu_cc_parent_data_1[] = { +- { .fw_name = "bi_tcxo" }, ++ { .index = DT_BI_TCXO, .fw_name = "bi_tcxo" }, + { .hw = &crc_div.hw }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, +- { .fw_name = "gcc_gpu_gpll0_clk" }, ++ { .index = DT_GPLL0_OUT_MAIN, .fw_name = "gcc_gpu_gpll0_clk_src" }, + }; + + static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { +diff --git a/drivers/clk/qcom/reset.c b/drivers/clk/qcom/reset.c +index 0e914ec7aeae1..e45e32804d2c7 100644 +--- a/drivers/clk/qcom/reset.c ++++ b/drivers/clk/qcom/reset.c +@@ -16,7 +16,8 @@ static int qcom_reset(struct reset_controller_dev *rcdev, unsigned long id) + struct qcom_reset_controller *rst = to_qcom_reset_controller(rcdev); + + rcdev->ops->assert(rcdev, id); +- udelay(rst->reset_map[id].udelay ?: 1); /* use 1 us as default */ ++ fsleep(rst->reset_map[id].udelay ?: 1); /* use 1 us as default */ ++ + rcdev->ops->deassert(rcdev, id); + return 0; + } +diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c +index f85902e2590c7..2f54f630c8b65 100644 +--- a/drivers/clk/rockchip/clk-rk3568.c ++++ b/drivers/clk/rockchip/clk-rk3568.c +@@ -81,7 +81,7 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = { + RK3036_PLL_RATE(108000000, 2, 45, 5, 1, 1, 0), + RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0), + RK3036_PLL_RATE(96000000, 1, 96, 6, 4, 1, 0), +- RK3036_PLL_RATE(78750000, 1, 96, 6, 4, 1, 0), ++ RK3036_PLL_RATE(78750000, 4, 315, 6, 4, 1, 0), + RK3036_PLL_RATE(74250000, 2, 99, 4, 4, 1, 0), + { /* sentinel */ }, + }; +diff --git a/drivers/clk/sunxi-ng/ccu_mmc_timing.c b/drivers/clk/sunxi-ng/ccu_mmc_timing.c +index 23a8d44e2449b..78919d7843bec 100644 +--- a/drivers/clk/sunxi-ng/ccu_mmc_timing.c ++++ b/drivers/clk/sunxi-ng/ccu_mmc_timing.c +@@ -43,7 +43,7 @@ int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode) + EXPORT_SYMBOL_GPL(sunxi_ccu_set_mmc_timing_mode); + + /** +- * sunxi_ccu_set_mmc_timing_mode: Get the current MMC clock timing mode ++ * sunxi_ccu_get_mmc_timing_mode: Get the current MMC clock timing mode + * @clk: clock to query + * + * Return: %0 if the clock is in old timing mode, > %0 if it is in +diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c +index 7f3fe20489818..502d494499ae8 100644 +--- a/drivers/cpufreq/amd-pstate-ut.c ++++ b/drivers/cpufreq/amd-pstate-ut.c +@@ -64,27 +64,9 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = { + static bool get_shared_mem(void) + { + bool result = false; +- char path[] = "/sys/module/amd_pstate/parameters/shared_mem"; +- char buf[5] = {0}; +- struct file *filp = NULL; +- loff_t pos = 0; +- ssize_t ret; +- +- if (!boot_cpu_has(X86_FEATURE_CPPC)) { +- filp = filp_open(path, O_RDONLY, 0); +- if (IS_ERR(filp)) +- pr_err("%s unable to open %s file!\n", __func__, path); +- else { +- ret = kernel_read(filp, &buf, sizeof(buf), &pos); +- if (ret < 0) +- pr_err("%s read %s file fail ret=%ld!\n", +- __func__, path, (long)ret); +- filp_close(filp, NULL); +- } + +- if ('Y' == *buf) +- result = true; +- } ++ if (!boot_cpu_has(X86_FEATURE_CPPC)) ++ result = true; + + return result; + } +@@ -158,7 +140,7 @@ static void amd_pstate_ut_check_perf(u32 index) + if (ret) { + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL; + pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret); +- return; ++ goto skip_test; + } + + nominal_perf = cppc_perf.nominal_perf; +@@ -169,7 +151,7 @@ static void amd_pstate_ut_check_perf(u32 index) + if (ret) { + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL; + pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret); +- return; ++ goto skip_test; + } + + nominal_perf = AMD_CPPC_NOMINAL_PERF(cap1); +@@ -187,7 +169,7 @@ static void amd_pstate_ut_check_perf(u32 index) + nominal_perf, cpudata->nominal_perf, + lowest_nonlinear_perf, cpudata->lowest_nonlinear_perf, + lowest_perf, cpudata->lowest_perf); +- return; ++ goto skip_test; + } + + if (!((highest_perf >= nominal_perf) && +@@ -198,11 +180,15 @@ static void amd_pstate_ut_check_perf(u32 index) + pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n", + __func__, cpu, highest_perf, nominal_perf, + lowest_nonlinear_perf, lowest_perf); +- return; ++ goto skip_test; + } ++ cpufreq_cpu_put(policy); + } + + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS; ++ return; ++skip_test: ++ cpufreq_cpu_put(policy); + } + + /* +@@ -230,14 +216,14 @@ static void amd_pstate_ut_check_freq(u32 index) + pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n", + __func__, cpu, cpudata->max_freq, cpudata->nominal_freq, + cpudata->lowest_nonlinear_freq, cpudata->min_freq); +- return; ++ goto skip_test; + } + + if (cpudata->min_freq != policy->min) { + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL; + pr_err("%s cpu%d cpudata_min_freq=%d policy_min=%d, they should be equal!\n", + __func__, cpu, cpudata->min_freq, policy->min); +- return; ++ goto skip_test; + } + + if (cpudata->boost_supported) { +@@ -249,16 +235,20 @@ static void amd_pstate_ut_check_freq(u32 index) + pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n", + __func__, cpu, policy->max, cpudata->max_freq, + cpudata->nominal_freq); +- return; ++ goto skip_test; + } + } else { + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL; + pr_err("%s cpu%d must support boost!\n", __func__, cpu); +- return; ++ goto skip_test; + } ++ cpufreq_cpu_put(policy); + } + + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS; ++ return; ++skip_test: ++ cpufreq_cpu_put(policy); + } + + static int __init amd_pstate_ut_init(void) +diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c +index ffea6402189d3..3052949aebbc7 100644 +--- a/drivers/cpufreq/brcmstb-avs-cpufreq.c ++++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c +@@ -434,7 +434,11 @@ brcm_avs_get_freq_table(struct device *dev, struct private_data *priv) + if (ret) + return ERR_PTR(ret); + +- table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1, sizeof(*table), ++ /* ++ * We allocate space for the 5 different P-STATES AVS, ++ * plus extra space for a terminating element. ++ */ ++ table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1 + 1, sizeof(*table), + GFP_KERNEL); + if (!table) + return ERR_PTR(-ENOMEM); +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 6b52ebe5a8904..f11b01b25e8d5 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -455,8 +455,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, + policy->cur, + policy->cpuinfo.max_freq); + ++ spin_lock(&policy->transition_lock); + policy->transition_ongoing = false; + policy->transition_task = NULL; ++ spin_unlock(&policy->transition_lock); + + wake_up(&policy->transition_wait); + } +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index f29182512b982..1d025bf7dc079 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -2570,6 +2570,11 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) + intel_pstate_clear_update_util_hook(policy->cpu); + intel_pstate_hwp_set(policy->cpu); + } ++ /* ++ * policy->cur is never updated with the intel_pstate driver, but it ++ * is used as a stale frequency value. So, keep it within limits. ++ */ ++ policy->cur = policy->min; + + mutex_unlock(&intel_pstate_limits_lock); + +diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c +index d289036beff23..b10f7a1b77f11 100644 +--- a/drivers/cpufreq/powernow-k8.c ++++ b/drivers/cpufreq/powernow-k8.c +@@ -1101,7 +1101,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol) + + kfree(data->powernow_table); + kfree(data); +- for_each_cpu(cpu, pol->cpus) ++ /* pol->cpus will be empty here, use related_cpus instead. */ ++ for_each_cpu(cpu, pol->related_cpus) + per_cpu(powernow_data, cpu) = NULL; + + return 0; +diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c +index 36dad5ea59475..75f1e611d0aab 100644 +--- a/drivers/cpufreq/tegra194-cpufreq.c ++++ b/drivers/cpufreq/tegra194-cpufreq.c +@@ -508,6 +508,32 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy) + return 0; + } + ++static int tegra194_cpufreq_online(struct cpufreq_policy *policy) ++{ ++ /* We did light-weight tear down earlier, nothing to do here */ ++ return 0; ++} ++ ++static int tegra194_cpufreq_offline(struct cpufreq_policy *policy) ++{ ++ /* ++ * Preserve policy->driver_data and don't free resources on light-weight ++ * tear down. ++ */ ++ ++ return 0; ++} ++ ++static int tegra194_cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct device *cpu_dev = get_cpu_device(policy->cpu); ++ ++ dev_pm_opp_remove_all_dynamic(cpu_dev); ++ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); ++ ++ return 0; ++} ++ + static int tegra194_cpufreq_set_target(struct cpufreq_policy *policy, + unsigned int index) + { +@@ -535,6 +561,9 @@ static struct cpufreq_driver tegra194_cpufreq_driver = { + .target_index = tegra194_cpufreq_set_target, + .get = tegra194_get_speed, + .init = tegra194_cpufreq_init, ++ .exit = tegra194_cpufreq_exit, ++ .online = tegra194_cpufreq_online, ++ .offline = tegra194_cpufreq_offline, + .attr = cpufreq_generic_attr, + }; + +diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c +index a7d33f3ee01e7..14db9b7d985d1 100644 +--- a/drivers/cpuidle/cpuidle-pseries.c ++++ b/drivers/cpuidle/cpuidle-pseries.c +@@ -414,13 +414,7 @@ static int __init pseries_idle_probe(void) + return -ENODEV; + + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { +- /* +- * Use local_paca instead of get_lppaca() since +- * preemption is not disabled, and it is not required in +- * fact, since lppaca_ptr does not need to be the value +- * associated to the current CPU, it can be from any CPU. +- */ +- if (lppaca_shared_proc(local_paca->lppaca_ptr)) { ++ if (lppaca_shared_proc()) { + cpuidle_state_table = shared_states; + max_idle_state = ARRAY_SIZE(shared_states); + } else { +diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c +index 987fc5f3997dc..2cdc711679a5f 100644 +--- a/drivers/cpuidle/governors/teo.c ++++ b/drivers/cpuidle/governors/teo.c +@@ -397,13 +397,23 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + * the shallowest non-polling state and exit. + */ + if (drv->state_count < 3 && cpu_data->utilized) { +- for (i = 0; i < drv->state_count; ++i) { +- if (!dev->states_usage[i].disable && +- !(drv->states[i].flags & CPUIDLE_FLAG_POLLING)) { +- idx = i; +- goto end; +- } +- } ++ /* The CPU is utilized, so assume a short idle duration. */ ++ duration_ns = teo_middle_of_bin(0, drv); ++ /* ++ * If state 0 is enabled and it is not a polling one, select it ++ * right away unless the scheduler tick has been stopped, in ++ * which case care needs to be taken to leave the CPU in a deep ++ * enough state in case it is not woken up any time soon after ++ * all. If state 1 is disabled, though, state 0 must be used ++ * anyway. ++ */ ++ if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) && ++ teo_time_ok(duration_ns)) || dev->states_usage[1].disable) ++ idx = 0; ++ else /* Assume that state 1 is not a polling one and use it. */ ++ idx = 1; ++ ++ goto end; + } + + /* +@@ -539,10 +549,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + + /* + * If the CPU is being utilized over the threshold, choose a shallower +- * non-polling state to improve latency ++ * non-polling state to improve latency, unless the scheduler tick has ++ * been stopped already and the shallower state's target residency is ++ * not sufficiently large. + */ +- if (cpu_data->utilized) +- idx = teo_find_shallower_state(drv, dev, idx, duration_ns, true); ++ if (cpu_data->utilized) { ++ s64 span_ns; ++ ++ i = teo_find_shallower_state(drv, dev, idx, duration_ns, true); ++ span_ns = teo_middle_of_bin(i, drv); ++ if (teo_time_ok(span_ns)) { ++ idx = i; ++ duration_ns = span_ns; ++ } ++ } + + end: + /* +diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c +index 72afc249d42fb..7e08af751e4ea 100644 +--- a/drivers/crypto/caam/caampkc.c ++++ b/drivers/crypto/caam/caampkc.c +@@ -225,7 +225,9 @@ static int caam_rsa_count_leading_zeros(struct scatterlist *sgl, + if (len && *buff) + break; + +- sg_miter_next(&miter); ++ if (!sg_miter_next(&miter)) ++ break; ++ + buff = miter.addr; + len = miter.length; + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h +index f8f8a9ee29e5b..db4326933d1c0 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h ++++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h +@@ -35,7 +35,7 @@ + #define ADF_GEN4_PM_MSG_PENDING BIT(0) + #define ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK GENMASK(28, 1) + +-#define ADF_GEN4_PM_DEFAULT_IDLE_FILTER (0x0) ++#define ADF_GEN4_PM_DEFAULT_IDLE_FILTER (0x6) + #define ADF_GEN4_PM_MAX_IDLE_FILTER (0x7) + + int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev); +diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c +index f0df32382719c..fabae6da627b9 100644 +--- a/drivers/crypto/stm32/stm32-hash.c ++++ b/drivers/crypto/stm32/stm32-hash.c +@@ -492,7 +492,7 @@ static int stm32_hash_xmit_dma(struct stm32_hash_dev *hdev, + + reg = stm32_hash_read(hdev, HASH_CR); + +- if (!hdev->pdata->has_mdmat) { ++ if (hdev->pdata->has_mdmat) { + if (mdma) + reg |= HASH_CR_MDMAT; + else +@@ -627,9 +627,9 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev) + } + + for_each_sg(rctx->sg, tsg, rctx->nents, i) { ++ sg[0] = *tsg; + len = sg->length; + +- sg[0] = *tsg; + if (sg_is_last(sg)) { + if (hdev->dma_mode == 1) { + len = (ALIGN(sg->length, 16) - 16); +@@ -1705,9 +1705,7 @@ static int stm32_hash_remove(struct platform_device *pdev) + if (!hdev) + return -ENODEV; + +- ret = pm_runtime_resume_and_get(hdev->dev); +- if (ret < 0) +- return ret; ++ ret = pm_runtime_get_sync(hdev->dev); + + stm32_hash_unregister_algs(hdev); + +@@ -1723,7 +1721,8 @@ static int stm32_hash_remove(struct platform_device *pdev) + pm_runtime_disable(hdev->dev); + pm_runtime_put_noidle(hdev->dev); + +- clk_disable_unprepare(hdev->clk); ++ if (ret >= 0) ++ clk_disable_unprepare(hdev->clk); + + return 0; + } +diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c +index e36cbb920ec88..9464f8d3cb5b4 100644 +--- a/drivers/devfreq/devfreq.c ++++ b/drivers/devfreq/devfreq.c +@@ -763,6 +763,7 @@ static void devfreq_dev_release(struct device *dev) + dev_pm_opp_put_opp_table(devfreq->opp_table); + + mutex_destroy(&devfreq->lock); ++ srcu_cleanup_notifier_head(&devfreq->transition_notifier_list); + kfree(devfreq); + } + +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index f5f422f9b8507..b6221b4432fd3 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -211,6 +211,7 @@ config FSL_DMA + config FSL_EDMA + tristate "Freescale eDMA engine support" + depends on OF ++ depends on HAS_IOMEM + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help +@@ -280,6 +281,7 @@ config IMX_SDMA + + config INTEL_IDMA64 + tristate "Intel integrated DMA 64-bit support" ++ depends on HAS_IOMEM + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help +diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c +index 293739ac55969..a5c3eb4348325 100644 +--- a/drivers/dma/idxd/sysfs.c ++++ b/drivers/dma/idxd/sysfs.c +@@ -1095,8 +1095,8 @@ static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + +- if (!idxd->hw.wq_cap.wq_ats_support) +- return -EOPNOTSUPP; ++ if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) ++ return -EPERM; + + rc = kstrtobool(buf, &ats_dis); + if (rc < 0) +@@ -1131,8 +1131,8 @@ static ssize_t wq_prs_disable_store(struct device *dev, struct device_attribute + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + +- if (!idxd->hw.wq_cap.wq_prs_support) +- return -EOPNOTSUPP; ++ if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) ++ return -EPERM; + + rc = kstrtobool(buf, &prs_dis); + if (rc < 0) +@@ -1288,12 +1288,9 @@ static struct attribute *idxd_wq_attributes[] = { + NULL, + }; + +-static bool idxd_wq_attr_op_config_invisible(struct attribute *attr, +- struct idxd_device *idxd) +-{ +- return attr == &dev_attr_wq_op_config.attr && +- !idxd->hw.wq_cap.op_config; +-} ++/* A WQ attr is invisible if the feature is not supported in WQCAP. */ ++#define idxd_wq_attr_invisible(name, cap_field, a, idxd) \ ++ ((a) == &dev_attr_wq_##name.attr && !(idxd)->hw.wq_cap.cap_field) + + static bool idxd_wq_attr_max_batch_size_invisible(struct attribute *attr, + struct idxd_device *idxd) +@@ -1303,13 +1300,6 @@ static bool idxd_wq_attr_max_batch_size_invisible(struct attribute *attr, + idxd->data->type == IDXD_TYPE_IAX; + } + +-static bool idxd_wq_attr_wq_prs_disable_invisible(struct attribute *attr, +- struct idxd_device *idxd) +-{ +- return attr == &dev_attr_wq_prs_disable.attr && +- !idxd->hw.wq_cap.wq_prs_support; +-} +- + static umode_t idxd_wq_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) + { +@@ -1317,13 +1307,16 @@ static umode_t idxd_wq_attr_visible(struct kobject *kobj, + struct idxd_wq *wq = confdev_to_wq(dev); + struct idxd_device *idxd = wq->idxd; + +- if (idxd_wq_attr_op_config_invisible(attr, idxd)) ++ if (idxd_wq_attr_invisible(op_config, op_config, attr, idxd)) + return 0; + + if (idxd_wq_attr_max_batch_size_invisible(attr, idxd)) + return 0; + +- if (idxd_wq_attr_wq_prs_disable_invisible(attr, idxd)) ++ if (idxd_wq_attr_invisible(prs_disable, wq_prs_support, attr, idxd)) ++ return 0; ++ ++ if (idxd_wq_attr_invisible(ats_disable, wq_ats_support, attr, idxd)) + return 0; + + return attr->mode; +@@ -1480,7 +1473,7 @@ static ssize_t pasid_enabled_show(struct device *dev, + { + struct idxd_device *idxd = confdev_to_idxd(dev); + +- return sysfs_emit(buf, "%u\n", device_pasid_enabled(idxd)); ++ return sysfs_emit(buf, "%u\n", device_user_pasid_enabled(idxd)); + } + static DEVICE_ATTR_RO(pasid_enabled); + +diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c +index f093e08c23b16..3b09fdc507e04 100644 +--- a/drivers/dma/ste_dma40.c ++++ b/drivers/dma/ste_dma40.c +@@ -3597,6 +3597,10 @@ static int __init d40_probe(struct platform_device *pdev) + spin_lock_init(&base->lcla_pool.lock); + + base->irq = platform_get_irq(pdev, 0); ++ if (base->irq < 0) { ++ ret = base->irq; ++ goto destroy_cache; ++ } + + ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base); + if (ret) { +diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c +index a897b6aff3686..349ff6cfb3796 100644 +--- a/drivers/edac/i10nm_base.c ++++ b/drivers/edac/i10nm_base.c +@@ -658,13 +658,49 @@ static struct pci_dev *get_ddr_munit(struct skx_dev *d, int i, u32 *offset, unsi + return mdev; + } + ++/** ++ * i10nm_imc_absent() - Check whether the memory controller @imc is absent ++ * ++ * @imc : The pointer to the structure of memory controller EDAC device. ++ * ++ * RETURNS : true if the memory controller EDAC device is absent, false otherwise. ++ */ ++static bool i10nm_imc_absent(struct skx_imc *imc) ++{ ++ u32 mcmtr; ++ int i; ++ ++ switch (res_cfg->type) { ++ case SPR: ++ for (i = 0; i < res_cfg->ddr_chan_num; i++) { ++ mcmtr = I10NM_GET_MCMTR(imc, i); ++ edac_dbg(1, "ch%d mcmtr reg %x\n", i, mcmtr); ++ if (mcmtr != ~0) ++ return false; ++ } ++ ++ /* ++ * Some workstations' absent memory controllers still ++ * appear as PCIe devices, misleading the EDAC driver. ++ * By observing that the MMIO registers of these absent ++ * memory controllers consistently hold the value of ~0. ++ * ++ * We identify a memory controller as absent by checking ++ * if its MMIO register "mcmtr" == ~0 in all its channels. ++ */ ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int i10nm_get_ddr_munits(void) + { + struct pci_dev *mdev; + void __iomem *mbase; + unsigned long size; + struct skx_dev *d; +- int i, j = 0; ++ int i, lmc, j = 0; + u32 reg, off; + u64 base; + +@@ -690,7 +726,7 @@ static int i10nm_get_ddr_munits(void) + edac_dbg(2, "socket%d mmio base 0x%llx (reg 0x%x)\n", + j++, base, reg); + +- for (i = 0; i < res_cfg->ddr_imc_num; i++) { ++ for (lmc = 0, i = 0; i < res_cfg->ddr_imc_num; i++) { + mdev = get_ddr_munit(d, i, &off, &size); + + if (i == 0 && !mdev) { +@@ -700,8 +736,6 @@ static int i10nm_get_ddr_munits(void) + if (!mdev) + continue; + +- d->imc[i].mdev = mdev; +- + edac_dbg(2, "mc%d mmio base 0x%llx size 0x%lx (reg 0x%x)\n", + i, base + off, size, reg); + +@@ -712,7 +746,17 @@ static int i10nm_get_ddr_munits(void) + return -ENODEV; + } + +- d->imc[i].mbase = mbase; ++ d->imc[lmc].mbase = mbase; ++ if (i10nm_imc_absent(&d->imc[lmc])) { ++ pci_dev_put(mdev); ++ iounmap(mbase); ++ d->imc[lmc].mbase = NULL; ++ edac_dbg(2, "Skip absent mc%d\n", i); ++ continue; ++ } else { ++ d->imc[lmc].mdev = mdev; ++ lmc++; ++ } + } + } + +diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c +index 544dd19072eab..1a18693294db4 100644 +--- a/drivers/edac/igen6_edac.c ++++ b/drivers/edac/igen6_edac.c +@@ -27,7 +27,7 @@ + #include "edac_mc.h" + #include "edac_module.h" + +-#define IGEN6_REVISION "v2.5" ++#define IGEN6_REVISION "v2.5.1" + + #define EDAC_MOD_STR "igen6_edac" + #define IGEN6_NMI_NAME "igen6_ibecc" +@@ -1216,9 +1216,6 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + INIT_WORK(&ecclog_work, ecclog_work_cb); + init_irq_work(&ecclog_irq_work, ecclog_irq_work_cb); + +- /* Check if any pending errors before registering the NMI handler */ +- ecclog_handler(); +- + rc = register_err_handler(); + if (rc) + goto fail3; +@@ -1230,6 +1227,9 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + goto fail4; + } + ++ /* Check if any pending errors before/during the registration of the error handler */ ++ ecclog_handler(); ++ + igen6_debug_setup(); + return 0; + fail4: +diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig +index 290186e44e6bd..4dd52a6a5b48d 100644 +--- a/drivers/extcon/Kconfig ++++ b/drivers/extcon/Kconfig +@@ -62,6 +62,7 @@ config EXTCON_INTEL_CHT_WC + tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver" + depends on INTEL_SOC_PMIC_CHTWC + depends on USB_SUPPORT ++ depends on POWER_SUPPLY + select USB_ROLE_SWITCH + help + Say Y here to enable extcon support for charger detection / control +diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c +index f9040bd610812..285fe7ad490d1 100644 +--- a/drivers/firmware/arm_sdei.c ++++ b/drivers/firmware/arm_sdei.c +@@ -1095,3 +1095,22 @@ int sdei_event_handler(struct pt_regs *regs, + return err; + } + NOKPROBE_SYMBOL(sdei_event_handler); ++ ++void sdei_handler_abort(void) ++{ ++ /* ++ * If the crash happened in an SDEI event handler then we need to ++ * finish the handler with the firmware so that we can have working ++ * interrupts in the crash kernel. ++ */ ++ if (__this_cpu_read(sdei_active_critical_event)) { ++ pr_warn("still in SDEI critical event context, attempting to finish handler.\n"); ++ __sdei_handler_abort(); ++ __this_cpu_write(sdei_active_critical_event, NULL); ++ } ++ if (__this_cpu_read(sdei_active_normal_event)) { ++ pr_warn("still in SDEI normal event context, attempting to finish handler.\n"); ++ __sdei_handler_abort(); ++ __this_cpu_write(sdei_active_normal_event, NULL); ++ } ++} +diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c +index ec056f6f40ce8..cc3a28f386a77 100644 +--- a/drivers/firmware/cirrus/cs_dsp.c ++++ b/drivers/firmware/cirrus/cs_dsp.c +@@ -978,7 +978,8 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, + ctl->alg_region.alg == alg_region->alg && + ctl->alg_region.type == alg_region->type) { + if ((!subname && !ctl->subname) || +- (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) { ++ (subname && (ctl->subname_len == subname_len) && ++ !strncmp(ctl->subname, subname, ctl->subname_len))) { + if (!ctl->enabled) + ctl->enabled = 1; + return 0; +diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c +index a0bfd31358ba9..9ae0d6d0c285f 100644 +--- a/drivers/firmware/efi/libstub/x86-stub.c ++++ b/drivers/firmware/efi/libstub/x86-stub.c +@@ -61,7 +61,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) + rom->data.type = SETUP_PCI; + rom->data.len = size - sizeof(struct setup_data); + rom->data.next = 0; +- rom->pcilen = pci->romsize; ++ rom->pcilen = romsize; + *__rom = rom; + + status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16, +diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c +index 798bcdb05d84e..9a2656d73600b 100644 +--- a/drivers/firmware/meson/meson_sm.c ++++ b/drivers/firmware/meson/meson_sm.c +@@ -292,6 +292,8 @@ static int __init meson_sm_probe(struct platform_device *pdev) + return -ENOMEM; + + chip = of_match_device(meson_sm_ids, dev)->data; ++ if (!chip) ++ return -EINVAL; + + if (chip->cmd_shmem_in_base) { + fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, +diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c +index 039d92a595ec6..91aaa0ca9bde8 100644 +--- a/drivers/firmware/ti_sci.c ++++ b/drivers/firmware/ti_sci.c +@@ -97,7 +97,6 @@ struct ti_sci_desc { + * @node: list head + * @host_id: Host ID + * @users: Number of users of this instance +- * @is_suspending: Flag set to indicate in suspend path. + */ + struct ti_sci_info { + struct device *dev; +@@ -116,7 +115,6 @@ struct ti_sci_info { + u8 host_id; + /* protected by ti_sci_list_mutex */ + int users; +- bool is_suspending; + }; + + #define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl) +@@ -418,14 +416,14 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info, + + ret = 0; + +- if (!info->is_suspending) { ++ if (system_state <= SYSTEM_RUNNING) { + /* And we wait for the response. */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); + if (!wait_for_completion_timeout(&xfer->done, timeout)) + ret = -ETIMEDOUT; + } else { + /* +- * If we are suspending, we cannot use wait_for_completion_timeout ++ * If we are !running, we cannot use wait_for_completion_timeout + * during noirq phase, so we must manually poll the completion. + */ + ret = read_poll_timeout_atomic(try_wait_for_completion, done_state, +@@ -3281,35 +3279,6 @@ static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode, + return NOTIFY_BAD; + } + +-static void ti_sci_set_is_suspending(struct ti_sci_info *info, bool is_suspending) +-{ +- info->is_suspending = is_suspending; +-} +- +-static int ti_sci_suspend(struct device *dev) +-{ +- struct ti_sci_info *info = dev_get_drvdata(dev); +- /* +- * We must switch operation to polled mode now as drivers and the genpd +- * layer may make late TI SCI calls to change clock and device states +- * from the noirq phase of suspend. +- */ +- ti_sci_set_is_suspending(info, true); +- +- return 0; +-} +- +-static int ti_sci_resume(struct device *dev) +-{ +- struct ti_sci_info *info = dev_get_drvdata(dev); +- +- ti_sci_set_is_suspending(info, false); +- +- return 0; +-} +- +-static DEFINE_SIMPLE_DEV_PM_OPS(ti_sci_pm_ops, ti_sci_suspend, ti_sci_resume); +- + /* Description for K2G */ + static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { + .default_host_id = 2, +@@ -3516,7 +3485,6 @@ static struct platform_driver ti_sci_driver = { + .driver = { + .name = "ti-sci", + .of_match_table = of_match_ptr(ti_sci_of_match), +- .pm = &ti_sci_pm_ops, + }, + }; + module_platform_driver(ti_sci_driver); +diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c +index 7cec1772820d3..5eccab175e86b 100644 +--- a/drivers/fsi/fsi-master-aspeed.c ++++ b/drivers/fsi/fsi-master-aspeed.c +@@ -454,6 +454,8 @@ static ssize_t cfam_reset_store(struct device *dev, struct device_attribute *att + gpiod_set_value(aspeed->cfam_reset_gpio, 1); + usleep_range(900, 1000); + gpiod_set_value(aspeed->cfam_reset_gpio, 0); ++ usleep_range(900, 1000); ++ opb_writel(aspeed, ctrl_base + FSI_MRESP0, cpu_to_be32(FSI_MRESP_RST_ALL_MASTER)); + mutex_unlock(&aspeed->lock); + trace_fsi_master_aspeed_cfam_reset(false); + +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index 5be8ad61523eb..6e7701f80929f 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -2175,12 +2175,18 @@ static bool gpiod_free_commit(struct gpio_desc *desc) + + void gpiod_free(struct gpio_desc *desc) + { +- if (desc && desc->gdev && gpiod_free_commit(desc)) { +- module_put(desc->gdev->owner); +- gpio_device_put(desc->gdev); +- } else { ++ /* ++ * We must not use VALIDATE_DESC_VOID() as the underlying gdev->chip ++ * may already be NULL but we still want to put the references. ++ */ ++ if (!desc) ++ return; ++ ++ if (!gpiod_free_commit(desc)) + WARN_ON(extra_checks); +- } ++ ++ module_put(desc->gdev->owner); ++ gpio_device_put(desc->gdev); + } + + /** +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 3108f5219cf3b..f7770e9c9aaca 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -1231,6 +1231,9 @@ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev) + u16 cmd; + int r; + ++ if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) ++ return 0; ++ + /* Bypass for VF */ + if (amdgpu_sriov_vf(adev)) + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index 724e80c192973..cecae6c1e8935 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -556,6 +556,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + crtc = (struct drm_crtc *)minfo->crtcs[i]; + if (crtc && crtc->base.id == info->mode_crtc.id) { + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); ++ + ui32 = amdgpu_crtc->crtc_id; + found = 1; + break; +@@ -574,7 +575,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + if (ret) + return ret; + +- ret = copy_to_user(out, &ip, min((size_t)size, sizeof(ip))); ++ ret = copy_to_user(out, &ip, min_t(size_t, size, sizeof(ip))); + return ret ? -EFAULT : 0; + } + case AMDGPU_INFO_HW_IP_COUNT: { +@@ -720,17 +721,18 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { +- unsigned n, alloc_size; ++ unsigned int n, alloc_size; + uint32_t *regs; +- unsigned se_num = (info->read_mmr_reg.instance >> ++ unsigned int se_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SE_INDEX_MASK; +- unsigned sh_num = (info->read_mmr_reg.instance >> ++ unsigned int sh_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; + + /* set full masks if the userspace set all bits +- * in the bitfields */ ++ * in the bitfields ++ */ + if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) + se_num = 0xffffffff; + else if (se_num >= AMDGPU_GFX_MAX_SE) +@@ -882,7 +884,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + return ret; + } + case AMDGPU_INFO_VCE_CLOCK_TABLE: { +- unsigned i; ++ unsigned int i; + struct drm_amdgpu_info_vce_clock_table vce_clk_table = {}; + struct amd_vce_state *vce_state; + +diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c +index de6d10390ab2f..9be6da37032a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik.c +@@ -1574,17 +1574,8 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev) + u16 bridge_cfg2, gpu_cfg2; + u32 max_lw, current_lw, tmp; + +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &bridge_cfg); +- pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL, +- &gpu_cfg); +- +- tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); +- +- tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + + tmp = RREG32_PCIE(ixPCIE_LC_STATUS1); + max_lw = (tmp & PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH_MASK) >> +@@ -1637,21 +1628,14 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev) + msleep(100); + + /* linkctl */ +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, +- tmp16); +- +- pcie_capability_read_word(adev->pdev, +- PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(adev->pdev, +- PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ bridge_cfg & ++ PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_clear_and_set_word(adev->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ gpu_cfg & ++ PCI_EXP_LNKCTL_HAWD); + + /* linkctl2 */ + pcie_capability_read_word(root, PCI_EXP_LNKCTL2, +diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +index caee76ab71105..92f2ee412908d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +@@ -136,14 +136,15 @@ static int psp_v13_0_wait_for_bootloader(struct psp_context *psp) + int ret; + int retry_loop; + ++ /* Wait for bootloader to signify that it is ready having bit 31 of ++ * C2PMSG_35 set to 1. All other bits are expected to be cleared. ++ * If there is an error in processing command, bits[7:0] will be set. ++ * This is applicable for PSP v13.0.6 and newer. ++ */ + for (retry_loop = 0; retry_loop < 10; retry_loop++) { +- /* Wait for bootloader to signify that is +- ready having bit 31 of C2PMSG_35 set to 1 */ +- ret = psp_wait_for(psp, +- SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35), +- 0x80000000, +- 0x80000000, +- false); ++ ret = psp_wait_for( ++ psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35), ++ 0x80000000, 0xffffffff, false); + + if (ret == 0) + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c +index 7f99e130acd06..fd34c2100bd96 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si.c ++++ b/drivers/gpu/drm/amd/amdgpu/si.c +@@ -2276,17 +2276,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + u16 bridge_cfg2, gpu_cfg2; + u32 max_lw, current_lw, tmp; + +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &bridge_cfg); +- pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL, +- &gpu_cfg); +- +- tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); +- +- tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + + tmp = RREG32_PCIE(PCIE_LC_STATUS1); + max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; +@@ -2331,21 +2322,14 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + + mdelay(100); + +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, +- tmp16); +- +- pcie_capability_read_word(adev->pdev, +- PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(adev->pdev, +- PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ bridge_cfg & ++ PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_clear_and_set_word(adev->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ gpu_cfg & ++ PCI_EXP_LNKCTL_HAWD); + + pcie_capability_read_word(root, PCI_EXP_LNKCTL2, + &tmp16); +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 4dd9a85f5c724..e20d55edb0209 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -7993,10 +7993,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + * fast updates. + */ + if (crtc->state->async_flip && +- acrtc_state->update_type != UPDATE_TYPE_FAST) ++ (acrtc_state->update_type != UPDATE_TYPE_FAST || ++ get_mem_type(old_plane_state->fb) != get_mem_type(fb))) + drm_warn_once(state->dev, + "[PLANE:%d:%s] async flip with non-fast update\n", + plane->base.id, plane->name); ++ + bundle->flip_addrs[planes_count].flip_immediate = + crtc->state->async_flip && + acrtc_state->update_type == UPDATE_TYPE_FAST && +@@ -9953,6 +9955,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + + /* Remove exiting planes if they are modified */ + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { ++ if (old_plane_state->fb && new_plane_state->fb && ++ get_mem_type(old_plane_state->fb) != ++ get_mem_type(new_plane_state->fb)) ++ lock_and_validation_needed = true; ++ + ret = dm_update_plane_state(dc, state, plane, + old_plane_state, + new_plane_state, +@@ -10200,9 +10207,20 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + struct dm_crtc_state *dm_new_crtc_state = + to_dm_crtc_state(new_crtc_state); + ++ /* ++ * Only allow async flips for fast updates that don't change ++ * the FB pitch, the DCC state, rotation, etc. ++ */ ++ if (new_crtc_state->async_flip && lock_and_validation_needed) { ++ drm_dbg_atomic(crtc->dev, ++ "[CRTC:%d:%s] async flips are only supported for fast updates\n", ++ crtc->base.id, crtc->name); ++ ret = -EINVAL; ++ goto fail; ++ } ++ + dm_new_crtc_state->update_type = lock_and_validation_needed ? +- UPDATE_TYPE_FULL : +- UPDATE_TYPE_FAST; ++ UPDATE_TYPE_FULL : UPDATE_TYPE_FAST; + } + + /* Must be success */ +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 30d4c6fd95f53..440fc0869a34b 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 +@@ -398,18 +398,6 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, + return -EINVAL; + } + +- /* +- * Only allow async flips for fast updates that don't change the FB +- * pitch, the DCC state, rotation, etc. +- */ +- if (crtc_state->async_flip && +- dm_crtc_state->update_type != UPDATE_TYPE_FAST) { +- drm_dbg_atomic(crtc->dev, +- "[CRTC:%d:%s] async flips are only supported for fast updates\n", +- crtc->base.id, crtc->name); +- return -EINVAL; +- } +- + /* In some use cases, like reset, no stream is attached */ + if (!dm_crtc_state->stream) + return 0; +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c +index 925d6e13620ec..1bbf85defd611 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c +@@ -32,6 +32,7 @@ + + #define MAX_INSTANCE 6 + #define MAX_SEGMENT 6 ++#define SMU_REGISTER_WRITE_RETRY_COUNT 5 + + struct IP_BASE_INSTANCE + { +@@ -134,6 +135,8 @@ static int dcn315_smu_send_msg_with_param( + unsigned int msg_id, unsigned int param) + { + uint32_t result; ++ uint32_t i = 0; ++ uint32_t read_back_data; + + result = dcn315_smu_wait_for_response(clk_mgr, 10, 200000); + +@@ -150,10 +153,19 @@ static int dcn315_smu_send_msg_with_param( + /* Set the parameter register for the SMU message, unit is Mhz */ + REG_WRITE(MP1_SMN_C2PMSG_37, param); + +- /* Trigger the message transaction by writing the message ID */ +- generic_write_indirect_reg(CTX, +- REG_NBIO(RSMU_INDEX), REG_NBIO(RSMU_DATA), +- mmMP1_C2PMSG_3, msg_id); ++ for (i = 0; i < SMU_REGISTER_WRITE_RETRY_COUNT; i++) { ++ /* Trigger the message transaction by writing the message ID */ ++ generic_write_indirect_reg(CTX, ++ REG_NBIO(RSMU_INDEX), REG_NBIO(RSMU_DATA), ++ mmMP1_C2PMSG_3, msg_id); ++ read_back_data = generic_read_indirect_reg(CTX, ++ REG_NBIO(RSMU_INDEX), REG_NBIO(RSMU_DATA), ++ mmMP1_C2PMSG_3); ++ if (read_back_data == msg_id) ++ break; ++ udelay(2); ++ smu_print("SMU msg id write fail %x times. \n", i + 1); ++ } + + result = dcn315_smu_wait_for_response(clk_mgr, 10, 200000); + +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +index 58e8fda04b861..ad28fdd87797f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +@@ -1795,10 +1795,13 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) + hws->funcs.edp_backlight_control(edp_link_with_sink, false); + } + /*resume from S3, no vbios posting, no need to power down again*/ ++ clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr); ++ + power_down_all_hw_blocks(dc); + disable_vga_and_power_gate_all_controllers(dc); + if (edp_link_with_sink && !keep_edp_vdd_on) + dc->hwss.edp_power_control(edp_link_with_sink, false); ++ clk_mgr_optimize_pwr_state(dc, dc->clk_mgr); + } + bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1); + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +index 6192851c59ed8..51265a812bdc8 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +@@ -75,6 +75,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = { + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, ++ .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +index 65c1d754e2d6b..01cc679ae4186 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +@@ -84,7 +84,8 @@ static enum phyd32clk_clock_source get_phy_mux_symclk( + struct dcn_dccg *dccg_dcn, + enum phyd32clk_clock_source src) + { +- if (dccg_dcn->base.ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { ++ if (dccg_dcn->base.ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && ++ dccg_dcn->base.ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + if (src == PHYD32CLKC) + src = PHYD32CLKF; + if (src == PHYD32CLKD) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +index b878effa2129b..b428a343add9c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +@@ -33,7 +33,7 @@ + #include "dml/display_mode_vba.h" + + struct _vcs_dpi_ip_params_st dcn3_14_ip = { +- .VBlankNomDefaultUS = 800, ++ .VBlankNomDefaultUS = 668, + .gpuvm_enable = 1, + .gpuvm_max_page_table_levels = 1, + .hostvm_enable = 1, +diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c +index f4f40459f22b9..a5b2a7d943f71 100644 +--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c ++++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c +@@ -2195,15 +2195,19 @@ static int amdgpu_device_attr_create(struct amdgpu_device *adev, + uint32_t mask, struct list_head *attr_list) + { + int ret = 0; +- struct device_attribute *dev_attr = &attr->dev_attr; +- const char *name = dev_attr->attr.name; + enum amdgpu_device_attr_states attr_states = ATTR_STATE_SUPPORTED; + struct amdgpu_device_attr_entry *attr_entry; ++ struct device_attribute *dev_attr; ++ const char *name; + + int (*attr_update)(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, + uint32_t mask, enum amdgpu_device_attr_states *states) = default_attr_update; + +- BUG_ON(!attr); ++ if (!attr) ++ return -EINVAL; ++ ++ dev_attr = &attr->dev_attr; ++ name = dev_attr->attr.name; + + attr_update = attr->attr_update ? attr->attr_update : default_attr_update; + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +index d7f09af2fb018..419a247dfbbf2 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +@@ -1323,7 +1323,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, + gpu_metrics->average_vclk1_frequency = metrics->AverageVclk1Frequency; + gpu_metrics->average_dclk1_frequency = metrics->AverageDclk1Frequency; + +- gpu_metrics->current_gfxclk = metrics->CurrClock[PPCLK_GFXCLK]; ++ gpu_metrics->current_gfxclk = gpu_metrics->average_gfxclk_frequency; + gpu_metrics->current_socclk = metrics->CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics->CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics->CurrClock[PPCLK_VCLK_0]; +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +index c9093517b1bda..bfa020fe0d4fe 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +@@ -697,16 +697,19 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, + *value = SMUQ10_TO_UINT(metrics->SocketPower) << 8; + break; + case METRICS_TEMPERATURE_HOTSPOT: +- *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature); ++ *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature) * ++ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: +- *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature); ++ *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature) * ++ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + /* This is the max of all VRs and not just SOC VR. + * No need to define another data type for the same. + */ + case METRICS_TEMPERATURE_VRSOC: +- *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature); ++ *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature) * ++ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = smu_v13_0_6_get_throttler_status(smu, metrics); +diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c +index f21eb8fb76d87..3b9bd8ecda137 100644 +--- a/drivers/gpu/drm/armada/armada_overlay.c ++++ b/drivers/gpu/drm/armada/armada_overlay.c +@@ -4,6 +4,8 @@ + * Rewritten from the dovefb driver, and Armada510 manuals. + */ + ++#include <linux/bitfield.h> ++ + #include <drm/armada_drm.h> + #include <drm/drm_atomic.h> + #include <drm/drm_atomic_helper.h> +@@ -445,8 +447,8 @@ static int armada_overlay_get_property(struct drm_plane *plane, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 0); + } else if (property == priv->colorkey_mode_prop) { +- *val = (drm_to_overlay_state(state)->colorkey_mode & +- CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK); ++ *val = FIELD_GET(CFG_CKMODE_MASK, ++ drm_to_overlay_state(state)->colorkey_mode); + } else if (property == priv->brightness_prop) { + *val = drm_to_overlay_state(state)->brightness + 256; + } else if (property == priv->contrast_prop) { +diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c +index 6dc1a09504e13..fdd9a493aa9c0 100644 +--- a/drivers/gpu/drm/ast/ast_dp.c ++++ b/drivers/gpu/drm/ast/ast_dp.c +@@ -7,6 +7,17 @@ + #include <drm/drm_print.h> + #include "ast_drv.h" + ++bool ast_astdp_is_connected(struct ast_device *ast) ++{ ++ if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING)) ++ return false; ++ if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)) ++ return false; ++ if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS)) ++ return false; ++ return true; ++} ++ + int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) + { + struct ast_device *ast = to_ast_device(dev); +diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c +index 1bc35a992369d..fa7442b0c2612 100644 +--- a/drivers/gpu/drm/ast/ast_dp501.c ++++ b/drivers/gpu/drm/ast/ast_dp501.c +@@ -272,11 +272,9 @@ static bool ast_launch_m68k(struct drm_device *dev) + return true; + } + +-bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) ++bool ast_dp501_is_connected(struct ast_device *ast) + { +- struct ast_device *ast = to_ast_device(dev); +- u32 i, boot_address, offset, data; +- u32 *pEDIDidx; ++ u32 boot_address, offset, data; + + if (ast->config_mode == ast_use_p2a) { + boot_address = get_fw_base(ast); +@@ -292,14 +290,6 @@ bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) + data = ast_mindwm(ast, boot_address + offset); + if (!(data & AST_DP501_PNP_CONNECTED)) + return false; +- +- /* Read EDID */ +- offset = AST_DP501_EDID_DATA; +- for (i = 0; i < 128; i += 4) { +- data = ast_mindwm(ast, boot_address + offset + i); +- pEDIDidx = (u32 *)(ediddata + i); +- *pEDIDidx = data; +- } + } else { + if (!ast->dp501_fw_buf) + return false; +@@ -319,7 +309,30 @@ bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) + data = readl(ast->dp501_fw_buf + offset); + if (!(data & AST_DP501_PNP_CONNECTED)) + return false; ++ } ++ return true; ++} ++ ++bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) ++{ ++ struct ast_device *ast = to_ast_device(dev); ++ u32 i, boot_address, offset, data; ++ u32 *pEDIDidx; ++ ++ if (!ast_dp501_is_connected(ast)) ++ return false; ++ ++ if (ast->config_mode == ast_use_p2a) { ++ boot_address = get_fw_base(ast); + ++ /* Read EDID */ ++ offset = AST_DP501_EDID_DATA; ++ for (i = 0; i < 128; i += 4) { ++ data = ast_mindwm(ast, boot_address + offset + i); ++ pEDIDidx = (u32 *)(ediddata + i); ++ *pEDIDidx = data; ++ } ++ } else { + /* Read EDID */ + offset = AST_DP501_EDID_DATA; + for (i = 0; i < 128; i += 4) { +diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h +index 5498a6676f2e8..8a0ffa8b5939b 100644 +--- a/drivers/gpu/drm/ast/ast_drv.h ++++ b/drivers/gpu/drm/ast/ast_drv.h +@@ -468,6 +468,7 @@ void ast_patch_ahb_2500(struct ast_device *ast); + /* ast dp501 */ + void ast_set_dp501_video_output(struct drm_device *dev, u8 mode); + bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); ++bool ast_dp501_is_connected(struct ast_device *ast); + bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); + u8 ast_get_dp501_max_clk(struct drm_device *dev); + void ast_init_3rdtx(struct drm_device *dev); +@@ -476,6 +477,7 @@ void ast_init_3rdtx(struct drm_device *dev); + struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev); + + /* aspeed DP */ ++bool ast_astdp_is_connected(struct ast_device *ast); + int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata); + void ast_dp_launch(struct drm_device *dev); + void ast_dp_power_on_off(struct drm_device *dev, bool no); +diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c +index b3c670af6ef2b..0724516f29737 100644 +--- a/drivers/gpu/drm/ast/ast_mode.c ++++ b/drivers/gpu/drm/ast/ast_mode.c +@@ -1585,8 +1585,20 @@ err_drm_connector_update_edid_property: + return 0; + } + ++static int ast_dp501_connector_helper_detect_ctx(struct drm_connector *connector, ++ struct drm_modeset_acquire_ctx *ctx, ++ bool force) ++{ ++ struct ast_device *ast = to_ast_device(connector->dev); ++ ++ if (ast_dp501_is_connected(ast)) ++ return connector_status_connected; ++ return connector_status_disconnected; ++} ++ + static const struct drm_connector_helper_funcs ast_dp501_connector_helper_funcs = { + .get_modes = ast_dp501_connector_helper_get_modes, ++ .detect_ctx = ast_dp501_connector_helper_detect_ctx, + }; + + static const struct drm_connector_funcs ast_dp501_connector_funcs = { +@@ -1611,7 +1623,7 @@ static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + + return 0; + } +@@ -1683,8 +1695,20 @@ err_drm_connector_update_edid_property: + return 0; + } + ++static int ast_astdp_connector_helper_detect_ctx(struct drm_connector *connector, ++ struct drm_modeset_acquire_ctx *ctx, ++ bool force) ++{ ++ struct ast_device *ast = to_ast_device(connector->dev); ++ ++ if (ast_astdp_is_connected(ast)) ++ return connector_status_connected; ++ return connector_status_disconnected; ++} ++ + static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = { + .get_modes = ast_astdp_connector_helper_get_modes, ++ .detect_ctx = ast_astdp_connector_helper_detect_ctx, + }; + + static const struct drm_connector_funcs ast_astdp_connector_funcs = { +@@ -1709,7 +1733,7 @@ static int ast_astdp_connector_init(struct drm_device *dev, struct drm_connector + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + + return 0; + } +@@ -1848,5 +1872,7 @@ int ast_mode_config_init(struct ast_device *ast) + + drm_mode_config_reset(dev); + ++ drm_kms_helper_poll_init(dev); ++ + return 0; + } +diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +index ddceafa7b6374..8d6c93296503e 100644 +--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c ++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +@@ -786,8 +786,13 @@ static void adv7511_mode_set(struct adv7511 *adv7511, + else + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE; + +- regmap_update_bits(adv7511->regmap, 0xfb, +- 0x6, low_refresh_rate << 1); ++ if (adv7511->type == ADV7511) ++ regmap_update_bits(adv7511->regmap, 0xfb, ++ 0x6, low_refresh_rate << 1); ++ else ++ regmap_update_bits(adv7511->regmap, 0x4a, ++ 0xc, low_refresh_rate << 2); ++ + regmap_update_bits(adv7511->regmap, 0x17, + 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); + +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c +index 9e387c3e9b696..666a2b5c0c5c0 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.c ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c +@@ -873,11 +873,11 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) + } + + /* Read downstream capability */ +- ret = anx7625_aux_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap); ++ ret = anx7625_aux_trans(ctx, DP_AUX_NATIVE_READ, DP_AUX_HDCP_BCAPS, 1, &bcap); + if (ret < 0) + return ret; + +- if (!(bcap & 0x01)) { ++ if (!(bcap & DP_BCAPS_HDCP_CAPABLE)) { + pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); + return 0; + } +@@ -932,8 +932,8 @@ static void anx7625_dp_start(struct anx7625_data *ctx) + + dev_dbg(dev, "set downstream sink into normal\n"); + /* Downstream sink enter into normal mode */ +- data = 1; +- ret = anx7625_aux_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); ++ data = DP_SET_POWER_D0; ++ ret = anx7625_aux_trans(ctx, DP_AUX_NATIVE_WRITE, DP_SET_POWER, 1, &data); + if (ret < 0) + dev_err(dev, "IO error : set sink into normal mode fail\n"); + +@@ -972,8 +972,8 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) + + dev_dbg(dev, "notify downstream enter into standby\n"); + /* Downstream monitor enter into standby mode */ +- data = 2; +- ret |= anx7625_aux_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); ++ data = DP_SET_POWER_D3; ++ ret |= anx7625_aux_trans(ctx, DP_AUX_NATIVE_WRITE, DP_SET_POWER, 1, &data); + if (ret < 0) + DRM_DEV_ERROR(dev, "IO error : mute video fail\n"); + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +index b2efecf7d1603..4291798bd70f5 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +@@ -265,6 +265,7 @@ struct dw_mipi_dsi { + struct dw_mipi_dsi *master; /* dual-dsi master ptr */ + struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */ + ++ struct drm_display_mode mode; + const struct dw_mipi_dsi_plat_data *plat_data; + }; + +@@ -332,6 +333,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + ++ bridge->pre_enable_prev_first = true; + dsi->panel_bridge = bridge; + + drm_bridge_add(&dsi->bridge); +@@ -859,15 +861,6 @@ static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, + */ + dw_mipi_dsi_set_mode(dsi, 0); + +- /* +- * TODO Only way found to call panel-bridge post_disable & +- * panel unprepare before the dsi "final" disable... +- * This needs to be fixed in the drm_bridge framework and the API +- * needs to be updated to manage our own call chains... +- */ +- if (dsi->panel_bridge->funcs->post_disable) +- dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); +- + if (phy_ops->power_off) + phy_ops->power_off(dsi->plat_data->priv_data); + +@@ -942,15 +935,25 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, + phy_ops->power_on(dsi->plat_data->priv_data); + } + ++static void dw_mipi_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) ++{ ++ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); ++ ++ /* Power up the dsi ctl into a command mode */ ++ dw_mipi_dsi_mode_set(dsi, &dsi->mode); ++ if (dsi->slave) ++ dw_mipi_dsi_mode_set(dsi->slave, &dsi->mode); ++} ++ + static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) + { + struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); + +- dw_mipi_dsi_mode_set(dsi, adjusted_mode); +- if (dsi->slave) +- dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); ++ /* Store the display mode for later use in pre_enable callback */ ++ drm_mode_copy(&dsi->mode, adjusted_mode); + } + + static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, +@@ -1004,6 +1007,7 @@ static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, ++ .atomic_pre_enable = dw_mipi_dsi_bridge_atomic_pre_enable, + .atomic_enable = dw_mipi_dsi_bridge_atomic_enable, + .atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable, + .mode_set = dw_mipi_dsi_bridge_mode_set, +diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c +index f85654f1b1045..8e938a7480f37 100644 +--- a/drivers/gpu/drm/bridge/tc358764.c ++++ b/drivers/gpu/drm/bridge/tc358764.c +@@ -176,7 +176,7 @@ static void tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val) + if (ret >= 0) + le32_to_cpus(val); + +- dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val); ++ dev_dbg(ctx->dev, "read: addr=0x%04x data=0x%08x\n", addr, *val); + } + + static void tc358764_write(struct tc358764 *ctx, u16 addr, u32 val) +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c +index 44b5f3c35aabe..898f84a0fc30c 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c +@@ -130,9 +130,9 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) + return; + etnaviv_dump_core = false; + +- mutex_lock(&gpu->mmu_context->lock); ++ mutex_lock(&submit->mmu_context->lock); + +- mmu_size = etnaviv_iommu_dump_size(gpu->mmu_context); ++ mmu_size = etnaviv_iommu_dump_size(submit->mmu_context); + + /* We always dump registers, mmu, ring, hanging cmdbuf and end marker */ + n_obj = 5; +@@ -162,7 +162,7 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) + iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN | + __GFP_NORETRY); + if (!iter.start) { +- mutex_unlock(&gpu->mmu_context->lock); ++ mutex_unlock(&submit->mmu_context->lock); + dev_warn(gpu->dev, "failed to allocate devcoredump file\n"); + return; + } +@@ -174,18 +174,18 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) + memset(iter.hdr, 0, iter.data - iter.start); + + etnaviv_core_dump_registers(&iter, gpu); +- etnaviv_core_dump_mmu(&iter, gpu->mmu_context, mmu_size); ++ etnaviv_core_dump_mmu(&iter, submit->mmu_context, mmu_size); + etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer.vaddr, + gpu->buffer.size, + etnaviv_cmdbuf_get_va(&gpu->buffer, +- &gpu->mmu_context->cmdbuf_mapping)); ++ &submit->mmu_context->cmdbuf_mapping)); + + etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, + submit->cmdbuf.vaddr, submit->cmdbuf.size, + etnaviv_cmdbuf_get_va(&submit->cmdbuf, +- &gpu->mmu_context->cmdbuf_mapping)); ++ &submit->mmu_context->cmdbuf_mapping)); + +- mutex_unlock(&gpu->mmu_context->lock); ++ mutex_unlock(&submit->mmu_context->lock); + + /* Reserve space for the bomap */ + if (n_bomap_pages) { +diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +index f830d62a5ce60..559ce242919df 100644 +--- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c ++++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +@@ -7,6 +7,7 @@ + #include <linux/hyperv.h> + #include <linux/module.h> + #include <linux/pci.h> ++#include <linux/screen_info.h> + + #include <drm/drm_aperture.h> + #include <drm/drm_atomic_helper.h> +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +index c0a38f5217eee..f2f6a5c01a6d2 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c ++++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +@@ -426,7 +426,7 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma + continue; + } + +- type = (enum mtk_ovl_adaptor_comp_type)of_id->data; ++ type = (enum mtk_ovl_adaptor_comp_type)(uintptr_t)of_id->data; + id = ovl_adaptor_comp_get_id(dev, node, type); + if (id < 0) { + dev_warn(dev, "Skipping unknown component %pOF\n", +diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c +index 64eee77452c04..c58b775877a31 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dp.c ++++ b/drivers/gpu/drm/mediatek/mtk_dp.c +@@ -1588,7 +1588,9 @@ static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp) + u8 val; + ssize_t ret; + +- drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap); ++ ret = drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap); ++ if (ret < 0) ++ return ret; + + if (drm_dp_tps4_supported(mtk_dp->rx_cap)) + mtk_dp->train_info.channel_eq_pattern = DP_TRAINING_PATTERN_4; +@@ -1615,10 +1617,13 @@ static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp) + return ret == 0 ? -EIO : ret; + } + +- if (val) +- drm_dp_dpcd_writeb(&mtk_dp->aux, +- DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0, +- val); ++ if (val) { ++ ret = drm_dp_dpcd_writeb(&mtk_dp->aux, ++ DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0, ++ val); ++ if (ret < 0) ++ return ret; ++ } + } + + return 0; +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index d40142842f85c..8d44f3df116fa 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -116,10 +116,9 @@ static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt * + dma_addr_t dma_addr; + + pkt->va_base = kzalloc(size, GFP_KERNEL); +- if (!pkt->va_base) { +- kfree(pkt); ++ if (!pkt->va_base) + return -ENOMEM; +- } ++ + pkt->buf_size = size; + pkt->cl = (void *)client; + +@@ -129,7 +128,6 @@ static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt * + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); + kfree(pkt->va_base); +- kfree(pkt); + return -ENOMEM; + } + +@@ -145,7 +143,6 @@ static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt) + dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, + DMA_TO_DEVICE); + kfree(pkt->va_base); +- kfree(pkt); + } + #endif + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +index f114da4d36a96..771f4e1733539 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -563,14 +563,15 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, + /* Not all drm components have a DTS device node, such as ovl_adaptor, + * which is the drm bring up sub driver + */ +- if (node) { +- comp_pdev = of_find_device_by_node(node); +- if (!comp_pdev) { +- DRM_INFO("Waiting for device %s\n", node->full_name); +- return -EPROBE_DEFER; +- } +- comp->dev = &comp_pdev->dev; ++ if (!node) ++ return 0; ++ ++ comp_pdev = of_find_device_by_node(node); ++ if (!comp_pdev) { ++ DRM_INFO("Waiting for device %s\n", node->full_name); ++ return -EPROBE_DEFER; + } ++ comp->dev = &comp_pdev->dev; + + if (type == MTK_DISP_AAL || + type == MTK_DISP_BLS || +@@ -580,7 +581,6 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, + type == MTK_DISP_MERGE || + type == MTK_DISP_OVL || + type == MTK_DISP_OVL_2L || +- type == MTK_DISP_OVL_ADAPTOR || + type == MTK_DISP_PWM || + type == MTK_DISP_RDMA || + type == MTK_DPI || +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +index 6dcb4ba2466c0..30d10f21562f4 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +@@ -354,7 +354,7 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) + const struct of_device_id *of_id; + struct device_node *node; + struct device *drm_dev; +- int cnt = 0; ++ unsigned int cnt = 0; + int i, j; + + for_each_child_of_node(phandle->parent, node) { +@@ -375,6 +375,9 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) + all_drm_priv[cnt] = dev_get_drvdata(drm_dev); + if (all_drm_priv[cnt] && all_drm_priv[cnt]->mtk_drm_bound) + cnt++; ++ ++ if (cnt == MAX_CRTC) ++ break; + } + + if (drm_priv->data->mmsys_dev_num == cnt) { +@@ -829,7 +832,7 @@ static int mtk_drm_probe(struct platform_device *pdev) + continue; + } + +- comp_type = (enum mtk_ddp_comp_type)of_id->data; ++ comp_type = (enum mtk_ddp_comp_type)(uintptr_t)of_id->data; + + if (comp_type == MTK_DISP_MUTEX) { + int id; +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c +index a25b28d3ee902..9f364df52478d 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c +@@ -247,7 +247,11 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) + + mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); +- ++ if (!mtk_gem->kvaddr) { ++ kfree(sgt); ++ kfree(mtk_gem->pages); ++ return -ENOMEM; ++ } + out: + kfree(sgt); + iosys_map_set_vaddr(map, mtk_gem->kvaddr); +diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +index c67089a7ebc10..ad4570d60abf2 100644 +--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +@@ -540,6 +540,10 @@ struct msm_gpu *a2xx_gpu_init(struct drm_device *dev) + gpu->perfcntrs = perfcntrs; + gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs); + ++ ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); ++ if (ret) ++ goto fail; ++ + if (adreno_is_a20x(adreno_gpu)) + adreno_gpu->registers = a200_registers; + else if (adreno_is_a225(adreno_gpu)) +@@ -547,10 +551,6 @@ struct msm_gpu *a2xx_gpu_init(struct drm_device *dev) + else + adreno_gpu->registers = a220_registers; + +- ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); +- if (ret) +- goto fail; +- + if (!gpu->aspace) { + dev_err(dev->dev, "No memory protection without MMU\n"); + if (!allow_vram_carveout) { +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +index 8914992378f21..1ff2a71e1aea5 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +@@ -1472,8 +1472,15 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + struct platform_device *pdev = to_platform_device(gmu->dev); + +- if (!gmu->initialized) ++ mutex_lock(&gmu->lock); ++ if (!gmu->initialized) { ++ mutex_unlock(&gmu->lock); + return; ++ } ++ ++ gmu->initialized = false; ++ ++ mutex_unlock(&gmu->lock); + + pm_runtime_force_suspend(gmu->dev); + +@@ -1501,8 +1508,6 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) + + /* Drop reference taken in of_find_device_by_node */ + put_device(gmu->dev); +- +- gmu->initialized = false; + } + + static int cxpd_notifier_cb(struct notifier_block *nb, +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 411b7a5fa2f32..bdda1a6336543 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -1697,9 +1697,7 @@ static void a6xx_destroy(struct msm_gpu *gpu) + + a6xx_llc_slices_destroy(a6xx_gpu); + +- mutex_lock(&a6xx_gpu->gmu.lock); + a6xx_gmu_remove(a6xx_gpu); +- mutex_unlock(&a6xx_gpu->gmu.lock); + + adreno_gpu_cleanup(adreno_gpu); + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +index ff9ccf72a4bf9..6560eeef00143 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +@@ -195,7 +195,6 @@ const struct dpu_mdss_cfg dpu_msm8998_cfg = { + .intf = msm8998_intf, + .vbif_count = ARRAY_SIZE(msm8998_vbif), + .vbif = msm8998_vbif, +- .reg_dma_count = 0, + .perf = &msm8998_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +index 5b9b3b99f1b5f..84159f8cbdaeb 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +@@ -193,8 +193,6 @@ const struct dpu_mdss_cfg dpu_sdm845_cfg = { + .intf = sdm845_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sdm845_regdma, + .perf = &sdm845_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +index 074ba54d420f4..266c525f8daaf 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +@@ -220,8 +220,6 @@ const struct dpu_mdss_cfg dpu_sm8150_cfg = { + .intf = sm8150_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sm8150_regdma, + .perf = &sm8150_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +index 0540d21810857..76c5745c2fa1f 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +@@ -198,8 +198,6 @@ const struct dpu_mdss_cfg dpu_sc8180x_cfg = { + .intf = sc8180x_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sm8150_regdma, + .perf = &sc8180x_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +index b3284de35b8fa..8660d04d0f589 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +@@ -228,8 +228,6 @@ const struct dpu_mdss_cfg dpu_sm8250_cfg = { + .vbif = sdm845_vbif, + .wb_count = ARRAY_SIZE(sm8250_wb), + .wb = sm8250_wb, +- .reg_dma_count = 1, +- .dma_cfg = &sm8250_regdma, + .perf = &sm8250_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +index 88c211876516a..9631116f99e9b 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +@@ -147,8 +147,6 @@ const struct dpu_mdss_cfg dpu_sc7180_cfg = { + .wb = sc7180_wb, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sdm845_regdma, + .perf = &sc7180_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +index 4f6a965bcd90b..9e8d6632a1927 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +@@ -211,8 +211,6 @@ const struct dpu_mdss_cfg dpu_sm8350_cfg = { + .intf = sm8350_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sm8350_regdma, + .perf = &sm8350_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +index 706d0f13b598e..cb58b4ec97db4 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +@@ -202,8 +202,6 @@ const struct dpu_mdss_cfg dpu_sc8280xp_cfg = { + .intf = sc8280xp_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sc8280xp_regdma, + .perf = &sc8280xp_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +index 8bd4bb97e639c..905b403ffb0fb 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +@@ -219,8 +219,6 @@ const struct dpu_mdss_cfg dpu_sm8450_cfg = { + .intf = sm8450_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sm8450_regdma, + .perf = &sm8450_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +index d0ab351b6a8b9..a6e4763660bb0 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +@@ -222,10 +222,8 @@ const struct dpu_mdss_cfg dpu_sm8550_cfg = { + .merge_3d = sm8550_merge_3d, + .intf_count = ARRAY_SIZE(sm8550_intf), + .intf = sm8550_intf, +- .vbif_count = ARRAY_SIZE(sdm845_vbif), +- .vbif = sdm845_vbif, +- .reg_dma_count = 1, +- .dma_cfg = &sm8450_regdma, ++ .vbif_count = ARRAY_SIZE(sm8550_vbif), ++ .vbif = sm8550_vbif, + .perf = &sm8550_perf_data, + .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +index bac4aa807b4bc..2553d6374482b 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +@@ -455,7 +455,8 @@ static int dpu_encoder_phys_wb_wait_for_commit_done( + wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + +- ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE, ++ ret = dpu_encoder_helper_wait_for_irq(phys_enc, ++ phys_enc->irq[INTR_IDX_WB_DONE], + dpu_encoder_phys_wb_done_irq, &wait_info); + if (ret == -ETIMEDOUT) + _dpu_encoder_phys_wb_handle_wbdone_timeout(phys_enc); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +index 0b604f31197bb..23c16d25b62f5 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +@@ -642,44 +642,24 @@ static const struct dpu_vbif_cfg sdm845_vbif[] = { + }, + }; + +-static const struct dpu_reg_dma_cfg sc8280xp_regdma = { +- .base = 0x0, +- .version = 0x00020000, +- .trigger_sel_off = 0x119c, +- .xin_id = 7, +- .clk_ctrl = DPU_CLK_CTRL_REG_DMA, +-}; +- +-static const struct dpu_reg_dma_cfg sdm845_regdma = { +- .base = 0x0, .version = 0x1, .trigger_sel_off = 0x119c +-}; +- +-static const struct dpu_reg_dma_cfg sm8150_regdma = { +- .base = 0x0, .version = 0x00010001, .trigger_sel_off = 0x119c +-}; +- +-static const struct dpu_reg_dma_cfg sm8250_regdma = { +- .base = 0x0, +- .version = 0x00010002, +- .trigger_sel_off = 0x119c, +- .xin_id = 7, +- .clk_ctrl = DPU_CLK_CTRL_REG_DMA, +-}; +- +-static const struct dpu_reg_dma_cfg sm8350_regdma = { +- .base = 0x400, +- .version = 0x00020000, +- .trigger_sel_off = 0x119c, +- .xin_id = 7, +- .clk_ctrl = DPU_CLK_CTRL_REG_DMA, +-}; +- +-static const struct dpu_reg_dma_cfg sm8450_regdma = { +- .base = 0x0, +- .version = 0x00020000, +- .trigger_sel_off = 0x119c, +- .xin_id = 7, +- .clk_ctrl = DPU_CLK_CTRL_REG_DMA, ++static const struct dpu_vbif_cfg sm8550_vbif[] = { ++ { ++ .name = "vbif_rt", .id = VBIF_RT, ++ .base = 0, .len = 0x1040, ++ .features = BIT(DPU_VBIF_QOS_REMAP), ++ .xin_halt_timeout = 0x4000, ++ .qos_rp_remap_size = 0x40, ++ .qos_rt_tbl = { ++ .npriority_lvl = ARRAY_SIZE(sdm845_rt_pri_lvl), ++ .priority_lvl = sdm845_rt_pri_lvl, ++ }, ++ .qos_nrt_tbl = { ++ .npriority_lvl = ARRAY_SIZE(sdm845_nrt_pri_lvl), ++ .priority_lvl = sdm845_nrt_pri_lvl, ++ }, ++ .memtype_count = 16, ++ .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, ++ }, + }; + + /************************************************************* +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +index 71584cd56fd75..8d62c21b051a8 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +@@ -720,21 +720,6 @@ struct dpu_vbif_cfg { + u32 memtype_count; + u32 memtype[MAX_XIN_COUNT]; + }; +-/** +- * struct dpu_reg_dma_cfg - information of lut dma blocks +- * @id enum identifying this block +- * @base register offset of this block +- * @features bit mask identifying sub-blocks/features +- * @version version of lutdma hw block +- * @trigger_sel_off offset to trigger select registers of lutdma +- */ +-struct dpu_reg_dma_cfg { +- DPU_HW_BLK_INFO; +- u32 version; +- u32 trigger_sel_off; +- u32 xin_id; +- enum dpu_clk_ctrl_type clk_ctrl; +-}; + + /** + * Define CDP use cases +@@ -850,9 +835,6 @@ struct dpu_mdss_cfg { + u32 wb_count; + const struct dpu_wb_cfg *wb; + +- u32 reg_dma_count; +- const struct dpu_reg_dma_cfg *dma_cfg; +- + u32 ad_count; + + u32 dspp_count; +diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +index bd2c4ac456017..0d5ff03cb0910 100644 +--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c ++++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +@@ -130,8 +130,7 @@ static void mdp5_plane_destroy_state(struct drm_plane *plane, + { + struct mdp5_plane_state *pstate = to_mdp5_plane_state(state); + +- if (state->fb) +- drm_framebuffer_put(state->fb); ++ __drm_atomic_helper_plane_destroy_state(state); + + kfree(pstate); + } +diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +index acfe1b31e0792..add72bbc28b17 100644 +--- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c ++++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +@@ -192,5 +192,5 @@ void msm_disp_snapshot_add_block(struct msm_disp_state *disp_state, u32 len, + new_blk->base_addr = base_addr; + + msm_disp_state_dump_regs(&new_blk->state, new_blk->size, base_addr); +- list_add(&new_blk->node, &disp_state->blocks); ++ list_add_tail(&new_blk->node, &disp_state->blocks); + } +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index cf6b146acc323..23c1b1a96df64 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1159,7 +1159,9 @@ static const struct panel_desc auo_t215hvn01 = { + .delay = { + .disable = 5, + .unprepare = 1000, +- } ++ }, ++ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, ++ .connector_type = DRM_MODE_CONNECTOR_LVDS, + }; + + static const struct drm_display_mode avic_tm070ddh03_mode = { +diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c +index 5819737c21c67..a6f3c811ceb8e 100644 +--- a/drivers/gpu/drm/radeon/cik.c ++++ b/drivers/gpu/drm/radeon/cik.c +@@ -9534,17 +9534,8 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) + u16 bridge_cfg2, gpu_cfg2; + u32 max_lw, current_lw, tmp; + +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &bridge_cfg); +- pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL, +- &gpu_cfg); +- +- tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); +- +- tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + + tmp = RREG32_PCIE_PORT(PCIE_LC_STATUS1); + max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; +@@ -9591,21 +9582,14 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) + msleep(100); + + /* linkctl */ +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, +- tmp16); +- +- pcie_capability_read_word(rdev->pdev, +- PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(rdev->pdev, +- PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ bridge_cfg & ++ PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ gpu_cfg & ++ PCI_EXP_LNKCTL_HAWD); + + /* linkctl2 */ + pcie_capability_read_word(root, PCI_EXP_LNKCTL2, +diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c +index 8d5e4b25609d5..a91012447b56e 100644 +--- a/drivers/gpu/drm/radeon/si.c ++++ b/drivers/gpu/drm/radeon/si.c +@@ -7131,17 +7131,8 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) + u16 bridge_cfg2, gpu_cfg2; + u32 max_lw, current_lw, tmp; + +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &bridge_cfg); +- pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL, +- &gpu_cfg); +- +- tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); +- +- tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; +- pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + + tmp = RREG32_PCIE(PCIE_LC_STATUS1); + max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; +@@ -7188,22 +7179,14 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) + msleep(100); + + /* linkctl */ +- pcie_capability_read_word(root, PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(root, +- PCI_EXP_LNKCTL, +- tmp16); +- +- pcie_capability_read_word(rdev->pdev, +- PCI_EXP_LNKCTL, +- &tmp16); +- tmp16 &= ~PCI_EXP_LNKCTL_HAWD; +- tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); +- pcie_capability_write_word(rdev->pdev, +- PCI_EXP_LNKCTL, +- tmp16); ++ pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ bridge_cfg & ++ PCI_EXP_LNKCTL_HAWD); ++ pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_HAWD, ++ gpu_cfg & ++ PCI_EXP_LNKCTL_HAWD); + + /* linkctl2 */ + pcie_capability_read_word(root, PCI_EXP_LNKCTL2, +diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c +index 4d2677dcd8315..68ded2e34e1cf 100644 +--- a/drivers/gpu/drm/tegra/dpaux.c ++++ b/drivers/gpu/drm/tegra/dpaux.c +@@ -468,7 +468,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) + + dpaux->irq = platform_get_irq(pdev, 0); + if (dpaux->irq < 0) +- return -ENXIO; ++ return dpaux->irq; + + if (!pdev->dev.pm_domain) { + dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); +diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c +index c2677d081a7b6..13ae148f59b9b 100644 +--- a/drivers/gpu/drm/tiny/repaper.c ++++ b/drivers/gpu/drm/tiny/repaper.c +@@ -533,7 +533,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb) + DRM_DEBUG("Flushing [FB:%d] st=%ums\n", fb->base.id, + epd->factored_stage_time); + +- buf = kmalloc_array(fb->width, fb->height, GFP_KERNEL); ++ buf = kmalloc(fb->width * fb->height / 8, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out_exit; +diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +index bab862484d429..068413be65275 100644 +--- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c ++++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +@@ -227,7 +227,9 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) + dpsub->dev = &pdev->dev; + platform_set_drvdata(pdev, dpsub); + +- dma_set_mask(dpsub->dev, DMA_BIT_MASK(ZYNQMP_DISP_MAX_DMA_BIT)); ++ ret = dma_set_mask(dpsub->dev, DMA_BIT_MASK(ZYNQMP_DISP_MAX_DMA_BIT)); ++ if (ret) ++ return ret; + + /* Try the reserved memory. Proceed if there's none. */ + of_reserved_mem_device_init(&pdev->dev); +diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c +index 851ee86eff32a..40a5645f8fe81 100644 +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -988,6 +988,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel + return; + + case 0x3c: /* Invert */ ++ device->quirks &= ~HID_QUIRK_NOINVERT; + map_key_clear(BTN_TOOL_RUBBER); + break; + +@@ -1013,9 +1014,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel + case 0x45: /* ERASER */ + /* + * This event is reported when eraser tip touches the surface. +- * Actual eraser (BTN_TOOL_RUBBER) is set by Invert usage when +- * tool gets in proximity. ++ * Actual eraser (BTN_TOOL_RUBBER) is set and released either ++ * by Invert if tool reports proximity or by Eraser directly. + */ ++ if (!test_bit(BTN_TOOL_RUBBER, input->keybit)) { ++ device->quirks |= HID_QUIRK_NOINVERT; ++ set_bit(BTN_TOOL_RUBBER, input->keybit); ++ } + map_key_clear(BTN_TOUCH); + break; + +@@ -1580,6 +1585,15 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct + else if (report->tool != BTN_TOOL_RUBBER) + /* value is off, tool is not rubber, ignore */ + return; ++ else if (*quirks & HID_QUIRK_NOINVERT && ++ !test_bit(BTN_TOUCH, input->key)) { ++ /* ++ * There is no invert to release the tool, let hid_input ++ * send BTN_TOUCH with scancode and release the tool after. ++ */ ++ hid_report_release_tool(report, input, BTN_TOOL_RUBBER); ++ return; ++ } + + /* let hid-input set BTN_TOUCH */ + break; +diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c +index 62180414efccd..e6a8b6d8eab70 100644 +--- a/drivers/hid/hid-logitech-dj.c ++++ b/drivers/hid/hid-logitech-dj.c +@@ -1285,6 +1285,9 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, + * 50 msec should gives enough time to the receiver to be ready. + */ + msleep(50); ++ ++ if (retval) ++ return retval; + } + + /* +@@ -1306,7 +1309,7 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, + buf[5] = 0x09; + buf[6] = 0x00; + +- hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf, ++ retval = hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf, + HIDPP_REPORT_SHORT_LENGTH, HID_OUTPUT_REPORT, + HID_REQ_SET_REPORT); + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index dfe8e09a18de0..e461ddaf10e80 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -275,21 +275,22 @@ static int __hidpp_send_report(struct hid_device *hdev, + } + + /* +- * hidpp_send_message_sync() returns 0 in case of success, and something else +- * in case of a failure. +- * - If ' something else' is positive, that means that an error has been raised +- * by the protocol itself. +- * - If ' something else' is negative, that means that we had a classic error +- * (-ENOMEM, -EPIPE, etc...) ++ * Effectively send the message to the device, waiting for its answer. ++ * ++ * Must be called with hidpp->send_mutex locked ++ * ++ * Same return protocol than hidpp_send_message_sync(): ++ * - success on 0 ++ * - negative error means transport error ++ * - positive value means protocol error + */ +-static int hidpp_send_message_sync(struct hidpp_device *hidpp, ++static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + struct hidpp_report *message, + struct hidpp_report *response) + { +- int ret = -1; +- int max_retries = 3; ++ int ret; + +- mutex_lock(&hidpp->send_mutex); ++ __must_hold(&hidpp->send_mutex); + + hidpp->send_receive_buf = response; + hidpp->answer_available = false; +@@ -300,47 +301,74 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, + */ + *response = *message; + +- for (; max_retries != 0 && ret; max_retries--) { +- ret = __hidpp_send_report(hidpp->hid_dev, message); ++ ret = __hidpp_send_report(hidpp->hid_dev, message); ++ if (ret) { ++ dbg_hid("__hidpp_send_report returned err: %d\n", ret); ++ memset(response, 0, sizeof(struct hidpp_report)); ++ return ret; ++ } + +- if (ret) { +- dbg_hid("__hidpp_send_report returned err: %d\n", ret); +- memset(response, 0, sizeof(struct hidpp_report)); +- break; +- } ++ if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, ++ 5*HZ)) { ++ dbg_hid("%s:timeout waiting for response\n", __func__); ++ memset(response, 0, sizeof(struct hidpp_report)); ++ return -ETIMEDOUT; ++ } + +- if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, +- 5*HZ)) { +- dbg_hid("%s:timeout waiting for response\n", __func__); +- memset(response, 0, sizeof(struct hidpp_report)); +- ret = -ETIMEDOUT; +- break; +- } ++ if (response->report_id == REPORT_ID_HIDPP_SHORT && ++ response->rap.sub_id == HIDPP_ERROR) { ++ ret = response->rap.params[1]; ++ dbg_hid("%s:got hidpp error %02X\n", __func__, ret); ++ return ret; ++ } + +- if (response->report_id == REPORT_ID_HIDPP_SHORT && +- response->rap.sub_id == HIDPP_ERROR) { +- ret = response->rap.params[1]; +- dbg_hid("%s:got hidpp error %02X\n", __func__, ret); ++ if ((response->report_id == REPORT_ID_HIDPP_LONG || ++ response->report_id == REPORT_ID_HIDPP_VERY_LONG) && ++ response->fap.feature_index == HIDPP20_ERROR) { ++ ret = response->fap.params[1]; ++ dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ++ * hidpp_send_message_sync() returns 0 in case of success, and something else ++ * in case of a failure. ++ * ++ * See __do_hidpp_send_message_sync() for a detailed explanation of the returned ++ * value. ++ */ ++static int hidpp_send_message_sync(struct hidpp_device *hidpp, ++ struct hidpp_report *message, ++ struct hidpp_report *response) ++{ ++ int ret; ++ int max_retries = 3; ++ ++ mutex_lock(&hidpp->send_mutex); ++ ++ do { ++ ret = __do_hidpp_send_message_sync(hidpp, message, response); ++ if (ret != HIDPP20_ERROR_BUSY) + break; +- } + +- if ((response->report_id == REPORT_ID_HIDPP_LONG || +- response->report_id == REPORT_ID_HIDPP_VERY_LONG) && +- response->fap.feature_index == HIDPP20_ERROR) { +- ret = response->fap.params[1]; +- if (ret != HIDPP20_ERROR_BUSY) { +- dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); +- break; +- } +- dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret); +- } +- } ++ dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret); ++ } while (--max_retries); + + mutex_unlock(&hidpp->send_mutex); + return ret; + + } + ++/* ++ * hidpp_send_fap_command_sync() returns 0 in case of success, and something else ++ * in case of a failure. ++ * ++ * See __do_hidpp_send_message_sync() for a detailed explanation of the returned ++ * value. ++ */ + static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, + u8 feat_index, u8 funcindex_clientid, u8 *params, int param_count, + struct hidpp_report *response) +@@ -373,6 +401,13 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, + return ret; + } + ++/* ++ * hidpp_send_rap_command_sync() returns 0 in case of success, and something else ++ * in case of a failure. ++ * ++ * See __do_hidpp_send_message_sync() for a detailed explanation of the returned ++ * value. ++ */ + static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev, + u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count, + struct hidpp_report *response) +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e31be0cb8b850..521b2ffb42449 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -1594,7 +1594,6 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +- char *name; + const char *suffix = NULL; + struct mt_report_data *rdata; + struct mt_application *mt_application = NULL; +@@ -1645,15 +1644,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + break; + } + +- if (suffix) { +- name = devm_kzalloc(&hi->input->dev, +- strlen(hdev->name) + strlen(suffix) + 2, +- GFP_KERNEL); +- if (name) { +- sprintf(name, "%s %s", hdev->name, suffix); +- hi->input->name = name; +- } +- } ++ if (suffix) ++ hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, ++ "%s %s", hdev->name, suffix); + + return 0; + } +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index f67835f9ed4cc..ad74cbc9a0aa5 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -85,10 +85,8 @@ static int uclogic_input_configured(struct hid_device *hdev, + { + struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); + struct uclogic_params *params = &drvdata->params; +- char *name; + const char *suffix = NULL; + struct hid_field *field; +- size_t len; + size_t i; + const struct uclogic_params_frame *frame; + +@@ -146,14 +144,9 @@ static int uclogic_input_configured(struct hid_device *hdev, + } + } + +- if (suffix) { +- len = strlen(hdev->name) + 2 + strlen(suffix); +- name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL); +- if (name) { +- snprintf(name, len, "%s %s", hdev->name, suffix); +- hi->input->name = name; +- } +- } ++ if (suffix) ++ hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, ++ "%s %s", hdev->name, suffix); + + return 0; + } +diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c +index 67f95a29aeca5..edbb38f6956b9 100644 +--- a/drivers/hv/vmbus_drv.c ++++ b/drivers/hv/vmbus_drv.c +@@ -2287,7 +2287,8 @@ static int vmbus_acpi_add(struct platform_device *pdev) + * Some ancestor of the vmbus acpi device (Gen1 or Gen2 + * firmware) is the VMOD that has the mmio ranges. Get that. + */ +- for (ancestor = acpi_dev_parent(device); ancestor; ++ for (ancestor = acpi_dev_parent(device); ++ ancestor && ancestor->handle != ACPI_ROOT_OBJECT; + ancestor = acpi_dev_parent(ancestor)) { + result = acpi_walk_resources(ancestor->handle, METHOD_NAME__CRS, + vmbus_walk_resources, NULL); +diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c +index 0693eaee054ff..a8167a48f824c 100644 +--- a/drivers/hwmon/tmp513.c ++++ b/drivers/hwmon/tmp513.c +@@ -434,7 +434,7 @@ static umode_t tmp51x_is_visible(const void *_data, + + switch (type) { + case hwmon_temp: +- if (data->id == tmp512 && channel == 4) ++ if (data->id == tmp512 && channel == 3) + return 0; + switch (attr) { + case hwmon_temp_input: +diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c +index 0ab1f73c2d06a..e374b02d98be3 100644 +--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c ++++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c +@@ -450,7 +450,7 @@ static int tmc_set_etf_buffer(struct coresight_device *csdev, + return -EINVAL; + + /* wrap head around to the amount of space we have */ +- head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1); ++ head = handle->head & (((unsigned long)buf->nr_pages << PAGE_SHIFT) - 1); + + /* find the page to write to */ + buf->cur = head / PAGE_SIZE; +diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c +index eaa296ced1678..8ef4a2a13427e 100644 +--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c ++++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c +@@ -45,7 +45,8 @@ struct etr_perf_buffer { + }; + + /* Convert the perf index to an offset within the ETR buffer */ +-#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT)) ++#define PERF_IDX2OFF(idx, buf) \ ++ ((idx) % ((unsigned long)(buf)->nr_pages << PAGE_SHIFT)) + + /* Lower limit for ETR hardware buffer */ + #define TMC_ETR_PERF_MIN_BUF_SIZE SZ_1M +@@ -1262,7 +1263,7 @@ alloc_etr_buf(struct tmc_drvdata *drvdata, struct perf_event *event, + * than the size requested via sysfs. + */ + if ((nr_pages << PAGE_SHIFT) > drvdata->size) { +- etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT), ++ etr_buf = tmc_alloc_etr_buf(drvdata, ((ssize_t)nr_pages << PAGE_SHIFT), + 0, node, NULL); + if (!IS_ERR(etr_buf)) + goto done; +diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h +index 01c0382a29c0a..26e6356261c11 100644 +--- a/drivers/hwtracing/coresight/coresight-tmc.h ++++ b/drivers/hwtracing/coresight/coresight-tmc.h +@@ -325,7 +325,7 @@ ssize_t tmc_sg_table_get_data(struct tmc_sg_table *sg_table, + static inline unsigned long + tmc_sg_table_buf_size(struct tmc_sg_table *sg_table) + { +- return sg_table->data_pages.nr_pages << PAGE_SHIFT; ++ return (unsigned long)sg_table->data_pages.nr_pages << PAGE_SHIFT; + } + + struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata); +diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c +index 1fc4fd79a1c69..925f6c9cecff4 100644 +--- a/drivers/hwtracing/coresight/coresight-trbe.c ++++ b/drivers/hwtracing/coresight/coresight-trbe.c +@@ -1223,6 +1223,16 @@ static void arm_trbe_enable_cpu(void *info) + enable_percpu_irq(drvdata->irq, IRQ_TYPE_NONE); + } + ++static void arm_trbe_disable_cpu(void *info) ++{ ++ struct trbe_drvdata *drvdata = info; ++ struct trbe_cpudata *cpudata = this_cpu_ptr(drvdata->cpudata); ++ ++ disable_percpu_irq(drvdata->irq); ++ trbe_reset_local(cpudata); ++} ++ ++ + static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cpu) + { + struct trbe_cpudata *cpudata = per_cpu_ptr(drvdata->cpudata, cpu); +@@ -1324,18 +1334,12 @@ cpu_clear: + cpumask_clear_cpu(cpu, &drvdata->supported_cpus); + } + +-static void arm_trbe_remove_coresight_cpu(void *info) ++static void arm_trbe_remove_coresight_cpu(struct trbe_drvdata *drvdata, int cpu) + { +- int cpu = smp_processor_id(); +- struct trbe_drvdata *drvdata = info; +- struct trbe_cpudata *cpudata = per_cpu_ptr(drvdata->cpudata, cpu); + struct coresight_device *trbe_csdev = coresight_get_percpu_sink(cpu); + +- disable_percpu_irq(drvdata->irq); +- trbe_reset_local(cpudata); + if (trbe_csdev) { + coresight_unregister(trbe_csdev); +- cpudata->drvdata = NULL; + coresight_set_percpu_sink(cpu, NULL); + } + } +@@ -1364,8 +1368,10 @@ static int arm_trbe_remove_coresight(struct trbe_drvdata *drvdata) + { + int cpu; + +- for_each_cpu(cpu, &drvdata->supported_cpus) +- smp_call_function_single(cpu, arm_trbe_remove_coresight_cpu, drvdata, 1); ++ for_each_cpu(cpu, &drvdata->supported_cpus) { ++ smp_call_function_single(cpu, arm_trbe_disable_cpu, drvdata, 1); ++ arm_trbe_remove_coresight_cpu(drvdata, cpu); ++ } + free_percpu(drvdata->cpudata); + return 0; + } +@@ -1404,12 +1410,8 @@ static int arm_trbe_cpu_teardown(unsigned int cpu, struct hlist_node *node) + { + struct trbe_drvdata *drvdata = hlist_entry_safe(node, struct trbe_drvdata, hotplug_node); + +- if (cpumask_test_cpu(cpu, &drvdata->supported_cpus)) { +- struct trbe_cpudata *cpudata = per_cpu_ptr(drvdata->cpudata, cpu); +- +- disable_percpu_irq(drvdata->irq); +- trbe_reset_local(cpudata); +- } ++ if (cpumask_test_cpu(cpu, &drvdata->supported_cpus)) ++ arm_trbe_disable_cpu(drvdata); + return 0; + } + +diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c +index 4d24ceb57ee74..338171f76daf7 100644 +--- a/drivers/i2c/busses/i2c-imx-lpi2c.c ++++ b/drivers/i2c/busses/i2c-imx-lpi2c.c +@@ -209,6 +209,9 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) + lpi2c_imx_set_mode(lpi2c_imx); + + clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk); ++ if (!clk_rate) ++ return -EINVAL; ++ + if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST) + filt = 0; + else +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index 79b08942a925d..964d51dd39a47 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -782,6 +782,10 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, + */ + break; + } else if (SVC_I3C_MSTATUS_NACKED(reg)) { ++ /* No I3C devices attached */ ++ if (dev_nb == 0) ++ break; ++ + /* + * A slave device nacked the address, this is + * allowed only once, DAA will be stopped and +@@ -1251,11 +1255,17 @@ static int svc_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, + { + struct svc_i3c_master *master = to_svc_i3c_master(m); + bool broadcast = cmd->id < 0x80; ++ int ret; + + if (broadcast) +- return svc_i3c_master_send_bdcast_ccc_cmd(master, cmd); ++ ret = svc_i3c_master_send_bdcast_ccc_cmd(master, cmd); + else +- return svc_i3c_master_send_direct_ccc_cmd(master, cmd); ++ ret = svc_i3c_master_send_direct_ccc_cmd(master, cmd); ++ ++ if (ret) ++ cmd->err = I3C_ERROR_M2; ++ ++ return ret; + } + + static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev, +diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c +index 99cc7fc294882..68785bd3ef2f0 100644 +--- a/drivers/iio/accel/adxl313_i2c.c ++++ b/drivers/iio/accel/adxl313_i2c.c +@@ -40,8 +40,8 @@ static const struct regmap_config adxl31x_i2c_regmap_config[] = { + + static const struct i2c_device_id adxl313_i2c_id[] = { + { .name = "adxl312", .driver_data = (kernel_ulong_t)&adxl31x_chip_info[ADXL312] }, +- { .name = "adxl313", .driver_data = (kernel_ulong_t)&adxl31x_chip_info[ADXL312] }, +- { .name = "adxl314", .driver_data = (kernel_ulong_t)&adxl31x_chip_info[ADXL312] }, ++ { .name = "adxl313", .driver_data = (kernel_ulong_t)&adxl31x_chip_info[ADXL313] }, ++ { .name = "adxl314", .driver_data = (kernel_ulong_t)&adxl31x_chip_info[ADXL314] }, + { } + }; + +diff --git a/drivers/infiniband/core/uverbs_std_types_counters.c b/drivers/infiniband/core/uverbs_std_types_counters.c +index 999da9c798668..381aa57976417 100644 +--- a/drivers/infiniband/core/uverbs_std_types_counters.c ++++ b/drivers/infiniband/core/uverbs_std_types_counters.c +@@ -107,6 +107,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_READ)( + return ret; + + uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF); ++ if (IS_ERR(uattr)) ++ return PTR_ERR(uattr); + read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64); + read_attr.counters_buff = uverbs_zalloc( + attrs, array_size(read_attr.ncounters, sizeof(u64))); +diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +index eef3ef3fabb42..bacb1b6723ef8 100644 +--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h ++++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +@@ -116,7 +116,6 @@ struct bnxt_re_dev { + struct list_head list; + unsigned long flags; + #define BNXT_RE_FLAG_NETDEV_REGISTERED 0 +-#define BNXT_RE_FLAG_GOT_MSIX 2 + #define BNXT_RE_FLAG_HAVE_L2_REF 3 + #define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4 + #define BNXT_RE_FLAG_QOS_WORK_REG 5 +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 4f00fb7869f8e..bfab2c83faf92 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -1113,8 +1113,8 @@ static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev) + bnxt_re_net_ring_free(rdev, rdev->rcfw.creq.ring_id, type); + bnxt_qplib_free_rcfw_channel(&rdev->rcfw); + } +- if (test_and_clear_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags)) +- rdev->num_msix = 0; ++ ++ rdev->num_msix = 0; + + bnxt_re_destroy_chip_ctx(rdev); + if (test_and_clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags)) +@@ -1170,7 +1170,6 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) + ibdev_dbg(&rdev->ibdev, "Got %d MSI-X vectors\n", + rdev->en_dev->ulp_tbl->msix_requested); + rdev->num_msix = rdev->en_dev->ulp_tbl->msix_requested; +- set_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags); + + bnxt_re_query_hwrm_intf_version(rdev); + +diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c +index 2a195c4b0f17d..3538d59521e41 100644 +--- a/drivers/infiniband/hw/efa/efa_verbs.c ++++ b/drivers/infiniband/hw/efa/efa_verbs.c +@@ -449,12 +449,12 @@ int efa_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) + + ibdev_dbg(&dev->ibdev, "Destroy qp[%u]\n", ibqp->qp_num); + +- efa_qp_user_mmap_entries_remove(qp); +- + err = efa_destroy_qp_handle(dev, qp->qp_handle); + if (err) + return err; + ++ efa_qp_user_mmap_entries_remove(qp); ++ + if (qp->rq_cpu_addr) { + ibdev_dbg(&dev->ibdev, + "qp->cpu_addr[0x%p] freed: size[%lu], dma[%pad]\n", +@@ -1013,8 +1013,8 @@ int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) + "Destroy cq[%d] virt[0x%p] freed: size[%lu], dma[%pad]\n", + cq->cq_idx, cq->cpu_addr, cq->size, &cq->dma_addr); + +- efa_cq_user_mmap_entries_remove(cq); + efa_destroy_cq_idx(dev, cq->cq_idx); ++ efa_cq_user_mmap_entries_remove(cq); + if (cq->eq) { + xa_erase(&dev->cqs_xa, cq->cq_idx); + synchronize_irq(cq->eq->irq.irqn); +diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h +index 84239b907de2a..bb94eb076858c 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_device.h ++++ b/drivers/infiniband/hw/hns/hns_roce_device.h +@@ -97,6 +97,7 @@ + #define HNS_ROCE_CQ_BANK_NUM 4 + + #define CQ_BANKID_SHIFT 2 ++#define CQ_BANKID_MASK GENMASK(1, 0) + + enum { + SERV_TYPE_RC, +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index d4c6b9bc0a4ea..ec1b82ddc23dd 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -757,7 +757,8 @@ out: + qp->sq.head += nreq; + qp->next_sge = sge_idx; + +- if (nreq == 1 && (qp->en_flags & HNS_ROCE_QP_CAP_DIRECT_WQE)) ++ if (nreq == 1 && !ret && ++ (qp->en_flags & HNS_ROCE_QP_CAP_DIRECT_WQE)) + write_dwqe(hr_dev, qp, wqe); + else + update_sq_db(hr_dev, qp); +@@ -6740,14 +6741,14 @@ static int __hns_roce_hw_v2_init_instance(struct hnae3_handle *handle) + ret = hns_roce_init(hr_dev); + if (ret) { + dev_err(hr_dev->dev, "RoCE Engine init failed!\n"); +- goto error_failed_cfg; ++ goto error_failed_roce_init; + } + + if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) { + ret = free_mr_init(hr_dev); + if (ret) { + dev_err(hr_dev->dev, "failed to init free mr!\n"); +- goto error_failed_roce_init; ++ goto error_failed_free_mr_init; + } + } + +@@ -6755,10 +6756,10 @@ static int __hns_roce_hw_v2_init_instance(struct hnae3_handle *handle) + + return 0; + +-error_failed_roce_init: ++error_failed_free_mr_init: + hns_roce_exit(hr_dev); + +-error_failed_cfg: ++error_failed_roce_init: + kfree(hr_dev->priv); + + error_failed_kzalloc: +diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c +index 485e110ca4333..9141eadf33d2a 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_main.c ++++ b/drivers/infiniband/hw/hns/hns_roce_main.c +@@ -219,6 +219,7 @@ static int hns_roce_query_port(struct ib_device *ib_dev, u32 port_num, + unsigned long flags; + enum ib_mtu mtu; + u32 port; ++ int ret; + + port = port_num - 1; + +@@ -231,8 +232,10 @@ static int hns_roce_query_port(struct ib_device *ib_dev, u32 port_num, + IB_PORT_BOOT_MGMT_SUP; + props->max_msg_sz = HNS_ROCE_MAX_MSG_LEN; + props->pkey_tbl_len = 1; +- props->active_width = IB_WIDTH_4X; +- props->active_speed = 1; ++ ret = ib_get_eth_speed(ib_dev, port_num, &props->active_speed, ++ &props->active_width); ++ if (ret) ++ ibdev_warn(ib_dev, "failed to get speed, ret = %d.\n", ret); + + spin_lock_irqsave(&hr_dev->iboe.lock, flags); + +diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c +index d855a917f4cfa..cdc1c6de43a17 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_qp.c ++++ b/drivers/infiniband/hw/hns/hns_roce_qp.c +@@ -170,14 +170,29 @@ static void hns_roce_ib_qp_event(struct hns_roce_qp *hr_qp, + } + } + +-static u8 get_least_load_bankid_for_qp(struct hns_roce_bank *bank) ++static u8 get_affinity_cq_bank(u8 qp_bank) + { +- u32 least_load = bank[0].inuse; ++ return (qp_bank >> 1) & CQ_BANKID_MASK; ++} ++ ++static u8 get_least_load_bankid_for_qp(struct ib_qp_init_attr *init_attr, ++ struct hns_roce_bank *bank) ++{ ++#define INVALID_LOAD_QPNUM 0xFFFFFFFF ++ struct ib_cq *scq = init_attr->send_cq; ++ u32 least_load = INVALID_LOAD_QPNUM; ++ unsigned long cqn = 0; + u8 bankid = 0; + u32 bankcnt; + u8 i; + +- for (i = 1; i < HNS_ROCE_QP_BANK_NUM; i++) { ++ if (scq) ++ cqn = to_hr_cq(scq)->cqn; ++ ++ for (i = 0; i < HNS_ROCE_QP_BANK_NUM; i++) { ++ if (scq && (get_affinity_cq_bank(i) != (cqn & CQ_BANKID_MASK))) ++ continue; ++ + bankcnt = bank[i].inuse; + if (bankcnt < least_load) { + least_load = bankcnt; +@@ -209,7 +224,8 @@ static int alloc_qpn_with_bankid(struct hns_roce_bank *bank, u8 bankid, + + return 0; + } +-static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) ++static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp, ++ struct ib_qp_init_attr *init_attr) + { + struct hns_roce_qp_table *qp_table = &hr_dev->qp_table; + unsigned long num = 0; +@@ -220,7 +236,7 @@ static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) + num = 1; + } else { + mutex_lock(&qp_table->bank_mutex); +- bankid = get_least_load_bankid_for_qp(qp_table->bank); ++ bankid = get_least_load_bankid_for_qp(init_attr, qp_table->bank); + + ret = alloc_qpn_with_bankid(&qp_table->bank[bankid], bankid, + &num); +@@ -1082,7 +1098,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, + goto err_buf; + } + +- ret = alloc_qpn(hr_dev, hr_qp); ++ ret = alloc_qpn(hr_dev, hr_qp, init_attr); + if (ret) { + ibdev_err(ibdev, "failed to alloc QPN, ret = %d.\n", ret); + goto err_qpn; +diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c +index 45e3344daa048..ef47ec271e19e 100644 +--- a/drivers/infiniband/hw/irdma/ctrl.c ++++ b/drivers/infiniband/hw/irdma/ctrl.c +@@ -1061,6 +1061,9 @@ static int irdma_sc_alloc_stag(struct irdma_sc_dev *dev, + u64 hdr; + enum irdma_page_size page_size; + ++ if (!info->total_len && !info->all_memory) ++ return -EINVAL; ++ + if (info->page_size == 0x40000000) + page_size = IRDMA_PAGE_SIZE_1G; + else if (info->page_size == 0x200000) +@@ -1126,6 +1129,9 @@ static int irdma_sc_mr_reg_non_shared(struct irdma_sc_dev *dev, + u8 addr_type; + enum irdma_page_size page_size; + ++ if (!info->total_len && !info->all_memory) ++ return -EINVAL; ++ + if (info->page_size == 0x40000000) + page_size = IRDMA_PAGE_SIZE_1G; + else if (info->page_size == 0x200000) +diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h +index 2323962cdeacb..de2f4c0514118 100644 +--- a/drivers/infiniband/hw/irdma/main.h ++++ b/drivers/infiniband/hw/irdma/main.h +@@ -239,7 +239,7 @@ struct irdma_qv_info { + + struct irdma_qvlist_info { + u32 num_vectors; +- struct irdma_qv_info qv_info[1]; ++ struct irdma_qv_info qv_info[]; + }; + + struct irdma_gen_ops { +diff --git a/drivers/infiniband/hw/irdma/type.h b/drivers/infiniband/hw/irdma/type.h +index a20709577ab0a..3b1fa5bc0a585 100644 +--- a/drivers/infiniband/hw/irdma/type.h ++++ b/drivers/infiniband/hw/irdma/type.h +@@ -971,6 +971,7 @@ struct irdma_allocate_stag_info { + bool remote_access:1; + bool use_hmc_fcn_index:1; + bool use_pf_rid:1; ++ bool all_memory:1; + u8 hmc_fcn_index; + }; + +@@ -998,6 +999,7 @@ struct irdma_reg_ns_stag_info { + bool use_hmc_fcn_index:1; + u8 hmc_fcn_index; + bool use_pf_rid:1; ++ bool all_memory:1; + }; + + struct irdma_fast_reg_stag_info { +diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c +index eaa12c1245982..20d70f0d21e0f 100644 +--- a/drivers/infiniband/hw/irdma/verbs.c ++++ b/drivers/infiniband/hw/irdma/verbs.c +@@ -2552,7 +2552,8 @@ static int irdma_hw_alloc_stag(struct irdma_device *iwdev, + struct irdma_mr *iwmr) + { + struct irdma_allocate_stag_info *info; +- struct irdma_pd *iwpd = to_iwpd(iwmr->ibmr.pd); ++ struct ib_pd *pd = iwmr->ibmr.pd; ++ struct irdma_pd *iwpd = to_iwpd(pd); + int status; + struct irdma_cqp_request *cqp_request; + struct cqp_cmds_info *cqp_info; +@@ -2568,6 +2569,7 @@ static int irdma_hw_alloc_stag(struct irdma_device *iwdev, + info->stag_idx = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S; + info->pd_id = iwpd->sc_pd.pd_id; + info->total_len = iwmr->len; ++ info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY; + info->remote_access = true; + cqp_info->cqp_cmd = IRDMA_OP_ALLOC_STAG; + cqp_info->post_sq = 1; +@@ -2615,6 +2617,8 @@ static struct ib_mr *irdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + iwmr->type = IRDMA_MEMREG_TYPE_MEM; + palloc = &iwpbl->pble_alloc; + iwmr->page_cnt = max_num_sg; ++ /* Use system PAGE_SIZE as the sg page sizes are unknown at this point */ ++ iwmr->len = max_num_sg * PAGE_SIZE; + err_code = irdma_get_pble(iwdev->rf->pble_rsrc, palloc, iwmr->page_cnt, + false); + if (err_code) +@@ -2694,7 +2698,8 @@ static int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr, + { + struct irdma_pbl *iwpbl = &iwmr->iwpbl; + struct irdma_reg_ns_stag_info *stag_info; +- struct irdma_pd *iwpd = to_iwpd(iwmr->ibmr.pd); ++ struct ib_pd *pd = iwmr->ibmr.pd; ++ struct irdma_pd *iwpd = to_iwpd(pd); + struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc; + struct irdma_cqp_request *cqp_request; + struct cqp_cmds_info *cqp_info; +@@ -2713,6 +2718,7 @@ static int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr, + stag_info->total_len = iwmr->len; + stag_info->access_rights = irdma_get_mr_access(access); + stag_info->pd_id = iwpd->sc_pd.pd_id; ++ stag_info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY; + if (stag_info->access_rights & IRDMA_ACCESS_FLAGS_ZERO_BASED) + stag_info->addr_type = IRDMA_ADDR_TYPE_ZERO_BASED; + else +@@ -4424,7 +4430,6 @@ static int irdma_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr) + ah_attr->grh.traffic_class = ah->sc_ah.ah_info.tc_tos; + ah_attr->grh.hop_limit = ah->sc_ah.ah_info.hop_ttl; + ah_attr->grh.sgid_index = ah->sgid_index; +- ah_attr->grh.sgid_index = ah->sgid_index; + memcpy(&ah_attr->grh.dgid, &ah->dgid, + sizeof(ah_attr->grh.dgid)); + } +diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c +index f46c5a5fd0aea..44fece204abdd 100644 +--- a/drivers/infiniband/sw/rxe/rxe_comp.c ++++ b/drivers/infiniband/sw/rxe/rxe_comp.c +@@ -597,6 +597,10 @@ static void flush_send_queue(struct rxe_qp *qp, bool notify) + struct rxe_queue *q = qp->sq.queue; + int err; + ++ /* send queue never got created. nothing to do. */ ++ if (!qp->sq.queue) ++ return; ++ + while ((wqe = queue_head(q, q->type))) { + if (notify) { + err = flush_send_wqe(qp, wqe); +diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h +index 804b15e929dd9..5b32724a95c8d 100644 +--- a/drivers/infiniband/sw/rxe/rxe_loc.h ++++ b/drivers/infiniband/sw/rxe/rxe_loc.h +@@ -138,12 +138,6 @@ static inline int qp_mtu(struct rxe_qp *qp) + return IB_MTU_4096; + } + +-static inline int rcv_wqe_size(int max_sge) +-{ +- return sizeof(struct rxe_recv_wqe) + +- max_sge * sizeof(struct ib_sge); +-} +- + void free_rd_atomic_resource(struct resp_res *res); + + static inline void rxe_advance_resp_resource(struct rxe_qp *qp) +diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c +index a0f206431cf8e..b66afadbd7c40 100644 +--- a/drivers/infiniband/sw/rxe/rxe_qp.c ++++ b/drivers/infiniband/sw/rxe/rxe_qp.c +@@ -183,13 +183,63 @@ static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp, + atomic_set(&qp->skb_out, 0); + } + ++static int rxe_init_sq(struct rxe_qp *qp, struct ib_qp_init_attr *init, ++ struct ib_udata *udata, ++ struct rxe_create_qp_resp __user *uresp) ++{ ++ struct rxe_dev *rxe = to_rdev(qp->ibqp.device); ++ int wqe_size; ++ int err; ++ ++ qp->sq.max_wr = init->cap.max_send_wr; ++ wqe_size = max_t(int, init->cap.max_send_sge * sizeof(struct ib_sge), ++ init->cap.max_inline_data); ++ qp->sq.max_sge = wqe_size / sizeof(struct ib_sge); ++ qp->sq.max_inline = wqe_size; ++ wqe_size += sizeof(struct rxe_send_wqe); ++ ++ qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, wqe_size, ++ QUEUE_TYPE_FROM_CLIENT); ++ if (!qp->sq.queue) { ++ rxe_err_qp(qp, "Unable to allocate send queue"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ /* prepare info for caller to mmap send queue if user space qp */ ++ err = do_mmap_info(rxe, uresp ? &uresp->sq_mi : NULL, udata, ++ qp->sq.queue->buf, qp->sq.queue->buf_size, ++ &qp->sq.queue->ip); ++ if (err) { ++ rxe_err_qp(qp, "do_mmap_info failed, err = %d", err); ++ goto err_free; ++ } ++ ++ /* return actual capabilities to caller which may be larger ++ * than requested ++ */ ++ init->cap.max_send_wr = qp->sq.max_wr; ++ init->cap.max_send_sge = qp->sq.max_sge; ++ init->cap.max_inline_data = qp->sq.max_inline; ++ ++ return 0; ++ ++err_free: ++ vfree(qp->sq.queue->buf); ++ kfree(qp->sq.queue); ++ qp->sq.queue = NULL; ++err_out: ++ return err; ++} ++ + static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, + struct ib_qp_init_attr *init, struct ib_udata *udata, + struct rxe_create_qp_resp __user *uresp) + { + int err; +- int wqe_size; +- enum queue_type type; ++ ++ /* if we don't finish qp create make sure queue is valid */ ++ skb_queue_head_init(&qp->req_pkts); + + err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk); + if (err < 0) +@@ -204,32 +254,10 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, + * (0xc000 - 0xffff). + */ + qp->src_port = RXE_ROCE_V2_SPORT + (hash_32(qp_num(qp), 14) & 0x3fff); +- qp->sq.max_wr = init->cap.max_send_wr; +- +- /* These caps are limited by rxe_qp_chk_cap() done by the caller */ +- wqe_size = max_t(int, init->cap.max_send_sge * sizeof(struct ib_sge), +- init->cap.max_inline_data); +- qp->sq.max_sge = init->cap.max_send_sge = +- wqe_size / sizeof(struct ib_sge); +- qp->sq.max_inline = init->cap.max_inline_data = wqe_size; +- wqe_size += sizeof(struct rxe_send_wqe); + +- type = QUEUE_TYPE_FROM_CLIENT; +- qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, +- wqe_size, type); +- if (!qp->sq.queue) +- return -ENOMEM; +- +- err = do_mmap_info(rxe, uresp ? &uresp->sq_mi : NULL, udata, +- qp->sq.queue->buf, qp->sq.queue->buf_size, +- &qp->sq.queue->ip); +- +- if (err) { +- vfree(qp->sq.queue->buf); +- kfree(qp->sq.queue); +- qp->sq.queue = NULL; ++ err = rxe_init_sq(qp, init, udata, uresp); ++ if (err) + return err; +- } + + qp->req.wqe_index = queue_get_producer(qp->sq.queue, + QUEUE_TYPE_FROM_CLIENT); +@@ -248,36 +276,65 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, + return 0; + } + ++static int rxe_init_rq(struct rxe_qp *qp, struct ib_qp_init_attr *init, ++ struct ib_udata *udata, ++ struct rxe_create_qp_resp __user *uresp) ++{ ++ struct rxe_dev *rxe = to_rdev(qp->ibqp.device); ++ int wqe_size; ++ int err; ++ ++ qp->rq.max_wr = init->cap.max_recv_wr; ++ qp->rq.max_sge = init->cap.max_recv_sge; ++ wqe_size = sizeof(struct rxe_recv_wqe) + ++ qp->rq.max_sge*sizeof(struct ib_sge); ++ ++ qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, wqe_size, ++ QUEUE_TYPE_FROM_CLIENT); ++ if (!qp->rq.queue) { ++ rxe_err_qp(qp, "Unable to allocate recv queue"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ /* prepare info for caller to mmap recv queue if user space qp */ ++ err = do_mmap_info(rxe, uresp ? &uresp->rq_mi : NULL, udata, ++ qp->rq.queue->buf, qp->rq.queue->buf_size, ++ &qp->rq.queue->ip); ++ if (err) { ++ rxe_err_qp(qp, "do_mmap_info failed, err = %d", err); ++ goto err_free; ++ } ++ ++ /* return actual capabilities to caller which may be larger ++ * than requested ++ */ ++ init->cap.max_recv_wr = qp->rq.max_wr; ++ ++ return 0; ++ ++err_free: ++ vfree(qp->rq.queue->buf); ++ kfree(qp->rq.queue); ++ qp->rq.queue = NULL; ++err_out: ++ return err; ++} ++ + static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, + struct ib_qp_init_attr *init, + struct ib_udata *udata, + struct rxe_create_qp_resp __user *uresp) + { + int err; +- int wqe_size; +- enum queue_type type; ++ ++ /* if we don't finish qp create make sure queue is valid */ ++ skb_queue_head_init(&qp->resp_pkts); + + if (!qp->srq) { +- qp->rq.max_wr = init->cap.max_recv_wr; +- qp->rq.max_sge = init->cap.max_recv_sge; +- +- wqe_size = rcv_wqe_size(qp->rq.max_sge); +- +- type = QUEUE_TYPE_FROM_CLIENT; +- qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, +- wqe_size, type); +- if (!qp->rq.queue) +- return -ENOMEM; +- +- err = do_mmap_info(rxe, uresp ? &uresp->rq_mi : NULL, udata, +- qp->rq.queue->buf, qp->rq.queue->buf_size, +- &qp->rq.queue->ip); +- if (err) { +- vfree(qp->rq.queue->buf); +- kfree(qp->rq.queue); +- qp->rq.queue = NULL; ++ err = rxe_init_rq(qp, init, udata, uresp); ++ if (err) + return err; +- } + } + + rxe_init_task(&qp->resp.task, qp, rxe_responder); +@@ -307,10 +364,10 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd, + if (srq) + rxe_get(srq); + +- qp->pd = pd; +- qp->rcq = rcq; +- qp->scq = scq; +- qp->srq = srq; ++ qp->pd = pd; ++ qp->rcq = rcq; ++ qp->scq = scq; ++ qp->srq = srq; + + atomic_inc(&rcq->num_wq); + atomic_inc(&scq->num_wq); +diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c +index 5fe7cbae30313..1104255b7be9a 100644 +--- a/drivers/infiniband/sw/rxe/rxe_req.c ++++ b/drivers/infiniband/sw/rxe/rxe_req.c +@@ -578,10 +578,11 @@ static void save_state(struct rxe_send_wqe *wqe, + struct rxe_send_wqe *rollback_wqe, + u32 *rollback_psn) + { +- rollback_wqe->state = wqe->state; ++ rollback_wqe->state = wqe->state; + rollback_wqe->first_psn = wqe->first_psn; +- rollback_wqe->last_psn = wqe->last_psn; +- *rollback_psn = qp->req.psn; ++ rollback_wqe->last_psn = wqe->last_psn; ++ rollback_wqe->dma = wqe->dma; ++ *rollback_psn = qp->req.psn; + } + + static void rollback_state(struct rxe_send_wqe *wqe, +@@ -589,10 +590,11 @@ static void rollback_state(struct rxe_send_wqe *wqe, + struct rxe_send_wqe *rollback_wqe, + u32 rollback_psn) + { +- wqe->state = rollback_wqe->state; ++ wqe->state = rollback_wqe->state; + wqe->first_psn = rollback_wqe->first_psn; +- wqe->last_psn = rollback_wqe->last_psn; +- qp->req.psn = rollback_psn; ++ wqe->last_psn = rollback_wqe->last_psn; ++ wqe->dma = rollback_wqe->dma; ++ qp->req.psn = rollback_psn; + } + + static void update_state(struct rxe_qp *qp, struct rxe_pkt_info *pkt) +@@ -797,6 +799,9 @@ int rxe_requester(struct rxe_qp *qp) + pkt.mask = rxe_opcode[opcode].mask; + pkt.wqe = wqe; + ++ /* save wqe state before we build and send packet */ ++ save_state(wqe, qp, &rollback_wqe, &rollback_psn); ++ + av = rxe_get_av(&pkt, &ah); + if (unlikely(!av)) { + rxe_dbg_qp(qp, "Failed no address vector\n"); +@@ -829,29 +834,29 @@ int rxe_requester(struct rxe_qp *qp) + if (ah) + rxe_put(ah); + +- /* +- * To prevent a race on wqe access between requester and completer, +- * wqe members state and psn need to be set before calling +- * rxe_xmit_packet(). +- * Otherwise, completer might initiate an unjustified retry flow. +- */ +- save_state(wqe, qp, &rollback_wqe, &rollback_psn); ++ /* update wqe state as though we had sent it */ + update_wqe_state(qp, wqe, &pkt); + update_wqe_psn(qp, wqe, &pkt, payload); + + err = rxe_xmit_packet(qp, &pkt, skb); + if (err) { +- qp->need_req_skb = 1; ++ if (err != -EAGAIN) { ++ wqe->status = IB_WC_LOC_QP_OP_ERR; ++ goto err; ++ } + ++ /* the packet was dropped so reset wqe to the state ++ * before we sent it so we can try to resend ++ */ + rollback_state(wqe, qp, &rollback_wqe, rollback_psn); + +- if (err == -EAGAIN) { +- rxe_sched_task(&qp->req.task); +- goto exit; +- } ++ /* force a delay until the dropped packet is freed and ++ * the send queue is drained below the low water mark ++ */ ++ qp->need_req_skb = 1; + +- wqe->status = IB_WC_LOC_QP_OP_ERR; +- goto err; ++ rxe_sched_task(&qp->req.task); ++ goto exit; + } + + update_state(qp, &pkt); +diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c +index ee68306555b99..ed5af55237d9f 100644 +--- a/drivers/infiniband/sw/rxe/rxe_resp.c ++++ b/drivers/infiniband/sw/rxe/rxe_resp.c +@@ -1452,6 +1452,10 @@ static void flush_recv_queue(struct rxe_qp *qp, bool notify) + if (qp->srq) + return; + ++ /* recv queue not created. nothing to do. */ ++ if (!qp->rq.queue) ++ return; ++ + while ((wqe = queue_head(q, q->type))) { + if (notify) { + err = flush_recv_wqe(qp, wqe); +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 27ca82ec0826b..3661cb627d28a 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -45,40 +45,41 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + struct ib_srq_init_attr *init, struct ib_udata *udata, + struct rxe_create_srq_resp __user *uresp) + { +- int err; +- int srq_wqe_size; + struct rxe_queue *q; +- enum queue_type type; ++ int wqe_size; ++ int err; + +- srq->ibsrq.event_handler = init->event_handler; +- srq->ibsrq.srq_context = init->srq_context; +- srq->limit = init->attr.srq_limit; +- srq->srq_num = srq->elem.index; +- srq->rq.max_wr = init->attr.max_wr; +- srq->rq.max_sge = init->attr.max_sge; ++ srq->ibsrq.event_handler = init->event_handler; ++ srq->ibsrq.srq_context = init->srq_context; ++ srq->limit = init->attr.srq_limit; ++ srq->srq_num = srq->elem.index; ++ srq->rq.max_wr = init->attr.max_wr; ++ srq->rq.max_sge = init->attr.max_sge; + +- srq_wqe_size = rcv_wqe_size(srq->rq.max_sge); ++ wqe_size = sizeof(struct rxe_recv_wqe) + ++ srq->rq.max_sge*sizeof(struct ib_sge); + + spin_lock_init(&srq->rq.producer_lock); + spin_lock_init(&srq->rq.consumer_lock); + +- type = QUEUE_TYPE_FROM_CLIENT; +- q = rxe_queue_init(rxe, &srq->rq.max_wr, srq_wqe_size, type); ++ q = rxe_queue_init(rxe, &srq->rq.max_wr, wqe_size, ++ QUEUE_TYPE_FROM_CLIENT); + if (!q) { + rxe_dbg_srq(srq, "Unable to allocate queue\n"); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto err_out; + } + +- srq->rq.queue = q; +- + err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, udata, q->buf, + q->buf_size, &q->ip); + if (err) { +- vfree(q->buf); +- kfree(q); +- return err; ++ rxe_dbg_srq(srq, "Unable to init mmap info for caller\n"); ++ goto err_free; + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + if (uresp) { + if (copy_to_user(&uresp->srq_num, &srq->srq_num, + sizeof(uresp->srq_num))) { +@@ -88,6 +89,12 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + + return 0; ++ ++err_free: ++ vfree(q->buf); ++ kfree(q); ++err_out: ++ return err; + } + + int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq, +@@ -145,9 +152,10 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, + struct ib_srq_attr *attr, enum ib_srq_attr_mask mask, + struct rxe_modify_srq_cmd *ucmd, struct ib_udata *udata) + { +- int err; + struct rxe_queue *q = srq->rq.queue; + struct mminfo __user *mi = NULL; ++ int wqe_size; ++ int err; + + if (mask & IB_SRQ_MAX_WR) { + /* +@@ -156,12 +164,16 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, + */ + mi = u64_to_user_ptr(ucmd->mmap_info_addr); + +- err = rxe_queue_resize(q, &attr->max_wr, +- rcv_wqe_size(srq->rq.max_sge), udata, mi, +- &srq->rq.producer_lock, ++ wqe_size = sizeof(struct rxe_recv_wqe) + ++ srq->rq.max_sge*sizeof(struct ib_sge); ++ ++ err = rxe_queue_resize(q, &attr->max_wr, wqe_size, ++ udata, mi, &srq->rq.producer_lock, + &srq->rq.consumer_lock); + if (err) +- goto err2; ++ goto err_free; ++ ++ srq->rq.max_wr = attr->max_wr; + } + + if (mask & IB_SRQ_LIMIT) +@@ -169,7 +181,7 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, + + return 0; + +-err2: ++err_free: + rxe_queue_cleanup(q); + srq->rq.queue = NULL; + return err; +diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h +index 2f3a9cda3850f..8b4a710b82bc1 100644 +--- a/drivers/infiniband/sw/siw/siw.h ++++ b/drivers/infiniband/sw/siw/siw.h +@@ -74,6 +74,7 @@ struct siw_device { + + u32 vendor_part_id; + int numa_node; ++ char raw_gid[ETH_ALEN]; + + /* physical port state (only one port per device) */ + enum ib_port_state state; +diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c +index da530c0404da4..a2605178f4eda 100644 +--- a/drivers/infiniband/sw/siw/siw_cm.c ++++ b/drivers/infiniband/sw/siw/siw_cm.c +@@ -1501,7 +1501,6 @@ error: + + cep->cm_id = NULL; + id->rem_ref(id); +- siw_cep_put(cep); + + qp->cep = NULL; + siw_cep_put(cep); +diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c +index 65b5cda5457ba..f45600d169ae7 100644 +--- a/drivers/infiniband/sw/siw/siw_main.c ++++ b/drivers/infiniband/sw/siw/siw_main.c +@@ -75,8 +75,7 @@ static int siw_device_register(struct siw_device *sdev, const char *name) + return rv; + } + +- siw_dbg(base_dev, "HWaddr=%pM\n", sdev->netdev->dev_addr); +- ++ siw_dbg(base_dev, "HWaddr=%pM\n", sdev->raw_gid); + return 0; + } + +@@ -313,24 +312,19 @@ static struct siw_device *siw_device_create(struct net_device *netdev) + return NULL; + + base_dev = &sdev->base_dev; +- + sdev->netdev = netdev; + +- if (netdev->type != ARPHRD_LOOPBACK && netdev->type != ARPHRD_NONE) { +- addrconf_addr_eui48((unsigned char *)&base_dev->node_guid, +- netdev->dev_addr); ++ if (netdev->addr_len) { ++ memcpy(sdev->raw_gid, netdev->dev_addr, ++ min_t(unsigned int, netdev->addr_len, ETH_ALEN)); + } else { + /* +- * This device does not have a HW address, +- * but connection mangagement lib expects gid != 0 ++ * This device does not have a HW address, but ++ * connection mangagement requires a unique gid. + */ +- size_t len = min_t(size_t, strlen(base_dev->name), 6); +- char addr[6] = { }; +- +- memcpy(addr, base_dev->name, len); +- addrconf_addr_eui48((unsigned char *)&base_dev->node_guid, +- addr); ++ eth_random_addr(sdev->raw_gid); + } ++ addrconf_addr_eui48((u8 *)&base_dev->node_guid, sdev->raw_gid); + + base_dev->uverbs_cmd_mask |= BIT_ULL(IB_USER_VERBS_CMD_POST_SEND); + +diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c +index 398ec13db6248..10cabc792c68e 100644 +--- a/drivers/infiniband/sw/siw/siw_verbs.c ++++ b/drivers/infiniband/sw/siw/siw_verbs.c +@@ -157,7 +157,7 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr, + attr->vendor_part_id = sdev->vendor_part_id; + + addrconf_addr_eui48((u8 *)&attr->sys_image_guid, +- sdev->netdev->dev_addr); ++ sdev->raw_gid); + + return 0; + } +@@ -218,7 +218,7 @@ int siw_query_gid(struct ib_device *base_dev, u32 port, int idx, + + /* subnet_prefix == interface_id == 0; */ + memset(gid, 0, sizeof(*gid)); +- memcpy(&gid->raw[0], sdev->netdev->dev_addr, 6); ++ memcpy(gid->raw, sdev->raw_gid, ETH_ALEN); + + return 0; + } +@@ -1494,7 +1494,7 @@ int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle, + + if (pbl->max_buf < num_sle) { + siw_dbg_mem(mem, "too many SGE's: %d > %d\n", +- mem->pbl->max_buf, num_sle); ++ num_sle, pbl->max_buf); + return -ENOMEM; + } + for_each_sg(sl, slp, num_sle, i) { +diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c +index 92e1e7587af8b..00a7303c8cc60 100644 +--- a/drivers/infiniband/ulp/isert/ib_isert.c ++++ b/drivers/infiniband/ulp/isert/ib_isert.c +@@ -2570,6 +2570,8 @@ static void isert_wait_conn(struct iscsit_conn *conn) + isert_put_unsol_pending_cmds(conn); + isert_wait4cmds(conn); + isert_wait4logout(isert_conn); ++ ++ queue_work(isert_release_wq, &isert_conn->release_work); + } + + static void isert_free_conn(struct iscsit_conn *conn) +diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c +index 0e513a7e5ac80..1574218764e0a 100644 +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -1979,12 +1979,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) + + if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) + scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); +- else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER)) +- scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt)); + else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER)) + scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); +- else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER)) +- scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt)); + + srp_free_req(ch, req, scmnd, + be32_to_cpu(rsp->req_lim_delta)); +diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h +index 028e45bd050bf..1724d6cb8649d 100644 +--- a/drivers/input/serio/i8042-acpipnpio.h ++++ b/drivers/input/serio/i8042-acpipnpio.h +@@ -1281,6 +1281,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, ++ /* See comment on TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU above */ ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "PD5x_7xPNP_PNR_PNN_PNT"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOAUX) ++ }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X170SM"), +diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c +index d5f2a6b5376bd..a2d437a05a11f 100644 +--- a/drivers/interconnect/qcom/bcm-voter.c ++++ b/drivers/interconnect/qcom/bcm-voter.c +@@ -58,6 +58,36 @@ static u64 bcm_div(u64 num, u32 base) + return num; + } + ++/* BCMs with enable_mask use one-hot-encoding for on/off signaling */ ++static void bcm_aggregate_mask(struct qcom_icc_bcm *bcm) ++{ ++ struct qcom_icc_node *node; ++ int bucket, i; ++ ++ for (bucket = 0; bucket < QCOM_ICC_NUM_BUCKETS; bucket++) { ++ bcm->vote_x[bucket] = 0; ++ bcm->vote_y[bucket] = 0; ++ ++ for (i = 0; i < bcm->num_nodes; i++) { ++ node = bcm->nodes[i]; ++ ++ /* If any vote in this bucket exists, keep the BCM enabled */ ++ if (node->sum_avg[bucket] || node->max_peak[bucket]) { ++ bcm->vote_x[bucket] = 0; ++ bcm->vote_y[bucket] = bcm->enable_mask; ++ break; ++ } ++ } ++ } ++ ++ if (bcm->keepalive) { ++ bcm->vote_x[QCOM_ICC_BUCKET_AMC] = bcm->enable_mask; ++ bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = bcm->enable_mask; ++ bcm->vote_y[QCOM_ICC_BUCKET_AMC] = bcm->enable_mask; ++ bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = bcm->enable_mask; ++ } ++} ++ + static void bcm_aggregate(struct qcom_icc_bcm *bcm) + { + struct qcom_icc_node *node; +@@ -83,11 +113,6 @@ static void bcm_aggregate(struct qcom_icc_bcm *bcm) + + temp = agg_peak[bucket] * bcm->vote_scale; + bcm->vote_y[bucket] = bcm_div(temp, bcm->aux_data.unit); +- +- if (bcm->enable_mask && (bcm->vote_x[bucket] || bcm->vote_y[bucket])) { +- bcm->vote_x[bucket] = 0; +- bcm->vote_y[bucket] = bcm->enable_mask; +- } + } + + if (bcm->keepalive && bcm->vote_x[QCOM_ICC_BUCKET_AMC] == 0 && +@@ -260,8 +285,12 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter) + return 0; + + mutex_lock(&voter->lock); +- list_for_each_entry(bcm, &voter->commit_list, list) +- bcm_aggregate(bcm); ++ list_for_each_entry(bcm, &voter->commit_list, list) { ++ if (bcm->enable_mask) ++ bcm_aggregate_mask(bcm); ++ else ++ bcm_aggregate(bcm); ++ } + + /* + * Pre sort the BCMs based on VCD for ease of generating a command list +diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c +index a29cdb4fac03f..82a2698ad66b1 100644 +--- a/drivers/interconnect/qcom/qcm2290.c ++++ b/drivers/interconnect/qcom/qcm2290.c +@@ -1355,6 +1355,7 @@ static struct platform_driver qcm2290_noc_driver = { + .driver = { + .name = "qnoc-qcm2290", + .of_match_table = qcm2290_noc_of_match, ++ .sync_state = icc_sync_state, + }, + }; + module_platform_driver(qcm2290_noc_driver); +diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c +index e64c214b40209..d6e582a02e628 100644 +--- a/drivers/interconnect/qcom/sm8450.c ++++ b/drivers/interconnect/qcom/sm8450.c +@@ -1886,6 +1886,7 @@ static struct platform_driver qnoc_driver = { + .driver = { + .name = "qnoc-sm8450", + .of_match_table = qnoc_of_match, ++ .sync_state = icc_sync_state, + }, + }; + +diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c +index 261352a232716..65d78d7e04408 100644 +--- a/drivers/iommu/amd/iommu_v2.c ++++ b/drivers/iommu/amd/iommu_v2.c +@@ -262,8 +262,8 @@ static void put_pasid_state(struct pasid_state *pasid_state) + + static void put_pasid_state_wait(struct pasid_state *pasid_state) + { +- refcount_dec(&pasid_state->count); +- wait_event(pasid_state->wq, !refcount_read(&pasid_state->count)); ++ if (!refcount_dec_and_test(&pasid_state->count)) ++ wait_event(pasid_state->wq, !refcount_read(&pasid_state->count)); + free_pasid_state(pasid_state); + } + +diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +index a503ed758ec30..3e551ca6afdb9 100644 +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -273,6 +273,13 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain, + ctx->secure_init = true; + } + ++ /* Disable context bank before programming */ ++ iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); ++ ++ /* Clear context bank fault address fault status registers */ ++ iommu_writel(ctx, ARM_SMMU_CB_FAR, 0); ++ iommu_writel(ctx, ARM_SMMU_CB_FSR, ARM_SMMU_FSR_FAULT); ++ + /* TTBRs */ + iommu_writeq(ctx, ARM_SMMU_CB_TTBR0, + pgtbl_cfg.arm_lpae_s1_cfg.ttbr | +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index c5d479770e12e..49fc5a038a145 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -129,7 +129,7 @@ int intel_pasid_alloc_table(struct device *dev) + info->pasid_table = pasid_table; + + if (!ecap_coherent(info->iommu->ecap)) +- clflush_cache_range(pasid_table->table, size); ++ clflush_cache_range(pasid_table->table, (1 << order) * PAGE_SIZE); + + return 0; + } +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index f1dcfa3f1a1b4..88e7154f846d3 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -3196,7 +3196,7 @@ static void __iommu_release_dma_ownership(struct iommu_group *group) + + /** + * iommu_group_release_dma_owner() - Release DMA ownership of a group +- * @dev: The device ++ * @group: The group + * + * Release the DMA ownership claimed by iommu_group_claim_dma_owner(). + */ +@@ -3210,7 +3210,7 @@ EXPORT_SYMBOL_GPL(iommu_group_release_dma_owner); + + /** + * iommu_device_release_dma_owner() - Release DMA ownership of a device +- * @group: The device. ++ * @dev: The device. + * + * Release the DMA ownership claimed by iommu_device_claim_dma_owner(). + */ +diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c +index ed2937a4e196f..2e43ebf1a2b5c 100644 +--- a/drivers/iommu/iommufd/device.c ++++ b/drivers/iommu/iommufd/device.c +@@ -298,8 +298,8 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev, + } + hwpt->auto_domain = true; + +- mutex_unlock(&ioas->mutex); + iommufd_object_finalize(idev->ictx, &hwpt->obj); ++ mutex_unlock(&ioas->mutex); + return 0; + out_unlock: + mutex_unlock(&ioas->mutex); +diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c +index e93906d6e112e..c2764891a779c 100644 +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -258,6 +258,8 @@ struct mtk_iommu_data { + struct device *smicomm_dev; + + struct mtk_iommu_bank_data *bank; ++ struct mtk_iommu_domain *share_dom; /* For 2 HWs share pgtable */ ++ + struct regmap *pericfg; + struct mutex mutex; /* Protect m4u_group/m4u_dom above */ + +@@ -620,15 +622,14 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom, + struct mtk_iommu_data *data, + unsigned int region_id) + { ++ struct mtk_iommu_domain *share_dom = data->share_dom; + const struct mtk_iommu_iova_region *region; +- struct mtk_iommu_domain *m4u_dom; +- +- /* Always use bank0 in sharing pgtable case */ +- m4u_dom = data->bank[0].m4u_dom; +- if (m4u_dom) { +- dom->iop = m4u_dom->iop; +- dom->cfg = m4u_dom->cfg; +- dom->domain.pgsize_bitmap = m4u_dom->cfg.pgsize_bitmap; ++ ++ /* Always use share domain in sharing pgtable case */ ++ if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE) && share_dom) { ++ dom->iop = share_dom->iop; ++ dom->cfg = share_dom->cfg; ++ dom->domain.pgsize_bitmap = share_dom->cfg.pgsize_bitmap; + goto update_iova_region; + } + +@@ -658,6 +659,9 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom, + /* Update our support page sizes bitmap */ + dom->domain.pgsize_bitmap = dom->cfg.pgsize_bitmap; + ++ if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE)) ++ data->share_dom = dom; ++ + update_iova_region: + /* Update the iova region for this domain */ + region = data->plat_data->iova_region + region_id; +@@ -708,7 +712,9 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, + /* Data is in the frstdata in sharing pgtable case. */ + frstdata = mtk_iommu_get_frst_data(hw_list); + ++ mutex_lock(&frstdata->mutex); + ret = mtk_iommu_domain_finalise(dom, frstdata, region_id); ++ mutex_unlock(&frstdata->mutex); + if (ret) { + mutex_unlock(&dom->mutex); + return ret; +diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c +index 4054030c32379..ae42959bc4905 100644 +--- a/drivers/iommu/rockchip-iommu.c ++++ b/drivers/iommu/rockchip-iommu.c +@@ -98,8 +98,6 @@ struct rk_iommu_ops { + phys_addr_t (*pt_address)(u32 dte); + u32 (*mk_dtentries)(dma_addr_t pt_dma); + u32 (*mk_ptentries)(phys_addr_t page, int prot); +- phys_addr_t (*dte_addr_phys)(u32 addr); +- u32 (*dma_addr_dte)(dma_addr_t dt_dma); + u64 dma_bit_mask; + }; + +@@ -278,8 +276,8 @@ static u32 rk_mk_pte(phys_addr_t page, int prot) + /* + * In v2: + * 31:12 - Page address bit 31:0 +- * 11:9 - Page address bit 34:32 +- * 8:4 - Page address bit 39:35 ++ * 11: 8 - Page address bit 35:32 ++ * 7: 4 - Page address bit 39:36 + * 3 - Security + * 2 - Writable + * 1 - Readable +@@ -506,7 +504,7 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu) + + /* + * Check if register DTE_ADDR is working by writing DTE_ADDR_DUMMY +- * and verifying that upper 5 nybbles are read back. ++ * and verifying that upper 5 (v1) or 7 (v2) nybbles are read back. + */ + for (i = 0; i < iommu->num_mmu; i++) { + dte_addr = rk_ops->pt_address(DTE_ADDR_DUMMY); +@@ -531,33 +529,6 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu) + return 0; + } + +-static inline phys_addr_t rk_dte_addr_phys(u32 addr) +-{ +- return (phys_addr_t)addr; +-} +- +-static inline u32 rk_dma_addr_dte(dma_addr_t dt_dma) +-{ +- return dt_dma; +-} +- +-#define DT_HI_MASK GENMASK_ULL(39, 32) +-#define DTE_BASE_HI_MASK GENMASK(11, 4) +-#define DT_SHIFT 28 +- +-static inline phys_addr_t rk_dte_addr_phys_v2(u32 addr) +-{ +- u64 addr64 = addr; +- return (phys_addr_t)(addr64 & RK_DTE_PT_ADDRESS_MASK) | +- ((addr64 & DTE_BASE_HI_MASK) << DT_SHIFT); +-} +- +-static inline u32 rk_dma_addr_dte_v2(dma_addr_t dt_dma) +-{ +- return (dt_dma & RK_DTE_PT_ADDRESS_MASK) | +- ((dt_dma & DT_HI_MASK) >> DT_SHIFT); +-} +- + static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova) + { + void __iomem *base = iommu->bases[index]; +@@ -577,7 +548,7 @@ static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova) + page_offset = rk_iova_page_offset(iova); + + mmu_dte_addr = rk_iommu_read(base, RK_MMU_DTE_ADDR); +- mmu_dte_addr_phys = rk_ops->dte_addr_phys(mmu_dte_addr); ++ mmu_dte_addr_phys = rk_ops->pt_address(mmu_dte_addr); + + dte_addr_phys = mmu_dte_addr_phys + (4 * dte_index); + dte_addr = phys_to_virt(dte_addr_phys); +@@ -967,7 +938,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu) + + for (i = 0; i < iommu->num_mmu; i++) { + rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, +- rk_ops->dma_addr_dte(rk_domain->dt_dma)); ++ rk_ops->mk_dtentries(rk_domain->dt_dma)); + rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE); + rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK); + } +@@ -1405,8 +1376,6 @@ static struct rk_iommu_ops iommu_data_ops_v1 = { + .pt_address = &rk_dte_pt_address, + .mk_dtentries = &rk_mk_dte, + .mk_ptentries = &rk_mk_pte, +- .dte_addr_phys = &rk_dte_addr_phys, +- .dma_addr_dte = &rk_dma_addr_dte, + .dma_bit_mask = DMA_BIT_MASK(32), + }; + +@@ -1414,8 +1383,6 @@ static struct rk_iommu_ops iommu_data_ops_v2 = { + .pt_address = &rk_dte_pt_address_v2, + .mk_dtentries = &rk_mk_dte_v2, + .mk_ptentries = &rk_mk_pte_v2, +- .dte_addr_phys = &rk_dte_addr_phys_v2, +- .dma_addr_dte = &rk_dma_addr_dte_v2, + .dma_bit_mask = DMA_BIT_MASK(40), + }; + +diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c +index 39e34fdeccda7..eb684d8807cab 100644 +--- a/drivers/iommu/sprd-iommu.c ++++ b/drivers/iommu/sprd-iommu.c +@@ -148,6 +148,7 @@ static struct iommu_domain *sprd_iommu_domain_alloc(unsigned int domain_type) + + dom->domain.geometry.aperture_start = 0; + dom->domain.geometry.aperture_end = SZ_256M - 1; ++ dom->domain.geometry.force_aperture = true; + + return &dom->domain; + } +diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c +index a7fcde3e3ecc7..ae28918df5c59 100644 +--- a/drivers/irqchip/irq-loongson-eiointc.c ++++ b/drivers/irqchip/irq-loongson-eiointc.c +@@ -143,7 +143,7 @@ static int eiointc_router_init(unsigned int cpu) + int i, bit; + uint32_t data; + uint32_t node = cpu_to_eio_node(cpu); +- uint32_t index = eiointc_index(node); ++ int index = eiointc_index(node); + + if (index < 0) { + pr_err("Error: invalid nodemap!\n"); +diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c +index e317408583df9..ec62a48116135 100644 +--- a/drivers/leds/led-class-multicolor.c ++++ b/drivers/leds/led-class-multicolor.c +@@ -6,6 +6,7 @@ + #include <linux/device.h> + #include <linux/init.h> + #include <linux/led-class-multicolor.h> ++#include <linux/math.h> + #include <linux/module.h> + #include <linux/slab.h> + #include <linux/uaccess.h> +@@ -19,9 +20,10 @@ int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) +- mcled_cdev->subled_info[i].brightness = brightness * +- mcled_cdev->subled_info[i].intensity / +- led_cdev->max_brightness; ++ mcled_cdev->subled_info[i].brightness = ++ DIV_ROUND_CLOSEST(brightness * ++ mcled_cdev->subled_info[i].intensity, ++ led_cdev->max_brightness); + + return 0; + } +diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c +index 4a97cb7457888..aad8bc44459fe 100644 +--- a/drivers/leds/led-core.c ++++ b/drivers/leds/led-core.c +@@ -419,15 +419,15 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data, + struct fwnode_handle *fwnode = init_data->fwnode; + const char *devicename = init_data->devicename; + +- /* We want to label LEDs that can produce full range of colors +- * as RGB, not multicolor */ +- BUG_ON(props.color == LED_COLOR_ID_MULTI); +- + if (!led_classdev_name) + return -EINVAL; + + led_parse_fwnode_props(dev, fwnode, &props); + ++ /* We want to label LEDs that can produce full range of colors ++ * as RGB, not multicolor */ ++ BUG_ON(props.color == LED_COLOR_ID_MULTI); ++ + if (props.label) { + /* + * If init_data.devicename is NULL, then it indicates that +diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c +index 29194cc382afb..87c199242f3c8 100644 +--- a/drivers/leds/leds-pwm.c ++++ b/drivers/leds/leds-pwm.c +@@ -146,7 +146,7 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) + led.name = to_of_node(fwnode)->name; + + if (!led.name) { +- ret = EINVAL; ++ ret = -EINVAL; + goto err_child_out; + } + +diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c +index f62db7e520b52..8ae0d2d284aff 100644 +--- a/drivers/leds/trigger/ledtrig-tty.c ++++ b/drivers/leds/trigger/ledtrig-tty.c +@@ -7,6 +7,8 @@ + #include <linux/tty.h> + #include <uapi/linux/serial.h> + ++#define LEDTRIG_TTY_INTERVAL 50 ++ + struct ledtrig_tty_data { + struct led_classdev *led_cdev; + struct delayed_work dwork; +@@ -122,17 +124,19 @@ static void ledtrig_tty_work(struct work_struct *work) + + if (icount.rx != trigger_data->rx || + icount.tx != trigger_data->tx) { +- led_set_brightness_sync(trigger_data->led_cdev, LED_ON); ++ unsigned long interval = LEDTRIG_TTY_INTERVAL; ++ ++ led_blink_set_oneshot(trigger_data->led_cdev, &interval, ++ &interval, 0); + + trigger_data->rx = icount.rx; + trigger_data->tx = icount.tx; +- } else { +- led_set_brightness_sync(trigger_data->led_cdev, LED_OFF); + } + + out: + mutex_unlock(&trigger_data->mutex); +- schedule_delayed_work(&trigger_data->dwork, msecs_to_jiffies(100)); ++ schedule_delayed_work(&trigger_data->dwork, ++ msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2)); + } + + static struct attribute *ledtrig_tty_attrs[] = { +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index ea226a37b110a..ba6b4819d37e4 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -2504,6 +2504,10 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len) + if (backlog > COUNTER_MAX) + return -EINVAL; + ++ rv = mddev_lock(mddev); ++ if (rv) ++ return rv; ++ + /* + * Without write mostly device, it doesn't make sense to set + * backlog for max_write_behind. +@@ -2517,6 +2521,7 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len) + if (!has_write_mostly) { + pr_warn_ratelimited("%s: can't set backlog, no write mostly device available\n", + mdname(mddev)); ++ mddev_unlock(mddev); + return -EINVAL; + } + +@@ -2527,13 +2532,13 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len) + mddev_destroy_serial_pool(mddev, NULL, false); + } else if (backlog && !mddev->serial_info_pool) { + /* serial_info_pool is needed since backlog is not zero */ +- struct md_rdev *rdev; +- + rdev_for_each(rdev, mddev) + mddev_create_serial_pool(mddev, rdev, false); + } + if (old_mwb != backlog) + md_bitmap_update_sb(mddev->bitmap); ++ ++ mddev_unlock(mddev); + return len; + } + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 32d7ba8069aef..a2904e10ae35e 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -477,11 +477,13 @@ EXPORT_SYMBOL_GPL(mddev_suspend); + + void mddev_resume(struct mddev *mddev) + { +- /* entred the memalloc scope from mddev_suspend() */ +- memalloc_noio_restore(mddev->noio_flag); + lockdep_assert_held(&mddev->reconfig_mutex); + if (--mddev->suspended) + return; ++ ++ /* entred the memalloc scope from mddev_suspend() */ ++ memalloc_noio_restore(mddev->noio_flag); ++ + percpu_ref_resurrect(&mddev->active_io); + wake_up(&mddev->sb_wait); + mddev->pers->quiesce(mddev, 0); +diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c +index d1ac73fcd8529..7c6a0b4437d8f 100644 +--- a/drivers/md/raid0.c ++++ b/drivers/md/raid0.c +@@ -557,54 +557,20 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) + bio_endio(bio); + } + +-static bool raid0_make_request(struct mddev *mddev, struct bio *bio) ++static void raid0_map_submit_bio(struct mddev *mddev, struct bio *bio) + { + struct r0conf *conf = mddev->private; + struct strip_zone *zone; + struct md_rdev *tmp_dev; +- sector_t bio_sector; +- sector_t sector; +- sector_t orig_sector; +- unsigned chunk_sects; +- unsigned sectors; +- +- if (unlikely(bio->bi_opf & REQ_PREFLUSH) +- && md_flush_request(mddev, bio)) +- return true; ++ sector_t bio_sector = bio->bi_iter.bi_sector; ++ sector_t sector = bio_sector; + +- if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) { +- raid0_handle_discard(mddev, bio); +- return true; +- } ++ md_account_bio(mddev, &bio); + +- bio_sector = bio->bi_iter.bi_sector; +- sector = bio_sector; +- chunk_sects = mddev->chunk_sectors; +- +- sectors = chunk_sects - +- (likely(is_power_of_2(chunk_sects)) +- ? (sector & (chunk_sects-1)) +- : sector_div(sector, chunk_sects)); +- +- /* Restore due to sector_div */ +- sector = bio_sector; +- +- if (sectors < bio_sectors(bio)) { +- struct bio *split = bio_split(bio, sectors, GFP_NOIO, +- &mddev->bio_set); +- bio_chain(split, bio); +- submit_bio_noacct(bio); +- bio = split; +- } +- +- if (bio->bi_pool != &mddev->bio_set) +- md_account_bio(mddev, &bio); +- +- orig_sector = sector; + zone = find_zone(mddev->private, §or); + switch (conf->layout) { + case RAID0_ORIG_LAYOUT: +- tmp_dev = map_sector(mddev, zone, orig_sector, §or); ++ tmp_dev = map_sector(mddev, zone, bio_sector, §or); + break; + case RAID0_ALT_MULTIZONE_LAYOUT: + tmp_dev = map_sector(mddev, zone, sector, §or); +@@ -612,13 +578,13 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) + default: + WARN(1, "md/raid0:%s: Invalid layout\n", mdname(mddev)); + bio_io_error(bio); +- return true; ++ return; + } + + if (unlikely(is_rdev_broken(tmp_dev))) { + bio_io_error(bio); + md_error(mddev, tmp_dev); +- return true; ++ return; + } + + bio_set_dev(bio, tmp_dev->bdev); +@@ -630,6 +596,40 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) + bio_sector); + mddev_check_write_zeroes(mddev, bio); + submit_bio_noacct(bio); ++} ++ ++static bool raid0_make_request(struct mddev *mddev, struct bio *bio) ++{ ++ sector_t sector; ++ unsigned chunk_sects; ++ unsigned sectors; ++ ++ if (unlikely(bio->bi_opf & REQ_PREFLUSH) ++ && md_flush_request(mddev, bio)) ++ return true; ++ ++ if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) { ++ raid0_handle_discard(mddev, bio); ++ return true; ++ } ++ ++ sector = bio->bi_iter.bi_sector; ++ chunk_sects = mddev->chunk_sectors; ++ ++ sectors = chunk_sects - ++ (likely(is_power_of_2(chunk_sects)) ++ ? (sector & (chunk_sects-1)) ++ : sector_div(sector, chunk_sects)); ++ ++ if (sectors < bio_sectors(bio)) { ++ struct bio *split = bio_split(bio, sectors, GFP_NOIO, ++ &mddev->bio_set); ++ bio_chain(split, bio); ++ raid0_map_submit_bio(mddev, bio); ++ bio = split; ++ } ++ ++ raid0_map_submit_bio(mddev, bio); + return true; + } + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index ee75b058438f3..925ab30c15d49 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -1321,6 +1321,25 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, + } + } + ++static struct md_rdev *dereference_rdev_and_rrdev(struct raid10_info *mirror, ++ struct md_rdev **prrdev) ++{ ++ struct md_rdev *rdev, *rrdev; ++ ++ rrdev = rcu_dereference(mirror->replacement); ++ /* ++ * Read replacement first to prevent reading both rdev and ++ * replacement as NULL during replacement replace rdev. ++ */ ++ smp_mb(); ++ rdev = rcu_dereference(mirror->rdev); ++ if (rdev == rrdev) ++ rrdev = NULL; ++ ++ *prrdev = rrdev; ++ return rdev; ++} ++ + static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio) + { + int i; +@@ -1331,11 +1350,9 @@ retry_wait: + blocked_rdev = NULL; + rcu_read_lock(); + for (i = 0; i < conf->copies; i++) { +- struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); +- struct md_rdev *rrdev = rcu_dereference( +- conf->mirrors[i].replacement); +- if (rdev == rrdev) +- rrdev = NULL; ++ struct md_rdev *rdev, *rrdev; ++ ++ rdev = dereference_rdev_and_rrdev(&conf->mirrors[i], &rrdev); + if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { + atomic_inc(&rdev->nr_pending); + blocked_rdev = rdev; +@@ -1464,15 +1481,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, + int d = r10_bio->devs[i].devnum; + struct md_rdev *rdev, *rrdev; + +- rrdev = rcu_dereference(conf->mirrors[d].replacement); +- /* +- * Read replacement first to prevent reading both rdev and +- * replacement as NULL during replacement replace rdev. +- */ +- smp_mb(); +- rdev = rcu_dereference(conf->mirrors[d].rdev); +- if (rdev == rrdev) +- rrdev = NULL; ++ rdev = dereference_rdev_and_rrdev(&conf->mirrors[d], &rrdev); + if (rdev && (test_bit(Faulty, &rdev->flags))) + rdev = NULL; + if (rrdev && (test_bit(Faulty, &rrdev->flags))) +@@ -1779,10 +1788,9 @@ retry_discard: + */ + rcu_read_lock(); + for (disk = 0; disk < geo->raid_disks; disk++) { +- struct md_rdev *rdev = rcu_dereference(conf->mirrors[disk].rdev); +- struct md_rdev *rrdev = rcu_dereference( +- conf->mirrors[disk].replacement); ++ struct md_rdev *rdev, *rrdev; + ++ rdev = dereference_rdev_and_rrdev(&conf->mirrors[disk], &rrdev); + r10_bio->devs[disk].bio = NULL; + r10_bio->devs[disk].repl_bio = NULL; + +diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c +index 46182b955aef8..21653e1ed9384 100644 +--- a/drivers/md/raid5-cache.c ++++ b/drivers/md/raid5-cache.c +@@ -1260,14 +1260,13 @@ static void r5l_log_flush_endio(struct bio *bio) + + if (bio->bi_status) + md_error(log->rdev->mddev, log->rdev); ++ bio_uninit(bio); + + spin_lock_irqsave(&log->io_list_lock, flags); + list_for_each_entry(io, &log->flushing_ios, log_sibling) + r5l_io_run_stripes(io); + list_splice_tail_init(&log->flushing_ios, &log->finished_ios); + spin_unlock_irqrestore(&log->io_list_lock, flags); +- +- bio_uninit(bio); + } + + /* +@@ -3164,12 +3163,15 @@ void r5l_exit_log(struct r5conf *conf) + { + struct r5l_log *log = conf->log; + +- /* Ensure disable_writeback_work wakes up and exits */ +- wake_up(&conf->mddev->sb_wait); +- flush_work(&log->disable_writeback_work); + md_unregister_thread(&log->reclaim_thread); + ++ /* ++ * 'reconfig_mutex' is held by caller, set 'confg->log' to NULL to ++ * ensure disable_writeback_work wakes up and exits. ++ */ + conf->log = NULL; ++ wake_up(&conf->mddev->sb_wait); ++ flush_work(&log->disable_writeback_work); + + mempool_exit(&log->meta_pool); + bioset_exit(&log->bs); +diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c +index 241b1621b197c..09ca83c233299 100644 +--- a/drivers/media/cec/core/cec-adap.c ++++ b/drivers/media/cec/core/cec-adap.c +@@ -385,8 +385,8 @@ static void cec_data_cancel(struct cec_data *data, u8 tx_status, u8 rx_status) + cec_queue_msg_monitor(adap, &data->msg, 1); + + if (!data->blocking && data->msg.sequence) +- /* Allow drivers to process the message first */ +- call_op(adap, received, &data->msg); ++ /* Allow drivers to react to a canceled transmit */ ++ call_void_op(adap, adap_nb_transmit_canceled, &data->msg); + + cec_data_completed(data); + } +@@ -1348,7 +1348,7 @@ static void cec_adap_unconfigure(struct cec_adapter *adap) + cec_flush(adap); + wake_up_interruptible(&adap->kthread_waitq); + cec_post_state_event(adap); +- call_void_op(adap, adap_configured, false); ++ call_void_op(adap, adap_unconfigured); + } + + /* +@@ -1539,7 +1539,7 @@ configured: + adap->kthread_config = NULL; + complete(&adap->config_completion); + mutex_unlock(&adap->lock); +- call_void_op(adap, adap_configured, true); ++ call_void_op(adap, configured); + return 0; + + unconfigure: +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 04b13cdc38d2c..ba67587bd43ec 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -809,8 +809,11 @@ static void pulse8_ping_eeprom_work_handler(struct work_struct *work) + + mutex_lock(&pulse8->lock); + cmd = MSGCODE_PING; +- pulse8_send_and_wait(pulse8, &cmd, 1, +- MSGCODE_COMMAND_ACCEPTED, 0); ++ if (pulse8_send_and_wait(pulse8, &cmd, 1, ++ MSGCODE_COMMAND_ACCEPTED, 0)) { ++ dev_warn(pulse8->dev, "failed to ping EEPROM\n"); ++ goto unlock; ++ } + + if (pulse8->vers < 2) + goto unlock; +diff --git a/drivers/media/dvb-frontends/ascot2e.c b/drivers/media/dvb-frontends/ascot2e.c +index 9b00b56230b61..cf8e5f1bd1018 100644 +--- a/drivers/media/dvb-frontends/ascot2e.c ++++ b/drivers/media/dvb-frontends/ascot2e.c +@@ -533,7 +533,7 @@ struct dvb_frontend *ascot2e_attach(struct dvb_frontend *fe, + priv->i2c_address, priv->i2c); + return fe; + } +-EXPORT_SYMBOL(ascot2e_attach); ++EXPORT_SYMBOL_GPL(ascot2e_attach); + + MODULE_DESCRIPTION("Sony ASCOT2E terr/cab tuner driver"); + MODULE_AUTHOR("info@netup.ru"); +diff --git a/drivers/media/dvb-frontends/atbm8830.c b/drivers/media/dvb-frontends/atbm8830.c +index bdd16b9c58244..778c865085bf9 100644 +--- a/drivers/media/dvb-frontends/atbm8830.c ++++ b/drivers/media/dvb-frontends/atbm8830.c +@@ -489,7 +489,7 @@ error_out: + return NULL; + + } +-EXPORT_SYMBOL(atbm8830_attach); ++EXPORT_SYMBOL_GPL(atbm8830_attach); + + MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver"); + MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); +diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c +index 78cafdf279618..230436bf6cbd9 100644 +--- a/drivers/media/dvb-frontends/au8522_dig.c ++++ b/drivers/media/dvb-frontends/au8522_dig.c +@@ -879,7 +879,7 @@ error: + au8522_release_state(state); + return NULL; + } +-EXPORT_SYMBOL(au8522_attach); ++EXPORT_SYMBOL_GPL(au8522_attach); + + static const struct dvb_frontend_ops au8522_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c +index 68b92b4419cff..b3f5c49accafd 100644 +--- a/drivers/media/dvb-frontends/bcm3510.c ++++ b/drivers/media/dvb-frontends/bcm3510.c +@@ -835,7 +835,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(bcm3510_attach); ++EXPORT_SYMBOL_GPL(bcm3510_attach); + + static const struct dvb_frontend_ops bcm3510_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c +index b39ff516271b2..1d04c0a652b26 100644 +--- a/drivers/media/dvb-frontends/cx22700.c ++++ b/drivers/media/dvb-frontends/cx22700.c +@@ -432,4 +432,4 @@ MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver"); + MODULE_AUTHOR("Holger Waechtler"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(cx22700_attach); ++EXPORT_SYMBOL_GPL(cx22700_attach); +diff --git a/drivers/media/dvb-frontends/cx22702.c b/drivers/media/dvb-frontends/cx22702.c +index cc6acbf6393d4..61ad34b7004b5 100644 +--- a/drivers/media/dvb-frontends/cx22702.c ++++ b/drivers/media/dvb-frontends/cx22702.c +@@ -604,7 +604,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(cx22702_attach); ++EXPORT_SYMBOL_GPL(cx22702_attach); + + static const struct dvb_frontend_ops cx22702_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c +index 6f99d6a27be2d..9aeea089756fe 100644 +--- a/drivers/media/dvb-frontends/cx24110.c ++++ b/drivers/media/dvb-frontends/cx24110.c +@@ -653,4 +653,4 @@ MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver"); + MODULE_AUTHOR("Peter Hettkamp"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(cx24110_attach); ++EXPORT_SYMBOL_GPL(cx24110_attach); +diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c +index dd55d314bf9af..203cb6b3f941b 100644 +--- a/drivers/media/dvb-frontends/cx24113.c ++++ b/drivers/media/dvb-frontends/cx24113.c +@@ -590,7 +590,7 @@ error: + + return NULL; + } +-EXPORT_SYMBOL(cx24113_attach); ++EXPORT_SYMBOL_GPL(cx24113_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); +diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c +index ea8264ccbb4e8..8b978a9f74a4e 100644 +--- a/drivers/media/dvb-frontends/cx24116.c ++++ b/drivers/media/dvb-frontends/cx24116.c +@@ -1133,7 +1133,7 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, + state->frontend.demodulator_priv = state; + return &state->frontend; + } +-EXPORT_SYMBOL(cx24116_attach); ++EXPORT_SYMBOL_GPL(cx24116_attach); + + /* + * Initialise or wake up device +diff --git a/drivers/media/dvb-frontends/cx24120.c b/drivers/media/dvb-frontends/cx24120.c +index d8acd582c7111..44515fdbe91d4 100644 +--- a/drivers/media/dvb-frontends/cx24120.c ++++ b/drivers/media/dvb-frontends/cx24120.c +@@ -305,7 +305,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(cx24120_attach); ++EXPORT_SYMBOL_GPL(cx24120_attach); + + static int cx24120_test_rom(struct cx24120_state *state) + { +@@ -973,7 +973,9 @@ static void cx24120_set_clock_ratios(struct dvb_frontend *fe) + cmd.arg[8] = (clock_ratios_table[idx].rate >> 8) & 0xff; + cmd.arg[9] = (clock_ratios_table[idx].rate >> 0) & 0xff; + +- cx24120_message_send(state, &cmd); ++ ret = cx24120_message_send(state, &cmd); ++ if (ret != 0) ++ return; + + /* Calculate ber window rates for stat work */ + cx24120_calculate_ber_window(state, clock_ratios_table[idx].rate); +diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c +index 3d84ee17e54c6..539889e638ccc 100644 +--- a/drivers/media/dvb-frontends/cx24123.c ++++ b/drivers/media/dvb-frontends/cx24123.c +@@ -1096,7 +1096,7 @@ error: + + return NULL; + } +-EXPORT_SYMBOL(cx24123_attach); ++EXPORT_SYMBOL_GPL(cx24123_attach); + + static const struct dvb_frontend_ops cx24123_ops = { + .delsys = { SYS_DVBS }, +diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c +index 47aa40967171d..3e7cb2756a787 100644 +--- a/drivers/media/dvb-frontends/cxd2820r_core.c ++++ b/drivers/media/dvb-frontends/cxd2820r_core.c +@@ -536,7 +536,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *config, + + return pdata.get_dvb_frontend(client); + } +-EXPORT_SYMBOL(cxd2820r_attach); ++EXPORT_SYMBOL_GPL(cxd2820r_attach); + + static struct dvb_frontend *cxd2820r_get_dvb_frontend(struct i2c_client *client) + { +diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c +index 5431f922f55e4..e9d1eef40c627 100644 +--- a/drivers/media/dvb-frontends/cxd2841er.c ++++ b/drivers/media/dvb-frontends/cxd2841er.c +@@ -3930,14 +3930,14 @@ struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, + { + return cxd2841er_attach(cfg, i2c, SYS_DVBS); + } +-EXPORT_SYMBOL(cxd2841er_attach_s); ++EXPORT_SYMBOL_GPL(cxd2841er_attach_s); + + struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, + struct i2c_adapter *i2c) + { + return cxd2841er_attach(cfg, i2c, 0); + } +-EXPORT_SYMBOL(cxd2841er_attach_t_c); ++EXPORT_SYMBOL_GPL(cxd2841er_attach_t_c); + + static const struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { + .delsys = { SYS_DVBS, SYS_DVBS2 }, +diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +index d5b1b3788e392..09d31c368741d 100644 +--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +@@ -1950,7 +1950,7 @@ struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(cxd2880_attach); ++EXPORT_SYMBOL_GPL(cxd2880_attach); + + MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver"); + MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); +diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c +index cafb41dba861c..9a8e7cdd2a247 100644 +--- a/drivers/media/dvb-frontends/dib0070.c ++++ b/drivers/media/dvb-frontends/dib0070.c +@@ -762,7 +762,7 @@ free_mem: + fe->tuner_priv = NULL; + return NULL; + } +-EXPORT_SYMBOL(dib0070_attach); ++EXPORT_SYMBOL_GPL(dib0070_attach); + + MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); + MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); +diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c +index 903da33642dff..c958bcff026ec 100644 +--- a/drivers/media/dvb-frontends/dib0090.c ++++ b/drivers/media/dvb-frontends/dib0090.c +@@ -2634,7 +2634,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte + return NULL; + } + +-EXPORT_SYMBOL(dib0090_register); ++EXPORT_SYMBOL_GPL(dib0090_register); + + struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) + { +@@ -2660,7 +2660,7 @@ free_mem: + fe->tuner_priv = NULL; + return NULL; + } +-EXPORT_SYMBOL(dib0090_fw_register); ++EXPORT_SYMBOL_GPL(dib0090_fw_register); + + MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); + MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>"); +diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c +index a6c2fc4586eb3..c598b2a633256 100644 +--- a/drivers/media/dvb-frontends/dib3000mb.c ++++ b/drivers/media/dvb-frontends/dib3000mb.c +@@ -815,4 +815,4 @@ MODULE_AUTHOR(DRIVER_AUTHOR); + MODULE_DESCRIPTION(DRIVER_DESC); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(dib3000mb_attach); ++EXPORT_SYMBOL_GPL(dib3000mb_attach); +diff --git a/drivers/media/dvb-frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c +index 2e11a246aae0d..c2fca8289abae 100644 +--- a/drivers/media/dvb-frontends/dib3000mc.c ++++ b/drivers/media/dvb-frontends/dib3000mc.c +@@ -935,7 +935,7 @@ error: + kfree(st); + return NULL; + } +-EXPORT_SYMBOL(dib3000mc_attach); ++EXPORT_SYMBOL_GPL(dib3000mc_attach); + + static const struct dvb_frontend_ops dib3000mc_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c +index 97ce97789c9e3..fdb22f32e3a11 100644 +--- a/drivers/media/dvb-frontends/dib7000m.c ++++ b/drivers/media/dvb-frontends/dib7000m.c +@@ -1434,7 +1434,7 @@ error: + kfree(st); + return NULL; + } +-EXPORT_SYMBOL(dib7000m_attach); ++EXPORT_SYMBOL_GPL(dib7000m_attach); + + static const struct dvb_frontend_ops dib7000m_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c +index a90d2f51868ff..d1e53de5206ae 100644 +--- a/drivers/media/dvb-frontends/dib7000p.c ++++ b/drivers/media/dvb-frontends/dib7000p.c +@@ -497,7 +497,7 @@ static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth + prediv = reg_1856 & 0x3f; + loopdiv = (reg_1856 >> 6) & 0x3f; + +- if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { ++ if (loopdiv && bw && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); + reg_1856 &= 0xf000; + reg_1857 = dib7000p_read_word(state, 1857); +@@ -2822,7 +2822,7 @@ void *dib7000p_attach(struct dib7000p_ops *ops) + + return ops; + } +-EXPORT_SYMBOL(dib7000p_attach); ++EXPORT_SYMBOL_GPL(dib7000p_attach); + + static const struct dvb_frontend_ops dib7000p_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c +index fe19d127abb3f..301d8eca7a6f9 100644 +--- a/drivers/media/dvb-frontends/dib8000.c ++++ b/drivers/media/dvb-frontends/dib8000.c +@@ -4527,7 +4527,7 @@ void *dib8000_attach(struct dib8000_ops *ops) + + return ops; + } +-EXPORT_SYMBOL(dib8000_attach); ++EXPORT_SYMBOL_GPL(dib8000_attach); + + MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>"); + MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); +diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c +index 914ca820c174b..6f81890b31eeb 100644 +--- a/drivers/media/dvb-frontends/dib9000.c ++++ b/drivers/media/dvb-frontends/dib9000.c +@@ -2546,7 +2546,7 @@ error: + kfree(st); + return NULL; + } +-EXPORT_SYMBOL(dib9000_attach); ++EXPORT_SYMBOL_GPL(dib9000_attach); + + static const struct dvb_frontend_ops dib9000_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c +index 68f4e8b5a0abb..a738573c8cd7a 100644 +--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c ++++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c +@@ -12372,7 +12372,7 @@ error: + + return NULL; + } +-EXPORT_SYMBOL(drx39xxj_attach); ++EXPORT_SYMBOL_GPL(drx39xxj_attach); + + static const struct dvb_frontend_ops drx39xxj_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c +index 9860cae65f1cf..6a531937f4bbb 100644 +--- a/drivers/media/dvb-frontends/drxd_hard.c ++++ b/drivers/media/dvb-frontends/drxd_hard.c +@@ -2939,7 +2939,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(drxd_attach); ++EXPORT_SYMBOL_GPL(drxd_attach); + + MODULE_DESCRIPTION("DRXD driver"); + MODULE_AUTHOR("Micronas"); +diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c +index 3301ef75d4417..1acdd204c25ce 100644 +--- a/drivers/media/dvb-frontends/drxk_hard.c ++++ b/drivers/media/dvb-frontends/drxk_hard.c +@@ -6833,7 +6833,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(drxk_attach); ++EXPORT_SYMBOL_GPL(drxk_attach); + + MODULE_DESCRIPTION("DRX-K driver"); + MODULE_AUTHOR("Ralph Metzler"); +diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c +index 20fcf31af1658..515aa7c7baf2a 100644 +--- a/drivers/media/dvb-frontends/ds3000.c ++++ b/drivers/media/dvb-frontends/ds3000.c +@@ -859,7 +859,7 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, + ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF); + return &state->frontend; + } +-EXPORT_SYMBOL(ds3000_attach); ++EXPORT_SYMBOL_GPL(ds3000_attach); + + static int ds3000_set_carrier_offset(struct dvb_frontend *fe, + s32 carrier_offset_khz) +diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c +index e35e00db7dbb3..b0199ec866705 100644 +--- a/drivers/media/dvb-frontends/dvb-pll.c ++++ b/drivers/media/dvb-frontends/dvb-pll.c +@@ -866,7 +866,7 @@ out: + + return NULL; + } +-EXPORT_SYMBOL(dvb_pll_attach); ++EXPORT_SYMBOL_GPL(dvb_pll_attach); + + + static int +diff --git a/drivers/media/dvb-frontends/ec100.c b/drivers/media/dvb-frontends/ec100.c +index 03bd80666cf83..2ad0a3c2f7567 100644 +--- a/drivers/media/dvb-frontends/ec100.c ++++ b/drivers/media/dvb-frontends/ec100.c +@@ -299,7 +299,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(ec100_attach); ++EXPORT_SYMBOL_GPL(ec100_attach); + + static const struct dvb_frontend_ops ec100_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c +index e4bbf6a51a2bc..685cf1c908bde 100644 +--- a/drivers/media/dvb-frontends/helene.c ++++ b/drivers/media/dvb-frontends/helene.c +@@ -1025,7 +1025,7 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, + priv->i2c_address, priv->i2c); + return fe; + } +-EXPORT_SYMBOL(helene_attach_s); ++EXPORT_SYMBOL_GPL(helene_attach_s); + + struct dvb_frontend *helene_attach(struct dvb_frontend *fe, + const struct helene_config *config, +@@ -1061,7 +1061,7 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe, + priv->i2c_address, priv->i2c); + return fe; + } +-EXPORT_SYMBOL(helene_attach); ++EXPORT_SYMBOL_GPL(helene_attach); + + static int helene_probe(struct i2c_client *client) + { +diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c +index 24bf5cbcc1846..0330b78a5b3f2 100644 +--- a/drivers/media/dvb-frontends/horus3a.c ++++ b/drivers/media/dvb-frontends/horus3a.c +@@ -395,7 +395,7 @@ struct dvb_frontend *horus3a_attach(struct dvb_frontend *fe, + priv->i2c_address, priv->i2c); + return fe; + } +-EXPORT_SYMBOL(horus3a_attach); ++EXPORT_SYMBOL_GPL(horus3a_attach); + + MODULE_DESCRIPTION("Sony HORUS3A satellite tuner driver"); + MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>"); +diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c +index 2cd69b4ff82cb..7d28a743f97eb 100644 +--- a/drivers/media/dvb-frontends/isl6405.c ++++ b/drivers/media/dvb-frontends/isl6405.c +@@ -141,7 +141,7 @@ struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter + + return fe; + } +-EXPORT_SYMBOL(isl6405_attach); ++EXPORT_SYMBOL_GPL(isl6405_attach); + + MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405"); + MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss"); +diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c +index 43b0dfc6f453e..2e9f6f12f849e 100644 +--- a/drivers/media/dvb-frontends/isl6421.c ++++ b/drivers/media/dvb-frontends/isl6421.c +@@ -213,7 +213,7 @@ struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter + + return fe; + } +-EXPORT_SYMBOL(isl6421_attach); ++EXPORT_SYMBOL_GPL(isl6421_attach); + + MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421"); + MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss"); +diff --git a/drivers/media/dvb-frontends/isl6423.c b/drivers/media/dvb-frontends/isl6423.c +index 8cd1bb88ce6e7..a0d0a38340574 100644 +--- a/drivers/media/dvb-frontends/isl6423.c ++++ b/drivers/media/dvb-frontends/isl6423.c +@@ -289,7 +289,7 @@ exit: + fe->sec_priv = NULL; + return NULL; + } +-EXPORT_SYMBOL(isl6423_attach); ++EXPORT_SYMBOL_GPL(isl6423_attach); + + MODULE_DESCRIPTION("ISL6423 SEC"); + MODULE_AUTHOR("Manu Abraham"); +diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c +index 1b33478653d16..f8f362f50e78d 100644 +--- a/drivers/media/dvb-frontends/itd1000.c ++++ b/drivers/media/dvb-frontends/itd1000.c +@@ -389,7 +389,7 @@ struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter + + return fe; + } +-EXPORT_SYMBOL(itd1000_attach); ++EXPORT_SYMBOL_GPL(itd1000_attach); + + MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>"); + MODULE_DESCRIPTION("Integrant ITD1000 driver"); +diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c +index 73f27105c139d..3212e333d472b 100644 +--- a/drivers/media/dvb-frontends/ix2505v.c ++++ b/drivers/media/dvb-frontends/ix2505v.c +@@ -302,7 +302,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(ix2505v_attach); ++EXPORT_SYMBOL_GPL(ix2505v_attach); + + module_param_named(debug, ix2505v_debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c +index c5106a1ea1cd0..fe5af2453d559 100644 +--- a/drivers/media/dvb-frontends/l64781.c ++++ b/drivers/media/dvb-frontends/l64781.c +@@ -593,4 +593,4 @@ MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver"); + MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(l64781_attach); ++EXPORT_SYMBOL_GPL(l64781_attach); +diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c +index f343066c297e2..fe700aa56bff3 100644 +--- a/drivers/media/dvb-frontends/lg2160.c ++++ b/drivers/media/dvb-frontends/lg2160.c +@@ -1426,7 +1426,7 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + + return &state->frontend; + } +-EXPORT_SYMBOL(lg2160_attach); ++EXPORT_SYMBOL_GPL(lg2160_attach); + + MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver"); + MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); +diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c +index 62d7439889196..60a97f1cc74e5 100644 +--- a/drivers/media/dvb-frontends/lgdt3305.c ++++ b/drivers/media/dvb-frontends/lgdt3305.c +@@ -1148,7 +1148,7 @@ fail: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(lgdt3305_attach); ++EXPORT_SYMBOL_GPL(lgdt3305_attach); + + static const struct dvb_frontend_ops lgdt3304_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c +index 6bf723b5ffad8..cfd76e0746336 100644 +--- a/drivers/media/dvb-frontends/lgdt3306a.c ++++ b/drivers/media/dvb-frontends/lgdt3306a.c +@@ -1859,7 +1859,7 @@ fail: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(lgdt3306a_attach); ++EXPORT_SYMBOL_GPL(lgdt3306a_attach); + + #ifdef DBG_DUMP + +diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c +index 1d6932d8e4978..5cd58efc38433 100644 +--- a/drivers/media/dvb-frontends/lgdt330x.c ++++ b/drivers/media/dvb-frontends/lgdt330x.c +@@ -927,7 +927,7 @@ struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config, + + return lgdt330x_get_dvb_frontend(client); + } +-EXPORT_SYMBOL(lgdt330x_attach); ++EXPORT_SYMBOL_GPL(lgdt330x_attach); + + static const struct dvb_frontend_ops lgdt3302_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/lgs8gxx.c b/drivers/media/dvb-frontends/lgs8gxx.c +index 30014979b985b..ffaf60e16ecd4 100644 +--- a/drivers/media/dvb-frontends/lgs8gxx.c ++++ b/drivers/media/dvb-frontends/lgs8gxx.c +@@ -1043,7 +1043,7 @@ error_out: + return NULL; + + } +-EXPORT_SYMBOL(lgs8gxx_attach); ++EXPORT_SYMBOL_GPL(lgs8gxx_attach); + + MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver"); + MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); +diff --git a/drivers/media/dvb-frontends/lnbh25.c b/drivers/media/dvb-frontends/lnbh25.c +index 9ffe06cd787dd..41bec050642b5 100644 +--- a/drivers/media/dvb-frontends/lnbh25.c ++++ b/drivers/media/dvb-frontends/lnbh25.c +@@ -173,7 +173,7 @@ struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe, + __func__, priv->i2c_address); + return fe; + } +-EXPORT_SYMBOL(lnbh25_attach); ++EXPORT_SYMBOL_GPL(lnbh25_attach); + + MODULE_DESCRIPTION("ST LNBH25 driver"); + MODULE_AUTHOR("info@netup.ru"); +diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c +index e564974162d65..32593b1f75a38 100644 +--- a/drivers/media/dvb-frontends/lnbp21.c ++++ b/drivers/media/dvb-frontends/lnbp21.c +@@ -155,7 +155,7 @@ struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, + return lnbx2x_attach(fe, i2c, override_set, override_clear, + i2c_addr, LNBH24_TTX); + } +-EXPORT_SYMBOL(lnbh24_attach); ++EXPORT_SYMBOL_GPL(lnbh24_attach); + + struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, +@@ -164,7 +164,7 @@ struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, + return lnbx2x_attach(fe, i2c, override_set, override_clear, + 0x08, LNBP21_ISEL); + } +-EXPORT_SYMBOL(lnbp21_attach); ++EXPORT_SYMBOL_GPL(lnbp21_attach); + + MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24"); + MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin"); +diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c +index b8c7145d4cefe..cb4ea5d3fad4a 100644 +--- a/drivers/media/dvb-frontends/lnbp22.c ++++ b/drivers/media/dvb-frontends/lnbp22.c +@@ -125,7 +125,7 @@ struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(lnbp22_attach); ++EXPORT_SYMBOL_GPL(lnbp22_attach); + + MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22"); + MODULE_AUTHOR("Dominik Kuhlen"); +diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c +index f26508b217ee6..36eab5d254b5b 100644 +--- a/drivers/media/dvb-frontends/m88ds3103.c ++++ b/drivers/media/dvb-frontends/m88ds3103.c +@@ -1695,7 +1695,7 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, + *tuner_i2c_adapter = pdata.get_i2c_adapter(client); + return pdata.get_dvb_frontend(client); + } +-EXPORT_SYMBOL(m88ds3103_attach); ++EXPORT_SYMBOL_GPL(m88ds3103_attach); + + static const struct dvb_frontend_ops m88ds3103_ops = { + .delsys = {SYS_DVBS, SYS_DVBS2}, +diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c +index b294ba87e934f..2aa98203cd659 100644 +--- a/drivers/media/dvb-frontends/m88rs2000.c ++++ b/drivers/media/dvb-frontends/m88rs2000.c +@@ -808,7 +808,7 @@ error: + + return NULL; + } +-EXPORT_SYMBOL(m88rs2000_attach); ++EXPORT_SYMBOL_GPL(m88rs2000_attach); + + MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver"); + MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c +index d3e29937cf4cf..460821a986e53 100644 +--- a/drivers/media/dvb-frontends/mb86a16.c ++++ b/drivers/media/dvb-frontends/mb86a16.c +@@ -1851,6 +1851,6 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(mb86a16_attach); ++EXPORT_SYMBOL_GPL(mb86a16_attach); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Manu Abraham"); +diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c +index b74b9afed9a2e..9f5c61d4f23c5 100644 +--- a/drivers/media/dvb-frontends/mb86a20s.c ++++ b/drivers/media/dvb-frontends/mb86a20s.c +@@ -2081,7 +2081,7 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, + dev_info(&i2c->dev, "Detected a Fujitsu mb86a20s frontend\n"); + return &state->frontend; + } +-EXPORT_SYMBOL(mb86a20s_attach); ++EXPORT_SYMBOL_GPL(mb86a20s_attach); + + static const struct dvb_frontend_ops mb86a20s_ops = { + .delsys = { SYS_ISDBT }, +diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c +index d43a67045dbe7..fb867dd8a26be 100644 +--- a/drivers/media/dvb-frontends/mt312.c ++++ b/drivers/media/dvb-frontends/mt312.c +@@ -827,7 +827,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(mt312_attach); ++EXPORT_SYMBOL_GPL(mt312_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/mt352.c b/drivers/media/dvb-frontends/mt352.c +index 399d5c519027e..1b2889f5cf67d 100644 +--- a/drivers/media/dvb-frontends/mt352.c ++++ b/drivers/media/dvb-frontends/mt352.c +@@ -593,4 +593,4 @@ MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver"); + MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(mt352_attach); ++EXPORT_SYMBOL_GPL(mt352_attach); +diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c +index 200b6dbc75f81..1c549ada6ebf9 100644 +--- a/drivers/media/dvb-frontends/nxt200x.c ++++ b/drivers/media/dvb-frontends/nxt200x.c +@@ -1216,5 +1216,5 @@ MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulat + MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(nxt200x_attach); ++EXPORT_SYMBOL_GPL(nxt200x_attach); + +diff --git a/drivers/media/dvb-frontends/nxt6000.c b/drivers/media/dvb-frontends/nxt6000.c +index 136918f82dda0..e8d4940370ddf 100644 +--- a/drivers/media/dvb-frontends/nxt6000.c ++++ b/drivers/media/dvb-frontends/nxt6000.c +@@ -621,4 +621,4 @@ MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver"); + MODULE_AUTHOR("Florian Schirmer"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(nxt6000_attach); ++EXPORT_SYMBOL_GPL(nxt6000_attach); +diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c +index 24de1b1151583..144a1f25dec0a 100644 +--- a/drivers/media/dvb-frontends/or51132.c ++++ b/drivers/media/dvb-frontends/or51132.c +@@ -605,4 +605,4 @@ MODULE_AUTHOR("Kirk Lapray"); + MODULE_AUTHOR("Trent Piepho"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(or51132_attach); ++EXPORT_SYMBOL_GPL(or51132_attach); +diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c +index ddcaea5c9941f..dc60482162c54 100644 +--- a/drivers/media/dvb-frontends/or51211.c ++++ b/drivers/media/dvb-frontends/or51211.c +@@ -551,5 +551,5 @@ MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver"); + MODULE_AUTHOR("Kirk Lapray"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(or51211_attach); ++EXPORT_SYMBOL_GPL(or51211_attach); + +diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c +index 3089cc174a6f5..28b1dca077ead 100644 +--- a/drivers/media/dvb-frontends/s5h1409.c ++++ b/drivers/media/dvb-frontends/s5h1409.c +@@ -981,7 +981,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(s5h1409_attach); ++EXPORT_SYMBOL_GPL(s5h1409_attach); + + static const struct dvb_frontend_ops s5h1409_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c +index 2563a72e98b70..fc48e659c2d8a 100644 +--- a/drivers/media/dvb-frontends/s5h1411.c ++++ b/drivers/media/dvb-frontends/s5h1411.c +@@ -900,7 +900,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(s5h1411_attach); ++EXPORT_SYMBOL_GPL(s5h1411_attach); + + static const struct dvb_frontend_ops s5h1411_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, +diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c +index 6bdec2898bc81..d700de1ea6c24 100644 +--- a/drivers/media/dvb-frontends/s5h1420.c ++++ b/drivers/media/dvb-frontends/s5h1420.c +@@ -918,7 +918,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(s5h1420_attach); ++EXPORT_SYMBOL_GPL(s5h1420_attach); + + static const struct dvb_frontend_ops s5h1420_ops = { + .delsys = { SYS_DVBS }, +diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c +index 956e8ee4b388e..ff5d3bdf3bc67 100644 +--- a/drivers/media/dvb-frontends/s5h1432.c ++++ b/drivers/media/dvb-frontends/s5h1432.c +@@ -355,7 +355,7 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, + + return &state->frontend; + } +-EXPORT_SYMBOL(s5h1432_attach); ++EXPORT_SYMBOL_GPL(s5h1432_attach); + + static const struct dvb_frontend_ops s5h1432_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c +index f118d8e641030..7e461ac159fc1 100644 +--- a/drivers/media/dvb-frontends/s921.c ++++ b/drivers/media/dvb-frontends/s921.c +@@ -495,7 +495,7 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, + + return &state->frontend; + } +-EXPORT_SYMBOL(s921_attach); ++EXPORT_SYMBOL_GPL(s921_attach); + + static const struct dvb_frontend_ops s921_ops = { + .delsys = { SYS_ISDBT }, +diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c +index 2d29d2c4d434c..210ccd356e2bf 100644 +--- a/drivers/media/dvb-frontends/si21xx.c ++++ b/drivers/media/dvb-frontends/si21xx.c +@@ -937,7 +937,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(si21xx_attach); ++EXPORT_SYMBOL_GPL(si21xx_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c +index 146e7f2dd3c5e..f59c0f96416b5 100644 +--- a/drivers/media/dvb-frontends/sp887x.c ++++ b/drivers/media/dvb-frontends/sp887x.c +@@ -624,4 +624,4 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(sp887x_attach); ++EXPORT_SYMBOL_GPL(sp887x_attach); +diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c +index 4ee6c1e1e9f7d..2f4d8fb400cd6 100644 +--- a/drivers/media/dvb-frontends/stb0899_drv.c ++++ b/drivers/media/dvb-frontends/stb0899_drv.c +@@ -1638,7 +1638,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(stb0899_attach); ++EXPORT_SYMBOL_GPL(stb0899_attach); + MODULE_PARM_DESC(verbose, "Set Verbosity level"); + MODULE_AUTHOR("Manu Abraham"); + MODULE_DESCRIPTION("STB0899 Multi-Std frontend"); +diff --git a/drivers/media/dvb-frontends/stb6000.c b/drivers/media/dvb-frontends/stb6000.c +index 8c9800d577e03..d74e34677b925 100644 +--- a/drivers/media/dvb-frontends/stb6000.c ++++ b/drivers/media/dvb-frontends/stb6000.c +@@ -232,7 +232,7 @@ struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, + + return fe; + } +-EXPORT_SYMBOL(stb6000_attach); ++EXPORT_SYMBOL_GPL(stb6000_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c +index 698866c4f15a7..c5818a15a0d70 100644 +--- a/drivers/media/dvb-frontends/stb6100.c ++++ b/drivers/media/dvb-frontends/stb6100.c +@@ -557,7 +557,7 @@ static void stb6100_release(struct dvb_frontend *fe) + kfree(state); + } + +-EXPORT_SYMBOL(stb6100_attach); ++EXPORT_SYMBOL_GPL(stb6100_attach); + MODULE_PARM_DESC(verbose, "Set Verbosity level"); + + MODULE_AUTHOR("Manu Abraham"); +diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c +index 3ae1f3a2f1420..a5581bd60f9e8 100644 +--- a/drivers/media/dvb-frontends/stv0288.c ++++ b/drivers/media/dvb-frontends/stv0288.c +@@ -590,7 +590,7 @@ error: + + return NULL; + } +-EXPORT_SYMBOL(stv0288_attach); ++EXPORT_SYMBOL_GPL(stv0288_attach); + + module_param(debug_legacy_dish_switch, int, 0444); + MODULE_PARM_DESC(debug_legacy_dish_switch, +diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c +index 6d5962d5697ac..9d4dbd99a5a79 100644 +--- a/drivers/media/dvb-frontends/stv0297.c ++++ b/drivers/media/dvb-frontends/stv0297.c +@@ -710,4 +710,4 @@ MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); + MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(stv0297_attach); ++EXPORT_SYMBOL_GPL(stv0297_attach); +diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c +index b5263a0ee5aa5..da7ff2c2e8e55 100644 +--- a/drivers/media/dvb-frontends/stv0299.c ++++ b/drivers/media/dvb-frontends/stv0299.c +@@ -752,4 +752,4 @@ MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); + MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(stv0299_attach); ++EXPORT_SYMBOL_GPL(stv0299_attach); +diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c +index 95e376f23506f..04556b77c16c9 100644 +--- a/drivers/media/dvb-frontends/stv0367.c ++++ b/drivers/media/dvb-frontends/stv0367.c +@@ -1750,7 +1750,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(stv0367ter_attach); ++EXPORT_SYMBOL_GPL(stv0367ter_attach); + + static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable) + { +@@ -2919,7 +2919,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(stv0367cab_attach); ++EXPORT_SYMBOL_GPL(stv0367cab_attach); + + /* + * Functions for operation on Digital Devices hardware +@@ -3340,7 +3340,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(stv0367ddb_attach); ++EXPORT_SYMBOL_GPL(stv0367ddb_attach); + + MODULE_PARM_DESC(debug, "Set debug"); + MODULE_PARM_DESC(i2c_debug, "Set i2c debug"); +diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c +index 212312d20ff62..e7b9b9b11d7df 100644 +--- a/drivers/media/dvb-frontends/stv0900_core.c ++++ b/drivers/media/dvb-frontends/stv0900_core.c +@@ -1957,7 +1957,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(stv0900_attach); ++EXPORT_SYMBOL_GPL(stv0900_attach); + + MODULE_PARM_DESC(debug, "Set debug"); + +diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c +index 9bde0ad6f26eb..fcf2d57fc11b9 100644 +--- a/drivers/media/dvb-frontends/stv090x.c ++++ b/drivers/media/dvb-frontends/stv090x.c +@@ -5071,7 +5071,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(stv090x_attach); ++EXPORT_SYMBOL_GPL(stv090x_attach); + + static const struct i2c_device_id stv090x_id_table[] = { + {"stv090x", 0}, +diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c +index 963f6a896102a..1cf9c095dbff0 100644 +--- a/drivers/media/dvb-frontends/stv6110.c ++++ b/drivers/media/dvb-frontends/stv6110.c +@@ -427,7 +427,7 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(stv6110_attach); ++EXPORT_SYMBOL_GPL(stv6110_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c +index b2f456116c60f..3d522965f7293 100644 +--- a/drivers/media/dvb-frontends/stv6110x.c ++++ b/drivers/media/dvb-frontends/stv6110x.c +@@ -467,7 +467,7 @@ const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + dev_info(&stv6110x->i2c->dev, "Attaching STV6110x\n"); + return stv6110x->devctl; + } +-EXPORT_SYMBOL(stv6110x_attach); ++EXPORT_SYMBOL_GPL(stv6110x_attach); + + static const struct i2c_device_id stv6110x_id_table[] = { + {"stv6110x", 0}, +diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c +index faa6e54b33729..462e12ab6bd14 100644 +--- a/drivers/media/dvb-frontends/tda10021.c ++++ b/drivers/media/dvb-frontends/tda10021.c +@@ -523,4 +523,4 @@ MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver"); + MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(tda10021_attach); ++EXPORT_SYMBOL_GPL(tda10021_attach); +diff --git a/drivers/media/dvb-frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c +index 8f32edf6b700e..4c2541ecd7433 100644 +--- a/drivers/media/dvb-frontends/tda10023.c ++++ b/drivers/media/dvb-frontends/tda10023.c +@@ -594,4 +594,4 @@ MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); + MODULE_AUTHOR("Georg Acher, Hartmut Birr"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(tda10023_attach); ++EXPORT_SYMBOL_GPL(tda10023_attach); +diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c +index 0b3f6999515e3..f6d8a64762b99 100644 +--- a/drivers/media/dvb-frontends/tda10048.c ++++ b/drivers/media/dvb-frontends/tda10048.c +@@ -1138,7 +1138,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(tda10048_attach); ++EXPORT_SYMBOL_GPL(tda10048_attach); + + static const struct dvb_frontend_ops tda10048_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c +index 83a798ca9b002..6f306db6c615f 100644 +--- a/drivers/media/dvb-frontends/tda1004x.c ++++ b/drivers/media/dvb-frontends/tda1004x.c +@@ -1378,5 +1378,5 @@ MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator"); + MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(tda10045_attach); +-EXPORT_SYMBOL(tda10046_attach); ++EXPORT_SYMBOL_GPL(tda10045_attach); ++EXPORT_SYMBOL_GPL(tda10046_attach); +diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c +index cdcf97664bba8..b449514ae5854 100644 +--- a/drivers/media/dvb-frontends/tda10086.c ++++ b/drivers/media/dvb-frontends/tda10086.c +@@ -764,4 +764,4 @@ MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator"); + MODULE_AUTHOR("Andrew de Quincey"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(tda10086_attach); ++EXPORT_SYMBOL_GPL(tda10086_attach); +diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c +index 13e8969da7f89..346be5011fb73 100644 +--- a/drivers/media/dvb-frontends/tda665x.c ++++ b/drivers/media/dvb-frontends/tda665x.c +@@ -227,7 +227,7 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(tda665x_attach); ++EXPORT_SYMBOL_GPL(tda665x_attach); + + MODULE_DESCRIPTION("TDA665x driver"); + MODULE_AUTHOR("Manu Abraham"); +diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c +index e3e1c3db2c856..44f53624557bc 100644 +--- a/drivers/media/dvb-frontends/tda8083.c ++++ b/drivers/media/dvb-frontends/tda8083.c +@@ -481,4 +481,4 @@ MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator"); + MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(tda8083_attach); ++EXPORT_SYMBOL_GPL(tda8083_attach); +diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c +index 0d576d41c67d8..8b06f92745dca 100644 +--- a/drivers/media/dvb-frontends/tda8261.c ++++ b/drivers/media/dvb-frontends/tda8261.c +@@ -188,7 +188,7 @@ exit: + return NULL; + } + +-EXPORT_SYMBOL(tda8261_attach); ++EXPORT_SYMBOL_GPL(tda8261_attach); + + MODULE_AUTHOR("Manu Abraham"); + MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); +diff --git a/drivers/media/dvb-frontends/tda826x.c b/drivers/media/dvb-frontends/tda826x.c +index f9703a1dd758c..eafcf5f7da3dc 100644 +--- a/drivers/media/dvb-frontends/tda826x.c ++++ b/drivers/media/dvb-frontends/tda826x.c +@@ -164,7 +164,7 @@ struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2 + + return fe; + } +-EXPORT_SYMBOL(tda826x_attach); ++EXPORT_SYMBOL_GPL(tda826x_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c +index c28fee7509cdd..9fa0bf6b95e4d 100644 +--- a/drivers/media/dvb-frontends/ts2020.c ++++ b/drivers/media/dvb-frontends/ts2020.c +@@ -525,7 +525,7 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(ts2020_attach); ++EXPORT_SYMBOL_GPL(ts2020_attach); + + /* + * We implement own regmap locking due to legacy DVB attach which uses frontend +diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c +index 2483f614d0e7d..41dd9b6d31908 100644 +--- a/drivers/media/dvb-frontends/tua6100.c ++++ b/drivers/media/dvb-frontends/tua6100.c +@@ -186,7 +186,7 @@ struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2 + fe->tuner_priv = priv; + return fe; + } +-EXPORT_SYMBOL(tua6100_attach); ++EXPORT_SYMBOL_GPL(tua6100_attach); + + MODULE_DESCRIPTION("DVB tua6100 driver"); + MODULE_AUTHOR("Andrew de Quincey"); +diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c +index 9df14d0be1c1a..ee5620e731e9b 100644 +--- a/drivers/media/dvb-frontends/ves1820.c ++++ b/drivers/media/dvb-frontends/ves1820.c +@@ -434,4 +434,4 @@ MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver"); + MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(ves1820_attach); ++EXPORT_SYMBOL_GPL(ves1820_attach); +diff --git a/drivers/media/dvb-frontends/ves1x93.c b/drivers/media/dvb-frontends/ves1x93.c +index b747272863025..c60e21d26b881 100644 +--- a/drivers/media/dvb-frontends/ves1x93.c ++++ b/drivers/media/dvb-frontends/ves1x93.c +@@ -540,4 +540,4 @@ MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver"); + MODULE_AUTHOR("Ralph Metzler"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(ves1x93_attach); ++EXPORT_SYMBOL_GPL(ves1x93_attach); +diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c +index d392c7cce2ce0..7ba575e9c55f4 100644 +--- a/drivers/media/dvb-frontends/zl10036.c ++++ b/drivers/media/dvb-frontends/zl10036.c +@@ -496,7 +496,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(zl10036_attach); ++EXPORT_SYMBOL_GPL(zl10036_attach); + + module_param_named(debug, zl10036_debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c +index 1335bf78d5b7f..a3e4d219400ce 100644 +--- a/drivers/media/dvb-frontends/zl10039.c ++++ b/drivers/media/dvb-frontends/zl10039.c +@@ -295,7 +295,7 @@ error: + kfree(state); + return NULL; + } +-EXPORT_SYMBOL(zl10039_attach); ++EXPORT_SYMBOL_GPL(zl10039_attach); + + module_param(debug, int, 0644); + MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +diff --git a/drivers/media/dvb-frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c +index 2a2cf20a73d61..8849d05475c27 100644 +--- a/drivers/media/dvb-frontends/zl10353.c ++++ b/drivers/media/dvb-frontends/zl10353.c +@@ -665,4 +665,4 @@ MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver"); + MODULE_AUTHOR("Chris Pascoe"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(zl10353_attach); ++EXPORT_SYMBOL_GPL(zl10353_attach); +diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig +index 76d1ee3cc1bab..dbcc2222ddd33 100644 +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -25,8 +25,15 @@ config VIDEO_IR_I2C + # V4L2 I2C drivers that are related with Camera support + # + +-menu "Camera sensor devices" +- visible if MEDIA_CAMERA_SUPPORT ++menuconfig VIDEO_CAMERA_SENSOR ++ bool "Camera sensor devices" ++ depends on MEDIA_CAMERA_SUPPORT && I2C ++ select MEDIA_CONTROLLER ++ select V4L2_FWNODE ++ select VIDEO_V4L2_SUBDEV_API ++ default y ++ ++if VIDEO_CAMERA_SENSOR + + config VIDEO_APTINA_PLL + tristate +@@ -797,7 +804,7 @@ config VIDEO_ST_VGXY61 + source "drivers/media/i2c/ccs/Kconfig" + source "drivers/media/i2c/et8ek8/Kconfig" + +-endmenu ++endif + + menu "Lens drivers" + visible if MEDIA_CAMERA_SUPPORT +diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c +index 44c26af49071c..786f38b4cbc0e 100644 +--- a/drivers/media/i2c/ad5820.c ++++ b/drivers/media/i2c/ad5820.c +@@ -349,7 +349,6 @@ static void ad5820_remove(struct i2c_client *client) + static const struct i2c_device_id ad5820_id_table[] = { + { "ad5820", 0 }, + { "ad5821", 0 }, +- { "ad5823", 0 }, + { } + }; + MODULE_DEVICE_TABLE(i2c, ad5820_id_table); +@@ -357,7 +356,6 @@ MODULE_DEVICE_TABLE(i2c, ad5820_id_table); + static const struct of_device_id ad5820_of_table[] = { + { .compatible = "adi,ad5820" }, + { .compatible = "adi,ad5821" }, +- { .compatible = "adi,ad5823" }, + { } + }; + MODULE_DEVICE_TABLE(of, ad5820_of_table); +diff --git a/drivers/media/i2c/ccs/ccs-data.c b/drivers/media/i2c/ccs/ccs-data.c +index 45f2b2f55ec5c..08400edf77ced 100644 +--- a/drivers/media/i2c/ccs/ccs-data.c ++++ b/drivers/media/i2c/ccs/ccs-data.c +@@ -464,8 +464,7 @@ static int ccs_data_parse_rules(struct bin_container *bin, + rule_payload = __rule_type + 1; + rule_plen2 = rule_plen - sizeof(*__rule_type); + +- switch (*__rule_type) { +- case CCS_DATA_BLOCK_RULE_ID_IF: { ++ if (*__rule_type == CCS_DATA_BLOCK_RULE_ID_IF) { + const struct __ccs_data_block_rule_if *__if_rules = + rule_payload; + const size_t __num_if_rules = +@@ -514,49 +513,61 @@ static int ccs_data_parse_rules(struct bin_container *bin, + rules->if_rules = if_rule; + rules->num_if_rules = __num_if_rules; + } +- break; +- } +- case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS: +- rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs, +- &rules->num_read_only_regs, +- rule_payload, +- rule_payload + rule_plen2, +- dev); +- if (rval) +- return rval; +- break; +- case CCS_DATA_BLOCK_RULE_ID_FFD: +- rval = ccs_data_parse_ffd(bin, &rules->frame_format, +- rule_payload, +- rule_payload + rule_plen2, +- dev); +- if (rval) +- return rval; +- break; +- case CCS_DATA_BLOCK_RULE_ID_MSR: +- rval = ccs_data_parse_reg_rules(bin, +- &rules->manufacturer_regs, +- &rules->num_manufacturer_regs, +- rule_payload, +- rule_payload + rule_plen2, +- dev); +- if (rval) +- return rval; +- break; +- case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT: +- rval = ccs_data_parse_pdaf_readout(bin, +- &rules->pdaf_readout, +- rule_payload, +- rule_payload + rule_plen2, +- dev); +- if (rval) +- return rval; +- break; +- default: +- dev_dbg(dev, +- "Don't know how to handle rule type %u!\n", +- *__rule_type); +- return -EINVAL; ++ } else { ++ /* Check there was an if rule before any other rules */ ++ if (bin->base && !rules) ++ return -EINVAL; ++ ++ switch (*__rule_type) { ++ case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS: ++ rval = ccs_data_parse_reg_rules(bin, ++ rules ? ++ &rules->read_only_regs : NULL, ++ rules ? ++ &rules->num_read_only_regs : NULL, ++ rule_payload, ++ rule_payload + rule_plen2, ++ dev); ++ if (rval) ++ return rval; ++ break; ++ case CCS_DATA_BLOCK_RULE_ID_FFD: ++ rval = ccs_data_parse_ffd(bin, rules ? ++ &rules->frame_format : NULL, ++ rule_payload, ++ rule_payload + rule_plen2, ++ dev); ++ if (rval) ++ return rval; ++ break; ++ case CCS_DATA_BLOCK_RULE_ID_MSR: ++ rval = ccs_data_parse_reg_rules(bin, ++ rules ? ++ &rules->manufacturer_regs : NULL, ++ rules ? ++ &rules->num_manufacturer_regs : NULL, ++ rule_payload, ++ rule_payload + rule_plen2, ++ dev); ++ if (rval) ++ return rval; ++ break; ++ case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT: ++ rval = ccs_data_parse_pdaf_readout(bin, ++ rules ? ++ &rules->pdaf_readout : NULL, ++ rule_payload, ++ rule_payload + rule_plen2, ++ dev); ++ if (rval) ++ return rval; ++ break; ++ default: ++ dev_dbg(dev, ++ "Don't know how to handle rule type %u!\n", ++ *__rule_type); ++ return -EINVAL; ++ } + } + __next_rule = __next_rule + rule_hlen + rule_plen; + } +diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c +index 5ea25b7acc55f..a84b581682a21 100644 +--- a/drivers/media/i2c/imx290.c ++++ b/drivers/media/i2c/imx290.c +@@ -902,7 +902,6 @@ static const char * const imx290_test_pattern_menu[] = { + }; + + static void imx290_ctrl_update(struct imx290 *imx290, +- const struct v4l2_mbus_framefmt *format, + const struct imx290_mode *mode) + { + unsigned int hblank_min = mode->hmax_min - mode->width; +@@ -1195,7 +1194,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + imx290->current_mode = mode; + +- imx290_ctrl_update(imx290, &fmt->format, mode); ++ imx290_ctrl_update(imx290, mode); + imx290_exposure_update(imx290, mode); + } + +@@ -1300,7 +1299,6 @@ static const struct media_entity_operations imx290_subdev_entity_ops = { + static int imx290_subdev_init(struct imx290 *imx290) + { + struct i2c_client *client = to_i2c_client(imx290->dev); +- const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + int ret; + +@@ -1335,8 +1333,7 @@ static int imx290_subdev_init(struct imx290 *imx290) + } + + state = v4l2_subdev_lock_and_get_active_state(&imx290->sd); +- format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); +- imx290_ctrl_update(imx290, format, imx290->current_mode); ++ imx290_ctrl_update(imx290, imx290->current_mode); + v4l2_subdev_unlock_state(state); + + return 0; +diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c +index 54153bf66bddc..8943e4e78a0df 100644 +--- a/drivers/media/i2c/ov2680.c ++++ b/drivers/media/i2c/ov2680.c +@@ -54,6 +54,9 @@ + #define OV2680_WIDTH_MAX 1600 + #define OV2680_HEIGHT_MAX 1200 + ++#define OV2680_DEFAULT_WIDTH 800 ++#define OV2680_DEFAULT_HEIGHT 600 ++ + enum ov2680_mode_id { + OV2680_MODE_QUXGA_800_600, + OV2680_MODE_720P_1280_720, +@@ -85,15 +88,8 @@ struct ov2680_mode_info { + + struct ov2680_ctrls { + struct v4l2_ctrl_handler handler; +- struct { +- struct v4l2_ctrl *auto_exp; +- struct v4l2_ctrl *exposure; +- }; +- struct { +- struct v4l2_ctrl *auto_gain; +- struct v4l2_ctrl *gain; +- }; +- ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *gain; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *test_pattern; +@@ -143,6 +139,7 @@ static const struct reg_value ov2680_setting_30fps_QUXGA_800_600[] = { + {0x380e, 0x02}, {0x380f, 0x84}, {0x3811, 0x04}, {0x3813, 0x04}, + {0x3814, 0x31}, {0x3815, 0x31}, {0x3820, 0xc0}, {0x4008, 0x00}, + {0x4009, 0x03}, {0x4837, 0x1e}, {0x3501, 0x4e}, {0x3502, 0xe0}, ++ {0x3503, 0x03}, + }; + + static const struct reg_value ov2680_setting_30fps_720P_1280_720[] = { +@@ -321,70 +318,62 @@ static void ov2680_power_down(struct ov2680_dev *sensor) + usleep_range(5000, 10000); + } + +-static int ov2680_bayer_order(struct ov2680_dev *sensor) ++static void ov2680_set_bayer_order(struct ov2680_dev *sensor, ++ struct v4l2_mbus_framefmt *fmt) + { +- u32 format1; +- u32 format2; +- u32 hv_flip; +- int ret; +- +- ret = ov2680_read_reg(sensor, OV2680_REG_FORMAT1, &format1); +- if (ret < 0) +- return ret; +- +- ret = ov2680_read_reg(sensor, OV2680_REG_FORMAT2, &format2); +- if (ret < 0) +- return ret; ++ int hv_flip = 0; + +- hv_flip = (format2 & BIT(2) << 1) | (format1 & BIT(2)); ++ if (sensor->ctrls.vflip && sensor->ctrls.vflip->val) ++ hv_flip += 1; + +- sensor->fmt.code = ov2680_hv_flip_bayer_order[hv_flip]; ++ if (sensor->ctrls.hflip && sensor->ctrls.hflip->val) ++ hv_flip += 2; + +- return 0; ++ fmt->code = ov2680_hv_flip_bayer_order[hv_flip]; + } + +-static int ov2680_vflip_enable(struct ov2680_dev *sensor) ++static void ov2680_fill_format(struct ov2680_dev *sensor, ++ struct v4l2_mbus_framefmt *fmt, ++ unsigned int width, unsigned int height) + { +- int ret; +- +- ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT1, BIT(2), BIT(2)); +- if (ret < 0) +- return ret; +- +- return ov2680_bayer_order(sensor); ++ memset(fmt, 0, sizeof(*fmt)); ++ fmt->width = width; ++ fmt->height = height; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_SRGB; ++ ov2680_set_bayer_order(sensor, fmt); + } + +-static int ov2680_vflip_disable(struct ov2680_dev *sensor) ++static int ov2680_set_vflip(struct ov2680_dev *sensor, s32 val) + { + int ret; + +- ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT1, BIT(2), BIT(0)); +- if (ret < 0) +- return ret; +- +- return ov2680_bayer_order(sensor); +-} +- +-static int ov2680_hflip_enable(struct ov2680_dev *sensor) +-{ +- int ret; ++ if (sensor->is_streaming) ++ return -EBUSY; + +- ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT2, BIT(2), BIT(2)); ++ ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT1, ++ BIT(2), val ? BIT(2) : 0); + if (ret < 0) + return ret; + +- return ov2680_bayer_order(sensor); ++ ov2680_set_bayer_order(sensor, &sensor->fmt); ++ return 0; + } + +-static int ov2680_hflip_disable(struct ov2680_dev *sensor) ++static int ov2680_set_hflip(struct ov2680_dev *sensor, s32 val) + { + int ret; + +- ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT2, BIT(2), BIT(0)); ++ if (sensor->is_streaming) ++ return -EBUSY; ++ ++ ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT2, ++ BIT(2), val ? BIT(2) : 0); + if (ret < 0) + return ret; + +- return ov2680_bayer_order(sensor); ++ ov2680_set_bayer_order(sensor, &sensor->fmt); ++ return 0; + } + + static int ov2680_test_pattern_set(struct ov2680_dev *sensor, int value) +@@ -405,69 +394,15 @@ static int ov2680_test_pattern_set(struct ov2680_dev *sensor, int value) + return 0; + } + +-static int ov2680_gain_set(struct ov2680_dev *sensor, bool auto_gain) ++static int ov2680_gain_set(struct ov2680_dev *sensor, u32 gain) + { +- struct ov2680_ctrls *ctrls = &sensor->ctrls; +- u32 gain; +- int ret; +- +- ret = ov2680_mod_reg(sensor, OV2680_REG_R_MANUAL, BIT(1), +- auto_gain ? 0 : BIT(1)); +- if (ret < 0) +- return ret; +- +- if (auto_gain || !ctrls->gain->is_new) +- return 0; +- +- gain = ctrls->gain->val; +- +- ret = ov2680_write_reg16(sensor, OV2680_REG_GAIN_PK, gain); +- +- return 0; +-} +- +-static int ov2680_gain_get(struct ov2680_dev *sensor) +-{ +- u32 gain; +- int ret; +- +- ret = ov2680_read_reg16(sensor, OV2680_REG_GAIN_PK, &gain); +- if (ret) +- return ret; +- +- return gain; +-} +- +-static int ov2680_exposure_set(struct ov2680_dev *sensor, bool auto_exp) +-{ +- struct ov2680_ctrls *ctrls = &sensor->ctrls; +- u32 exp; +- int ret; +- +- ret = ov2680_mod_reg(sensor, OV2680_REG_R_MANUAL, BIT(0), +- auto_exp ? 0 : BIT(0)); +- if (ret < 0) +- return ret; +- +- if (auto_exp || !ctrls->exposure->is_new) +- return 0; +- +- exp = (u32)ctrls->exposure->val; +- exp <<= 4; +- +- return ov2680_write_reg24(sensor, OV2680_REG_EXPOSURE_PK_HIGH, exp); ++ return ov2680_write_reg16(sensor, OV2680_REG_GAIN_PK, gain); + } + +-static int ov2680_exposure_get(struct ov2680_dev *sensor) ++static int ov2680_exposure_set(struct ov2680_dev *sensor, u32 exp) + { +- int ret; +- u32 exp; +- +- ret = ov2680_read_reg24(sensor, OV2680_REG_EXPOSURE_PK_HIGH, &exp); +- if (ret) +- return ret; +- +- return exp >> 4; ++ return ov2680_write_reg24(sensor, OV2680_REG_EXPOSURE_PK_HIGH, ++ exp << 4); + } + + static int ov2680_stream_enable(struct ov2680_dev *sensor) +@@ -482,33 +417,17 @@ static int ov2680_stream_disable(struct ov2680_dev *sensor) + + static int ov2680_mode_set(struct ov2680_dev *sensor) + { +- struct ov2680_ctrls *ctrls = &sensor->ctrls; + int ret; + +- ret = ov2680_gain_set(sensor, false); +- if (ret < 0) +- return ret; +- +- ret = ov2680_exposure_set(sensor, false); ++ ret = ov2680_load_regs(sensor, sensor->current_mode); + if (ret < 0) + return ret; + +- ret = ov2680_load_regs(sensor, sensor->current_mode); ++ /* Restore value of all ctrls */ ++ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret < 0) + return ret; + +- if (ctrls->auto_gain->val) { +- ret = ov2680_gain_set(sensor, true); +- if (ret < 0) +- return ret; +- } +- +- if (ctrls->auto_exp->val == V4L2_EXPOSURE_AUTO) { +- ret = ov2680_exposure_set(sensor, true); +- if (ret < 0) +- return ret; +- } +- + sensor->mode_pending_changes = false; + + return 0; +@@ -556,7 +475,7 @@ static int ov2680_power_on(struct ov2680_dev *sensor) + ret = ov2680_write_reg(sensor, OV2680_REG_SOFT_RESET, 0x01); + if (ret != 0) { + dev_err(dev, "sensor soft reset failed\n"); +- return ret; ++ goto err_disable_regulators; + } + usleep_range(1000, 2000); + } else { +@@ -566,7 +485,7 @@ static int ov2680_power_on(struct ov2680_dev *sensor) + + ret = clk_prepare_enable(sensor->xvclk); + if (ret < 0) +- return ret; ++ goto err_disable_regulators; + + sensor->is_enabled = true; + +@@ -576,6 +495,10 @@ static int ov2680_power_on(struct ov2680_dev *sensor) + ov2680_stream_disable(sensor); + + return 0; ++ ++err_disable_regulators: ++ regulator_bulk_disable(OV2680_NUM_SUPPLIES, sensor->supplies); ++ return ret; + } + + static int ov2680_s_power(struct v4l2_subdev *sd, int on) +@@ -590,15 +513,10 @@ static int ov2680_s_power(struct v4l2_subdev *sd, int on) + else + ret = ov2680_power_off(sensor); + +- mutex_unlock(&sensor->lock); +- +- if (on && ret == 0) { +- ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); +- if (ret < 0) +- return ret; +- ++ if (on && ret == 0) + ret = ov2680_mode_restore(sensor); +- } ++ ++ mutex_unlock(&sensor->lock); + + return ret; + } +@@ -664,7 +582,6 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, + { + struct ov2680_dev *sensor = to_ov2680_dev(sd); + struct v4l2_mbus_framefmt *fmt = NULL; +- int ret = 0; + + if (format->pad != 0) + return -EINVAL; +@@ -672,22 +589,17 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, + mutex_lock(&sensor->lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, + format->pad); +-#else +- ret = -EINVAL; +-#endif + } else { + fmt = &sensor->fmt; + } + +- if (fmt) +- format->format = *fmt; ++ format->format = *fmt; + + mutex_unlock(&sensor->lock); + +- return ret; ++ return 0; + } + + static int ov2680_set_fmt(struct v4l2_subdev *sd, +@@ -695,43 +607,35 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_format *format) + { + struct ov2680_dev *sensor = to_ov2680_dev(sd); +- struct v4l2_mbus_framefmt *fmt = &format->format; +-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *try_fmt; +-#endif + const struct ov2680_mode_info *mode; + int ret = 0; + + if (format->pad != 0) + return -EINVAL; + +- mutex_lock(&sensor->lock); +- +- if (sensor->is_streaming) { +- ret = -EBUSY; +- goto unlock; +- } +- + mode = v4l2_find_nearest_size(ov2680_mode_data, +- ARRAY_SIZE(ov2680_mode_data), width, +- height, fmt->width, fmt->height); +- if (!mode) { +- ret = -EINVAL; +- goto unlock; +- } ++ ARRAY_SIZE(ov2680_mode_data), ++ width, height, ++ format->format.width, ++ format->format.height); ++ if (!mode) ++ return -EINVAL; ++ ++ ov2680_fill_format(sensor, &format->format, mode->width, mode->height); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); +- format->format = *try_fmt; +-#endif +- goto unlock; ++ *try_fmt = format->format; ++ return 0; + } + +- fmt->width = mode->width; +- fmt->height = mode->height; +- fmt->code = sensor->fmt.code; +- fmt->colorspace = sensor->fmt.colorspace; ++ mutex_lock(&sensor->lock); ++ ++ if (sensor->is_streaming) { ++ ret = -EBUSY; ++ goto unlock; ++ } + + sensor->current_mode = mode; + sensor->fmt = format->format; +@@ -746,16 +650,11 @@ unlock: + static int ov2680_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) + { +- struct v4l2_subdev_format fmt = { +- .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY +- : V4L2_SUBDEV_FORMAT_ACTIVE, +- .format = { +- .width = 800, +- .height = 600, +- } +- }; ++ struct ov2680_dev *sensor = to_ov2680_dev(sd); + +- return ov2680_set_fmt(sd, sd_state, &fmt); ++ ov2680_fill_format(sensor, &sd_state->pads[0].try_fmt, ++ OV2680_DEFAULT_WIDTH, OV2680_DEFAULT_HEIGHT); ++ return 0; + } + + static int ov2680_enum_frame_size(struct v4l2_subdev *sd, +@@ -794,66 +693,23 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd, + return 0; + } + +-static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +-{ +- struct v4l2_subdev *sd = ctrl_to_sd(ctrl); +- struct ov2680_dev *sensor = to_ov2680_dev(sd); +- struct ov2680_ctrls *ctrls = &sensor->ctrls; +- int val; +- +- if (!sensor->is_enabled) +- return 0; +- +- switch (ctrl->id) { +- case V4L2_CID_GAIN: +- val = ov2680_gain_get(sensor); +- if (val < 0) +- return val; +- ctrls->gain->val = val; +- break; +- case V4L2_CID_EXPOSURE: +- val = ov2680_exposure_get(sensor); +- if (val < 0) +- return val; +- ctrls->exposure->val = val; +- break; +- } +- +- return 0; +-} +- + static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) + { + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct ov2680_dev *sensor = to_ov2680_dev(sd); +- struct ov2680_ctrls *ctrls = &sensor->ctrls; + + if (!sensor->is_enabled) + return 0; + + switch (ctrl->id) { +- case V4L2_CID_AUTOGAIN: +- return ov2680_gain_set(sensor, !!ctrl->val); + case V4L2_CID_GAIN: +- return ov2680_gain_set(sensor, !!ctrls->auto_gain->val); +- case V4L2_CID_EXPOSURE_AUTO: +- return ov2680_exposure_set(sensor, !!ctrl->val); ++ return ov2680_gain_set(sensor, ctrl->val); + case V4L2_CID_EXPOSURE: +- return ov2680_exposure_set(sensor, !!ctrls->auto_exp->val); ++ return ov2680_exposure_set(sensor, ctrl->val); + case V4L2_CID_VFLIP: +- if (sensor->is_streaming) +- return -EBUSY; +- if (ctrl->val) +- return ov2680_vflip_enable(sensor); +- else +- return ov2680_vflip_disable(sensor); ++ return ov2680_set_vflip(sensor, ctrl->val); + case V4L2_CID_HFLIP: +- if (sensor->is_streaming) +- return -EBUSY; +- if (ctrl->val) +- return ov2680_hflip_enable(sensor); +- else +- return ov2680_hflip_disable(sensor); ++ return ov2680_set_hflip(sensor, ctrl->val); + case V4L2_CID_TEST_PATTERN: + return ov2680_test_pattern_set(sensor, ctrl->val); + default: +@@ -864,7 +720,6 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) + } + + static const struct v4l2_ctrl_ops ov2680_ctrl_ops = { +- .g_volatile_ctrl = ov2680_g_volatile_ctrl, + .s_ctrl = ov2680_s_ctrl, + }; + +@@ -898,11 +753,8 @@ static int ov2680_mode_init(struct ov2680_dev *sensor) + const struct ov2680_mode_info *init_mode; + + /* set initial mode */ +- sensor->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; +- sensor->fmt.width = 800; +- sensor->fmt.height = 600; +- sensor->fmt.field = V4L2_FIELD_NONE; +- sensor->fmt.colorspace = V4L2_COLORSPACE_SRGB; ++ ov2680_fill_format(sensor, &sensor->fmt, ++ OV2680_DEFAULT_WIDTH, OV2680_DEFAULT_HEIGHT); + + sensor->frame_interval.denominator = OV2680_FRAME_RATE; + sensor->frame_interval.numerator = 1; +@@ -926,9 +778,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) + v4l2_i2c_subdev_init(&sensor->sd, sensor->i2c_client, + &ov2680_subdev_ops); + +-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; +-#endif + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + +@@ -936,7 +786,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) + if (ret < 0) + return ret; + +- v4l2_ctrl_handler_init(hdl, 7); ++ v4l2_ctrl_handler_init(hdl, 5); + + hdl->lock = &sensor->lock; + +@@ -948,16 +798,9 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) + ARRAY_SIZE(test_pattern_menu) - 1, + 0, 0, test_pattern_menu); + +- ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, +- V4L2_CID_EXPOSURE_AUTO, +- V4L2_EXPOSURE_MANUAL, 0, +- V4L2_EXPOSURE_AUTO); +- + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + 0, 32767, 1, 0); + +- ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, +- 0, 1, 1, 1); + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 2047, 1, 0); + + if (hdl->error) { +@@ -965,14 +808,9 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) + goto cleanup_entity; + } + +- ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; +- ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + +- v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); +- v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); +- + sensor->sd.ctrl_handler = hdl; + + ret = v4l2_async_register_subdev(&sensor->sd); +diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c +index 1536649b9e90f..bf50705ad6d36 100644 +--- a/drivers/media/i2c/ov5640.c ++++ b/drivers/media/i2c/ov5640.c +@@ -568,9 +568,7 @@ static const struct reg_value ov5640_init_setting[] = { + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, +- {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, +- {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x4837, 0x0a, 0, 0}, + {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, + {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, + {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, +@@ -634,7 +632,8 @@ static const struct reg_value ov5640_setting_low_res[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_720P_1280_720[] = { +@@ -2453,16 +2452,13 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable) + static void ov5640_powerup_sequence(struct ov5640_dev *sensor) + { + if (sensor->pwdn_gpio) { +- gpiod_set_value_cansleep(sensor->reset_gpio, 0); ++ gpiod_set_value_cansleep(sensor->reset_gpio, 1); + + /* camera power cycle */ + ov5640_power(sensor, false); +- usleep_range(5000, 10000); ++ usleep_range(5000, 10000); /* t2 */ + ov5640_power(sensor, true); +- usleep_range(5000, 10000); +- +- gpiod_set_value_cansleep(sensor->reset_gpio, 1); +- usleep_range(1000, 2000); ++ usleep_range(1000, 2000); /* t3 */ + + gpiod_set_value_cansleep(sensor->reset_gpio, 0); + } else { +@@ -2470,7 +2466,7 @@ static void ov5640_powerup_sequence(struct ov5640_dev *sensor) + ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, + OV5640_REG_SYS_CTRL0_SW_RST); + } +- usleep_range(20000, 25000); ++ usleep_range(20000, 25000); /* t4 */ + + /* + * software standby: allows registers programming; +@@ -2543,9 +2539,9 @@ static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) + * "ov5640_set_stream_mipi()") + * [4] = 0 : Power up MIPI HS Tx + * [3] = 0 : Power up MIPI LS Rx +- * [2] = 0 : MIPI interface disabled ++ * [2] = 1 : MIPI interface enabled + */ +- ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40); ++ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x44); + if (ret) + return ret; + +diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c +index 9ccc56c30d3b0..d269c541ebe4c 100644 +--- a/drivers/media/i2c/rdacm21.c ++++ b/drivers/media/i2c/rdacm21.c +@@ -351,7 +351,7 @@ static void ov10640_power_up(struct rdacm21_device *dev) + static int ov10640_check_id(struct rdacm21_device *dev) + { + unsigned int i; +- u8 val; ++ u8 val = 0; + + /* Read OV10640 ID to test communications. */ + for (i = 0; i < OV10640_PID_TIMEOUT; ++i) { +diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c +index 859f1cb2fa744..84f87c016f9b5 100644 +--- a/drivers/media/i2c/tvp5150.c ++++ b/drivers/media/i2c/tvp5150.c +@@ -2068,6 +2068,10 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) + tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", + v4l2c->name, v4l2c->label ? + v4l2c->label : ""); ++ if (!tvpc->ent.name) { ++ ret = -ENOMEM; ++ goto err_free; ++ } + } + + ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0); +diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig +index 480194543d055..ee095bde0b686 100644 +--- a/drivers/media/pci/Kconfig ++++ b/drivers/media/pci/Kconfig +@@ -73,7 +73,7 @@ config VIDEO_PCI_SKELETON + Enable build of the skeleton PCI driver, used as a reference + when developing new drivers. + +-source "drivers/media/pci/intel/ipu3/Kconfig" ++source "drivers/media/pci/intel/Kconfig" + + endif #MEDIA_PCI_SUPPORT + endif #PCI +diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c +index 3e52a51982d76..110651e478314 100644 +--- a/drivers/media/pci/bt8xx/dst.c ++++ b/drivers/media/pci/bt8xx/dst.c +@@ -1722,7 +1722,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad + return state; /* Manu (DST is a card not a frontend) */ + } + +-EXPORT_SYMBOL(dst_attach); ++EXPORT_SYMBOL_GPL(dst_attach); + + static const struct dvb_frontend_ops dst_dvbt_ops = { + .delsys = { SYS_DVBT }, +diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c +index 85fcdc59f0d18..571392d80ccc6 100644 +--- a/drivers/media/pci/bt8xx/dst_ca.c ++++ b/drivers/media/pci/bt8xx/dst_ca.c +@@ -668,7 +668,7 @@ struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_ + return NULL; + } + +-EXPORT_SYMBOL(dst_ca_attach); ++EXPORT_SYMBOL_GPL(dst_ca_attach); + + MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); + MODULE_AUTHOR("Manu Abraham"); +diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c +index 8fd5b6ef24282..7551ca4a322a4 100644 +--- a/drivers/media/pci/cx23885/cx23885-dvb.c ++++ b/drivers/media/pci/cx23885/cx23885-dvb.c +@@ -2459,16 +2459,10 @@ static int dvb_register(struct cx23885_tsport *port) + request_module("%s", info.type); + client_tuner = i2c_new_client_device(&dev->i2c_bus[1].i2c_adap, &info); + if (!i2c_client_has_driver(client_tuner)) { +- module_put(client_demod->dev.driver->owner); +- i2c_unregister_device(client_demod); +- port->i2c_client_demod = NULL; + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); +- module_put(client_demod->dev.driver->owner); +- i2c_unregister_device(client_demod); +- port->i2c_client_demod = NULL; + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; +@@ -2505,16 +2499,10 @@ static int dvb_register(struct cx23885_tsport *port) + request_module("%s", info.type); + client_tuner = i2c_new_client_device(&dev->i2c_bus[1].i2c_adap, &info); + if (!i2c_client_has_driver(client_tuner)) { +- module_put(client_demod->dev.driver->owner); +- i2c_unregister_device(client_demod); +- port->i2c_client_demod = NULL; + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); +- module_put(client_demod->dev.driver->owner); +- i2c_unregister_device(client_demod); +- port->i2c_client_demod = NULL; + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; +diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c +index 6868a0c4fc82a..520ebd16b0c44 100644 +--- a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c ++++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c +@@ -112,7 +112,7 @@ struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void) + state->frontend.demodulator_priv = state; + return &state->frontend; + } +-EXPORT_SYMBOL(ddbridge_dummy_fe_qam_attach); ++EXPORT_SYMBOL_GPL(ddbridge_dummy_fe_qam_attach); + + static const struct dvb_frontend_ops ddbridge_dummy_fe_qam_ops = { + .delsys = { SYS_DVBC_ANNEX_A }, +diff --git a/drivers/media/pci/intel/Kconfig b/drivers/media/pci/intel/Kconfig +new file mode 100644 +index 0000000000000..51b18fce6a1de +--- /dev/null ++++ b/drivers/media/pci/intel/Kconfig +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config IPU_BRIDGE ++ tristate ++ depends on I2C && ACPI ++ help ++ This is a helper module for the IPU bridge, which can be ++ used by ipu3 and other drivers. In order to handle module ++ dependencies, this is selected by each driver that needs it. ++ ++source "drivers/media/pci/intel/ipu3/Kconfig" +diff --git a/drivers/media/pci/intel/Makefile b/drivers/media/pci/intel/Makefile +index 0b4236c4db49a..951191a7e4011 100644 +--- a/drivers/media/pci/intel/Makefile ++++ b/drivers/media/pci/intel/Makefile +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0-only + # +-# Makefile for the IPU3 cio2 and ImGU drivers ++# Makefile for the IPU drivers + # +- ++obj-$(CONFIG_IPU_BRIDGE) += ipu-bridge.o + obj-y += ipu3/ +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +new file mode 100644 +index 0000000000000..c5c44fb43c97a +--- /dev/null ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -0,0 +1,502 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Author: Dan Scally <djrscally@gmail.com> */ ++ ++#include <linux/acpi.h> ++#include <linux/device.h> ++#include <linux/i2c.h> ++#include <linux/pci.h> ++#include <linux/property.h> ++#include <media/v4l2-fwnode.h> ++ ++#include "ipu-bridge.h" ++ ++/* ++ * Extend this array with ACPI Hardware IDs of devices known to be working ++ * plus the number of link-frequencies expected by their drivers, along with ++ * the frequency values in hertz. This is somewhat opportunistic way of adding ++ * support for this for now in the hopes of a better source for the information ++ * (possibly some encoded value in the SSDB buffer that we're unaware of) ++ * becoming apparent in the future. ++ * ++ * Do not add an entry for a sensor that is not actually supported. ++ */ ++static const struct ipu_sensor_config ipu_supported_sensors[] = { ++ /* Omnivision OV5693 */ ++ IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), ++ /* Omnivision OV8865 */ ++ IPU_SENSOR_CONFIG("INT347A", 1, 360000000), ++ /* Omnivision OV7251 */ ++ IPU_SENSOR_CONFIG("INT347E", 1, 319200000), ++ /* Omnivision OV2680 */ ++ IPU_SENSOR_CONFIG("OVTI2680", 0), ++ /* Omnivision ov8856 */ ++ IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), ++ /* Omnivision ov2740 */ ++ IPU_SENSOR_CONFIG("INT3474", 1, 360000000), ++ /* Hynix hi556 */ ++ IPU_SENSOR_CONFIG("INT3537", 1, 437000000), ++ /* Omnivision ov13b10 */ ++ IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), ++}; ++ ++static const struct ipu_property_names prop_names = { ++ .clock_frequency = "clock-frequency", ++ .rotation = "rotation", ++ .orientation = "orientation", ++ .bus_type = "bus-type", ++ .data_lanes = "data-lanes", ++ .remote_endpoint = "remote-endpoint", ++ .link_frequencies = "link-frequencies", ++}; ++ ++static const char * const ipu_vcm_types[] = { ++ "ad5823", ++ "dw9714", ++ "ad5816", ++ "dw9719", ++ "dw9718", ++ "dw9806b", ++ "wv517s", ++ "lc898122xa", ++ "lc898212axb", ++}; ++ ++static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id, ++ void *data, u32 size) ++{ ++ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; ++ union acpi_object *obj; ++ acpi_status status; ++ int ret = 0; ++ ++ status = acpi_evaluate_object(adev->handle, id, NULL, &buffer); ++ if (ACPI_FAILURE(status)) ++ return -ENODEV; ++ ++ obj = buffer.pointer; ++ if (!obj) { ++ dev_err(&adev->dev, "Couldn't locate ACPI buffer\n"); ++ return -ENODEV; ++ } ++ ++ if (obj->type != ACPI_TYPE_BUFFER) { ++ dev_err(&adev->dev, "Not an ACPI buffer\n"); ++ ret = -ENODEV; ++ goto out_free_buff; ++ } ++ ++ if (obj->buffer.length > size) { ++ dev_err(&adev->dev, "Given buffer is too small\n"); ++ ret = -EINVAL; ++ goto out_free_buff; ++ } ++ ++ memcpy(data, obj->buffer.pointer, obj->buffer.length); ++ ++out_free_buff: ++ kfree(buffer.pointer); ++ return ret; ++} ++ ++static u32 ipu_bridge_parse_rotation(struct ipu_sensor *sensor) ++{ ++ switch (sensor->ssdb.degree) { ++ case IPU_SENSOR_ROTATION_NORMAL: ++ return 0; ++ case IPU_SENSOR_ROTATION_INVERTED: ++ return 180; ++ default: ++ dev_warn(&sensor->adev->dev, ++ "Unknown rotation %d. Assume 0 degree rotation\n", ++ sensor->ssdb.degree); ++ return 0; ++ } ++} ++ ++static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct ipu_sensor *sensor) ++{ ++ switch (sensor->pld->panel) { ++ case ACPI_PLD_PANEL_FRONT: ++ return V4L2_FWNODE_ORIENTATION_FRONT; ++ case ACPI_PLD_PANEL_BACK: ++ return V4L2_FWNODE_ORIENTATION_BACK; ++ case ACPI_PLD_PANEL_TOP: ++ case ACPI_PLD_PANEL_LEFT: ++ case ACPI_PLD_PANEL_RIGHT: ++ case ACPI_PLD_PANEL_UNKNOWN: ++ return V4L2_FWNODE_ORIENTATION_EXTERNAL; ++ default: ++ dev_warn(&sensor->adev->dev, "Unknown _PLD panel value %d\n", ++ sensor->pld->panel); ++ return V4L2_FWNODE_ORIENTATION_EXTERNAL; ++ } ++} ++ ++static void ipu_bridge_create_fwnode_properties( ++ struct ipu_sensor *sensor, ++ struct ipu_bridge *bridge, ++ const struct ipu_sensor_config *cfg) ++{ ++ u32 rotation; ++ enum v4l2_fwnode_orientation orientation; ++ ++ rotation = ipu_bridge_parse_rotation(sensor); ++ orientation = ipu_bridge_parse_orientation(sensor); ++ ++ sensor->prop_names = prop_names; ++ ++ sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_IPU_ENDPOINT]); ++ sensor->remote_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_SENSOR_ENDPOINT]); ++ ++ sensor->dev_properties[0] = PROPERTY_ENTRY_U32( ++ sensor->prop_names.clock_frequency, ++ sensor->ssdb.mclkspeed); ++ sensor->dev_properties[1] = PROPERTY_ENTRY_U32( ++ sensor->prop_names.rotation, ++ rotation); ++ sensor->dev_properties[2] = PROPERTY_ENTRY_U32( ++ sensor->prop_names.orientation, ++ orientation); ++ if (sensor->ssdb.vcmtype) { ++ sensor->vcm_ref[0] = ++ SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_VCM]); ++ sensor->dev_properties[3] = ++ PROPERTY_ENTRY_REF_ARRAY("lens-focus", sensor->vcm_ref); ++ } ++ ++ sensor->ep_properties[0] = PROPERTY_ENTRY_U32( ++ sensor->prop_names.bus_type, ++ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY); ++ sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN( ++ sensor->prop_names.data_lanes, ++ bridge->data_lanes, ++ sensor->ssdb.lanes); ++ sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY( ++ sensor->prop_names.remote_endpoint, ++ sensor->local_ref); ++ ++ if (cfg->nr_link_freqs > 0) ++ sensor->ep_properties[3] = PROPERTY_ENTRY_U64_ARRAY_LEN( ++ sensor->prop_names.link_frequencies, ++ cfg->link_freqs, ++ cfg->nr_link_freqs); ++ ++ sensor->ipu_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN( ++ sensor->prop_names.data_lanes, ++ bridge->data_lanes, ++ sensor->ssdb.lanes); ++ sensor->ipu_properties[1] = PROPERTY_ENTRY_REF_ARRAY( ++ sensor->prop_names.remote_endpoint, ++ sensor->remote_ref); ++} ++ ++static void ipu_bridge_init_swnode_names(struct ipu_sensor *sensor) ++{ ++ snprintf(sensor->node_names.remote_port, ++ sizeof(sensor->node_names.remote_port), ++ SWNODE_GRAPH_PORT_NAME_FMT, sensor->ssdb.link); ++ snprintf(sensor->node_names.port, ++ sizeof(sensor->node_names.port), ++ SWNODE_GRAPH_PORT_NAME_FMT, 0); /* Always port 0 */ ++ snprintf(sensor->node_names.endpoint, ++ sizeof(sensor->node_names.endpoint), ++ SWNODE_GRAPH_ENDPOINT_NAME_FMT, 0); /* And endpoint 0 */ ++} ++ ++static void ipu_bridge_init_swnode_group(struct ipu_sensor *sensor) ++{ ++ struct software_node *nodes = sensor->swnodes; ++ ++ sensor->group[SWNODE_SENSOR_HID] = &nodes[SWNODE_SENSOR_HID]; ++ sensor->group[SWNODE_SENSOR_PORT] = &nodes[SWNODE_SENSOR_PORT]; ++ sensor->group[SWNODE_SENSOR_ENDPOINT] = &nodes[SWNODE_SENSOR_ENDPOINT]; ++ sensor->group[SWNODE_IPU_PORT] = &nodes[SWNODE_IPU_PORT]; ++ sensor->group[SWNODE_IPU_ENDPOINT] = &nodes[SWNODE_IPU_ENDPOINT]; ++ if (sensor->ssdb.vcmtype) ++ sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM]; ++} ++ ++static void ipu_bridge_create_connection_swnodes(struct ipu_bridge *bridge, ++ struct ipu_sensor *sensor) ++{ ++ struct software_node *nodes = sensor->swnodes; ++ ++ ipu_bridge_init_swnode_names(sensor); ++ ++ nodes[SWNODE_SENSOR_HID] = NODE_SENSOR(sensor->name, ++ sensor->dev_properties); ++ nodes[SWNODE_SENSOR_PORT] = NODE_PORT(sensor->node_names.port, ++ &nodes[SWNODE_SENSOR_HID]); ++ nodes[SWNODE_SENSOR_ENDPOINT] = NODE_ENDPOINT( ++ sensor->node_names.endpoint, ++ &nodes[SWNODE_SENSOR_PORT], ++ sensor->ep_properties); ++ nodes[SWNODE_IPU_PORT] = NODE_PORT(sensor->node_names.remote_port, ++ &bridge->ipu_hid_node); ++ nodes[SWNODE_IPU_ENDPOINT] = NODE_ENDPOINT( ++ sensor->node_names.endpoint, ++ &nodes[SWNODE_IPU_PORT], ++ sensor->ipu_properties); ++ if (sensor->ssdb.vcmtype) { ++ /* append ssdb.link to distinguish VCM nodes with same HID */ ++ snprintf(sensor->node_names.vcm, sizeof(sensor->node_names.vcm), ++ "%s-%u", ipu_vcm_types[sensor->ssdb.vcmtype - 1], ++ sensor->ssdb.link); ++ nodes[SWNODE_VCM] = NODE_VCM(sensor->node_names.vcm); ++ } ++ ++ ipu_bridge_init_swnode_group(sensor); ++} ++ ++static void ipu_bridge_instantiate_vcm_i2c_client(struct ipu_sensor *sensor) ++{ ++ struct i2c_board_info board_info = { }; ++ char name[16]; ++ ++ if (!sensor->ssdb.vcmtype) ++ return; ++ ++ snprintf(name, sizeof(name), "%s-VCM", acpi_dev_name(sensor->adev)); ++ board_info.dev_name = name; ++ strscpy(board_info.type, ipu_vcm_types[sensor->ssdb.vcmtype - 1], ++ ARRAY_SIZE(board_info.type)); ++ board_info.swnode = &sensor->swnodes[SWNODE_VCM]; ++ ++ sensor->vcm_i2c_client = ++ i2c_acpi_new_device_by_fwnode(acpi_fwnode_handle(sensor->adev), ++ 1, &board_info); ++ if (IS_ERR(sensor->vcm_i2c_client)) { ++ dev_warn(&sensor->adev->dev, "Error instantiation VCM i2c-client: %ld\n", ++ PTR_ERR(sensor->vcm_i2c_client)); ++ sensor->vcm_i2c_client = NULL; ++ } ++} ++ ++static void ipu_bridge_unregister_sensors(struct ipu_bridge *bridge) ++{ ++ struct ipu_sensor *sensor; ++ unsigned int i; ++ ++ for (i = 0; i < bridge->n_sensors; i++) { ++ sensor = &bridge->sensors[i]; ++ software_node_unregister_node_group(sensor->group); ++ ACPI_FREE(sensor->pld); ++ acpi_dev_put(sensor->adev); ++ i2c_unregister_device(sensor->vcm_i2c_client); ++ } ++} ++ ++static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg, ++ struct ipu_bridge *bridge, ++ struct pci_dev *ipu) ++{ ++ struct fwnode_handle *fwnode, *primary; ++ struct ipu_sensor *sensor; ++ struct acpi_device *adev; ++ acpi_status status; ++ int ret; ++ ++ for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { ++ if (!adev->status.enabled) ++ continue; ++ ++ if (bridge->n_sensors >= CIO2_NUM_PORTS) { ++ acpi_dev_put(adev); ++ dev_err(&ipu->dev, "Exceeded available IPU ports\n"); ++ return -EINVAL; ++ } ++ ++ sensor = &bridge->sensors[bridge->n_sensors]; ++ /* ++ * Borrow our adev ref to the sensor for now, on success ++ * acpi_dev_get(adev) is done further below. ++ */ ++ sensor->adev = adev; ++ ++ ret = ipu_bridge_read_acpi_buffer(adev, "SSDB", ++ &sensor->ssdb, ++ sizeof(sensor->ssdb)); ++ if (ret) ++ goto err_put_adev; ++ ++ snprintf(sensor->name, sizeof(sensor->name), "%s-%u", ++ cfg->hid, sensor->ssdb.link); ++ ++ if (sensor->ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) { ++ dev_warn(&adev->dev, "Unknown VCM type %d\n", ++ sensor->ssdb.vcmtype); ++ sensor->ssdb.vcmtype = 0; ++ } ++ ++ status = acpi_get_physical_device_location(adev->handle, &sensor->pld); ++ if (ACPI_FAILURE(status)) { ++ ret = -ENODEV; ++ goto err_put_adev; ++ } ++ ++ if (sensor->ssdb.lanes > IPU_MAX_LANES) { ++ dev_err(&adev->dev, ++ "Number of lanes in SSDB is invalid\n"); ++ ret = -EINVAL; ++ goto err_free_pld; ++ } ++ ++ ipu_bridge_create_fwnode_properties(sensor, bridge, cfg); ++ ipu_bridge_create_connection_swnodes(bridge, sensor); ++ ++ ret = software_node_register_node_group(sensor->group); ++ if (ret) ++ goto err_free_pld; ++ ++ fwnode = software_node_fwnode(&sensor->swnodes[ ++ SWNODE_SENSOR_HID]); ++ if (!fwnode) { ++ ret = -ENODEV; ++ goto err_free_swnodes; ++ } ++ ++ sensor->adev = acpi_dev_get(adev); ++ ++ primary = acpi_fwnode_handle(adev); ++ primary->secondary = fwnode; ++ ++ ipu_bridge_instantiate_vcm_i2c_client(sensor); ++ ++ dev_info(&ipu->dev, "Found supported sensor %s\n", ++ acpi_dev_name(adev)); ++ ++ bridge->n_sensors++; ++ } ++ ++ return 0; ++ ++err_free_swnodes: ++ software_node_unregister_node_group(sensor->group); ++err_free_pld: ++ ACPI_FREE(sensor->pld); ++err_put_adev: ++ acpi_dev_put(adev); ++ return ret; ++} ++ ++static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge, ++ struct pci_dev *ipu) ++{ ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) { ++ const struct ipu_sensor_config *cfg = ++ &ipu_supported_sensors[i]; ++ ++ ret = ipu_bridge_connect_sensor(cfg, bridge, ipu); ++ if (ret) ++ goto err_unregister_sensors; ++ } ++ ++ return 0; ++ ++err_unregister_sensors: ++ ipu_bridge_unregister_sensors(bridge); ++ return ret; ++} ++ ++/* ++ * The VCM cannot be probed until the PMIC is completely setup. We cannot rely ++ * on -EPROBE_DEFER for this, since the consumer<->supplier relations between ++ * the VCM and regulators/clks are not described in ACPI, instead they are ++ * passed as board-data to the PMIC drivers. Since -PROBE_DEFER does not work ++ * for the clks/regulators the VCM i2c-clients must not be instantiated until ++ * the PMIC is fully setup. ++ * ++ * The sensor/VCM ACPI device has an ACPI _DEP on the PMIC, check this using the ++ * acpi_dev_ready_for_enumeration() helper, like the i2c-core-acpi code does ++ * for the sensors. ++ */ ++static int ipu_bridge_sensors_are_ready(void) ++{ ++ struct acpi_device *adev; ++ bool ready = true; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) { ++ const struct ipu_sensor_config *cfg = ++ &ipu_supported_sensors[i]; ++ ++ for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { ++ if (!adev->status.enabled) ++ continue; ++ ++ if (!acpi_dev_ready_for_enumeration(adev)) ++ ready = false; ++ } ++ } ++ ++ return ready; ++} ++ ++int ipu_bridge_init(struct pci_dev *ipu) ++{ ++ struct device *dev = &ipu->dev; ++ struct fwnode_handle *fwnode; ++ struct ipu_bridge *bridge; ++ unsigned int i; ++ int ret; ++ ++ if (!ipu_bridge_sensors_are_ready()) ++ return -EPROBE_DEFER; ++ ++ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); ++ if (!bridge) ++ return -ENOMEM; ++ ++ strscpy(bridge->ipu_node_name, IPU_HID, ++ sizeof(bridge->ipu_node_name)); ++ bridge->ipu_hid_node.name = bridge->ipu_node_name; ++ ++ ret = software_node_register(&bridge->ipu_hid_node); ++ if (ret < 0) { ++ dev_err(dev, "Failed to register the IPU HID node\n"); ++ goto err_free_bridge; ++ } ++ ++ /* ++ * Map the lane arrangement, which is fixed for the IPU3 (meaning we ++ * only need one, rather than one per sensor). We include it as a ++ * member of the struct ipu_bridge rather than a global variable so ++ * that it survives if the module is unloaded along with the rest of ++ * the struct. ++ */ ++ for (i = 0; i < IPU_MAX_LANES; i++) ++ bridge->data_lanes[i] = i + 1; ++ ++ ret = ipu_bridge_connect_sensors(bridge, ipu); ++ if (ret || bridge->n_sensors == 0) ++ goto err_unregister_ipu; ++ ++ dev_info(dev, "Connected %d cameras\n", bridge->n_sensors); ++ ++ fwnode = software_node_fwnode(&bridge->ipu_hid_node); ++ if (!fwnode) { ++ dev_err(dev, "Error getting fwnode from ipu software_node\n"); ++ ret = -ENODEV; ++ goto err_unregister_sensors; ++ } ++ ++ set_secondary_fwnode(dev, fwnode); ++ ++ return 0; ++ ++err_unregister_sensors: ++ ipu_bridge_unregister_sensors(bridge); ++err_unregister_ipu: ++ software_node_unregister(&bridge->ipu_hid_node); ++err_free_bridge: ++ kfree(bridge); ++ ++ return ret; ++} ++EXPORT_SYMBOL_NS_GPL(ipu_bridge_init, INTEL_IPU_BRIDGE); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Intel IPU Sensors Bridge driver"); +diff --git a/drivers/media/pci/intel/ipu-bridge.h b/drivers/media/pci/intel/ipu-bridge.h +new file mode 100644 +index 0000000000000..1ff0b2d04d929 +--- /dev/null ++++ b/drivers/media/pci/intel/ipu-bridge.h +@@ -0,0 +1,153 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Author: Dan Scally <djrscally@gmail.com> */ ++#ifndef __IPU_BRIDGE_H ++#define __IPU_BRIDGE_H ++ ++#include <linux/property.h> ++#include <linux/types.h> ++ ++#include "ipu3/ipu3-cio2.h" ++ ++struct i2c_client; ++ ++#define IPU_HID "INT343E" ++#define IPU_MAX_LANES 4 ++#define MAX_NUM_LINK_FREQS 3 ++ ++/* Values are educated guesses as we don't have a spec */ ++#define IPU_SENSOR_ROTATION_NORMAL 0 ++#define IPU_SENSOR_ROTATION_INVERTED 1 ++ ++#define IPU_SENSOR_CONFIG(_HID, _NR, ...) \ ++ (const struct ipu_sensor_config) { \ ++ .hid = _HID, \ ++ .nr_link_freqs = _NR, \ ++ .link_freqs = { __VA_ARGS__ } \ ++ } ++ ++#define NODE_SENSOR(_HID, _PROPS) \ ++ (const struct software_node) { \ ++ .name = _HID, \ ++ .properties = _PROPS, \ ++ } ++ ++#define NODE_PORT(_PORT, _SENSOR_NODE) \ ++ (const struct software_node) { \ ++ .name = _PORT, \ ++ .parent = _SENSOR_NODE, \ ++ } ++ ++#define NODE_ENDPOINT(_EP, _PORT, _PROPS) \ ++ (const struct software_node) { \ ++ .name = _EP, \ ++ .parent = _PORT, \ ++ .properties = _PROPS, \ ++ } ++ ++#define NODE_VCM(_TYPE) \ ++ (const struct software_node) { \ ++ .name = _TYPE, \ ++ } ++ ++enum ipu_sensor_swnodes { ++ SWNODE_SENSOR_HID, ++ SWNODE_SENSOR_PORT, ++ SWNODE_SENSOR_ENDPOINT, ++ SWNODE_IPU_PORT, ++ SWNODE_IPU_ENDPOINT, ++ /* Must be last because it is optional / maybe empty */ ++ SWNODE_VCM, ++ SWNODE_COUNT ++}; ++ ++/* Data representation as it is in ACPI SSDB buffer */ ++struct ipu_sensor_ssdb { ++ u8 version; ++ u8 sku; ++ u8 guid_csi2[16]; ++ u8 devfunction; ++ u8 bus; ++ u32 dphylinkenfuses; ++ u32 clockdiv; ++ u8 link; ++ u8 lanes; ++ u32 csiparams[10]; ++ u32 maxlanespeed; ++ u8 sensorcalibfileidx; ++ u8 sensorcalibfileidxInMBZ[3]; ++ u8 romtype; ++ u8 vcmtype; ++ u8 platforminfo; ++ u8 platformsubinfo; ++ u8 flash; ++ u8 privacyled; ++ u8 degree; ++ u8 mipilinkdefined; ++ u32 mclkspeed; ++ u8 controllogicid; ++ u8 reserved1[3]; ++ u8 mclkport; ++ u8 reserved2[13]; ++} __packed; ++ ++struct ipu_property_names { ++ char clock_frequency[16]; ++ char rotation[9]; ++ char orientation[12]; ++ char bus_type[9]; ++ char data_lanes[11]; ++ char remote_endpoint[16]; ++ char link_frequencies[17]; ++}; ++ ++struct ipu_node_names { ++ char port[7]; ++ char endpoint[11]; ++ char remote_port[7]; ++ char vcm[16]; ++}; ++ ++struct ipu_sensor_config { ++ const char *hid; ++ const u8 nr_link_freqs; ++ const u64 link_freqs[MAX_NUM_LINK_FREQS]; ++}; ++ ++struct ipu_sensor { ++ /* append ssdb.link(u8) in "-%u" format as suffix of HID */ ++ char name[ACPI_ID_LEN + 4]; ++ struct acpi_device *adev; ++ struct i2c_client *vcm_i2c_client; ++ ++ /* SWNODE_COUNT + 1 for terminating NULL */ ++ const struct software_node *group[SWNODE_COUNT + 1]; ++ struct software_node swnodes[SWNODE_COUNT]; ++ struct ipu_node_names node_names; ++ ++ struct ipu_sensor_ssdb ssdb; ++ struct acpi_pld_info *pld; ++ ++ struct ipu_property_names prop_names; ++ struct property_entry ep_properties[5]; ++ struct property_entry dev_properties[5]; ++ struct property_entry ipu_properties[3]; ++ struct software_node_ref_args local_ref[1]; ++ struct software_node_ref_args remote_ref[1]; ++ struct software_node_ref_args vcm_ref[1]; ++}; ++ ++struct ipu_bridge { ++ char ipu_node_name[ACPI_ID_LEN]; ++ struct software_node ipu_hid_node; ++ u32 data_lanes[4]; ++ unsigned int n_sensors; ++ struct ipu_sensor sensors[CIO2_NUM_PORTS]; ++}; ++ ++#if IS_ENABLED(CONFIG_IPU_BRIDGE) ++int ipu_bridge_init(struct pci_dev *ipu); ++#else ++static inline int ipu_bridge_init(struct pci_dev *ipu) { return 0; } ++#endif ++ ++#endif +diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig +index 65b0c1598fbf1..0951545eab21a 100644 +--- a/drivers/media/pci/intel/ipu3/Kconfig ++++ b/drivers/media/pci/intel/ipu3/Kconfig +@@ -8,6 +8,7 @@ config VIDEO_IPU3_CIO2 + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + select VIDEOBUF2_DMA_SG ++ select IPU_BRIDGE if CIO2_BRIDGE + + help + This is the Intel IPU3 CIO2 CSI-2 receiver unit, found in Intel +diff --git a/drivers/media/pci/intel/ipu3/Makefile b/drivers/media/pci/intel/ipu3/Makefile +index 933777e6ea8ab..429d516452e42 100644 +--- a/drivers/media/pci/intel/ipu3/Makefile ++++ b/drivers/media/pci/intel/ipu3/Makefile +@@ -2,4 +2,3 @@ + obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o + + ipu3-cio2-y += ipu3-cio2-main.o +-ipu3-cio2-$(CONFIG_CIO2_BRIDGE) += cio2-bridge.o +diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c +deleted file mode 100644 +index 3c2accfe54551..0000000000000 +--- a/drivers/media/pci/intel/ipu3/cio2-bridge.c ++++ /dev/null +@@ -1,494 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* Author: Dan Scally <djrscally@gmail.com> */ +- +-#include <linux/acpi.h> +-#include <linux/device.h> +-#include <linux/i2c.h> +-#include <linux/pci.h> +-#include <linux/property.h> +-#include <media/v4l2-fwnode.h> +- +-#include "cio2-bridge.h" +- +-/* +- * Extend this array with ACPI Hardware IDs of devices known to be working +- * plus the number of link-frequencies expected by their drivers, along with +- * the frequency values in hertz. This is somewhat opportunistic way of adding +- * support for this for now in the hopes of a better source for the information +- * (possibly some encoded value in the SSDB buffer that we're unaware of) +- * becoming apparent in the future. +- * +- * Do not add an entry for a sensor that is not actually supported. +- */ +-static const struct cio2_sensor_config cio2_supported_sensors[] = { +- /* Omnivision OV5693 */ +- CIO2_SENSOR_CONFIG("INT33BE", 1, 419200000), +- /* Omnivision OV8865 */ +- CIO2_SENSOR_CONFIG("INT347A", 1, 360000000), +- /* Omnivision OV7251 */ +- CIO2_SENSOR_CONFIG("INT347E", 1, 319200000), +- /* Omnivision OV2680 */ +- CIO2_SENSOR_CONFIG("OVTI2680", 0), +- /* Omnivision ov8856 */ +- CIO2_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), +- /* Omnivision ov2740 */ +- CIO2_SENSOR_CONFIG("INT3474", 1, 360000000), +- /* Hynix hi556 */ +- CIO2_SENSOR_CONFIG("INT3537", 1, 437000000), +- /* Omnivision ov13b10 */ +- CIO2_SENSOR_CONFIG("OVTIDB10", 1, 560000000), +-}; +- +-static const struct cio2_property_names prop_names = { +- .clock_frequency = "clock-frequency", +- .rotation = "rotation", +- .orientation = "orientation", +- .bus_type = "bus-type", +- .data_lanes = "data-lanes", +- .remote_endpoint = "remote-endpoint", +- .link_frequencies = "link-frequencies", +-}; +- +-static const char * const cio2_vcm_types[] = { +- "ad5823", +- "dw9714", +- "ad5816", +- "dw9719", +- "dw9718", +- "dw9806b", +- "wv517s", +- "lc898122xa", +- "lc898212axb", +-}; +- +-static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id, +- void *data, u32 size) +-{ +- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; +- union acpi_object *obj; +- acpi_status status; +- int ret = 0; +- +- status = acpi_evaluate_object(adev->handle, id, NULL, &buffer); +- if (ACPI_FAILURE(status)) +- return -ENODEV; +- +- obj = buffer.pointer; +- if (!obj) { +- dev_err(&adev->dev, "Couldn't locate ACPI buffer\n"); +- return -ENODEV; +- } +- +- if (obj->type != ACPI_TYPE_BUFFER) { +- dev_err(&adev->dev, "Not an ACPI buffer\n"); +- ret = -ENODEV; +- goto out_free_buff; +- } +- +- if (obj->buffer.length > size) { +- dev_err(&adev->dev, "Given buffer is too small\n"); +- ret = -EINVAL; +- goto out_free_buff; +- } +- +- memcpy(data, obj->buffer.pointer, obj->buffer.length); +- +-out_free_buff: +- kfree(buffer.pointer); +- return ret; +-} +- +-static u32 cio2_bridge_parse_rotation(struct cio2_sensor *sensor) +-{ +- switch (sensor->ssdb.degree) { +- case CIO2_SENSOR_ROTATION_NORMAL: +- return 0; +- case CIO2_SENSOR_ROTATION_INVERTED: +- return 180; +- default: +- dev_warn(&sensor->adev->dev, +- "Unknown rotation %d. Assume 0 degree rotation\n", +- sensor->ssdb.degree); +- return 0; +- } +-} +- +-static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(struct cio2_sensor *sensor) +-{ +- switch (sensor->pld->panel) { +- case ACPI_PLD_PANEL_FRONT: +- return V4L2_FWNODE_ORIENTATION_FRONT; +- case ACPI_PLD_PANEL_BACK: +- return V4L2_FWNODE_ORIENTATION_BACK; +- case ACPI_PLD_PANEL_TOP: +- case ACPI_PLD_PANEL_LEFT: +- case ACPI_PLD_PANEL_RIGHT: +- case ACPI_PLD_PANEL_UNKNOWN: +- return V4L2_FWNODE_ORIENTATION_EXTERNAL; +- default: +- dev_warn(&sensor->adev->dev, "Unknown _PLD panel value %d\n", +- sensor->pld->panel); +- return V4L2_FWNODE_ORIENTATION_EXTERNAL; +- } +-} +- +-static void cio2_bridge_create_fwnode_properties( +- struct cio2_sensor *sensor, +- struct cio2_bridge *bridge, +- const struct cio2_sensor_config *cfg) +-{ +- u32 rotation; +- enum v4l2_fwnode_orientation orientation; +- +- rotation = cio2_bridge_parse_rotation(sensor); +- orientation = cio2_bridge_parse_orientation(sensor); +- +- sensor->prop_names = prop_names; +- +- sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_CIO2_ENDPOINT]); +- sensor->remote_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_SENSOR_ENDPOINT]); +- +- sensor->dev_properties[0] = PROPERTY_ENTRY_U32( +- sensor->prop_names.clock_frequency, +- sensor->ssdb.mclkspeed); +- sensor->dev_properties[1] = PROPERTY_ENTRY_U32( +- sensor->prop_names.rotation, +- rotation); +- sensor->dev_properties[2] = PROPERTY_ENTRY_U32( +- sensor->prop_names.orientation, +- orientation); +- if (sensor->ssdb.vcmtype) { +- sensor->vcm_ref[0] = +- SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_VCM]); +- sensor->dev_properties[3] = +- PROPERTY_ENTRY_REF_ARRAY("lens-focus", sensor->vcm_ref); +- } +- +- sensor->ep_properties[0] = PROPERTY_ENTRY_U32( +- sensor->prop_names.bus_type, +- V4L2_FWNODE_BUS_TYPE_CSI2_DPHY); +- sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN( +- sensor->prop_names.data_lanes, +- bridge->data_lanes, +- sensor->ssdb.lanes); +- sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY( +- sensor->prop_names.remote_endpoint, +- sensor->local_ref); +- +- if (cfg->nr_link_freqs > 0) +- sensor->ep_properties[3] = PROPERTY_ENTRY_U64_ARRAY_LEN( +- sensor->prop_names.link_frequencies, +- cfg->link_freqs, +- cfg->nr_link_freqs); +- +- sensor->cio2_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN( +- sensor->prop_names.data_lanes, +- bridge->data_lanes, +- sensor->ssdb.lanes); +- sensor->cio2_properties[1] = PROPERTY_ENTRY_REF_ARRAY( +- sensor->prop_names.remote_endpoint, +- sensor->remote_ref); +-} +- +-static void cio2_bridge_init_swnode_names(struct cio2_sensor *sensor) +-{ +- snprintf(sensor->node_names.remote_port, +- sizeof(sensor->node_names.remote_port), +- SWNODE_GRAPH_PORT_NAME_FMT, sensor->ssdb.link); +- snprintf(sensor->node_names.port, +- sizeof(sensor->node_names.port), +- SWNODE_GRAPH_PORT_NAME_FMT, 0); /* Always port 0 */ +- snprintf(sensor->node_names.endpoint, +- sizeof(sensor->node_names.endpoint), +- SWNODE_GRAPH_ENDPOINT_NAME_FMT, 0); /* And endpoint 0 */ +-} +- +-static void cio2_bridge_init_swnode_group(struct cio2_sensor *sensor) +-{ +- struct software_node *nodes = sensor->swnodes; +- +- sensor->group[SWNODE_SENSOR_HID] = &nodes[SWNODE_SENSOR_HID]; +- sensor->group[SWNODE_SENSOR_PORT] = &nodes[SWNODE_SENSOR_PORT]; +- sensor->group[SWNODE_SENSOR_ENDPOINT] = &nodes[SWNODE_SENSOR_ENDPOINT]; +- sensor->group[SWNODE_CIO2_PORT] = &nodes[SWNODE_CIO2_PORT]; +- sensor->group[SWNODE_CIO2_ENDPOINT] = &nodes[SWNODE_CIO2_ENDPOINT]; +- if (sensor->ssdb.vcmtype) +- sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM]; +-} +- +-static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge, +- struct cio2_sensor *sensor) +-{ +- struct software_node *nodes = sensor->swnodes; +- char vcm_name[ACPI_ID_LEN + 4]; +- +- cio2_bridge_init_swnode_names(sensor); +- +- nodes[SWNODE_SENSOR_HID] = NODE_SENSOR(sensor->name, +- sensor->dev_properties); +- nodes[SWNODE_SENSOR_PORT] = NODE_PORT(sensor->node_names.port, +- &nodes[SWNODE_SENSOR_HID]); +- nodes[SWNODE_SENSOR_ENDPOINT] = NODE_ENDPOINT( +- sensor->node_names.endpoint, +- &nodes[SWNODE_SENSOR_PORT], +- sensor->ep_properties); +- nodes[SWNODE_CIO2_PORT] = NODE_PORT(sensor->node_names.remote_port, +- &bridge->cio2_hid_node); +- nodes[SWNODE_CIO2_ENDPOINT] = NODE_ENDPOINT( +- sensor->node_names.endpoint, +- &nodes[SWNODE_CIO2_PORT], +- sensor->cio2_properties); +- if (sensor->ssdb.vcmtype) { +- /* append ssdb.link to distinguish VCM nodes with same HID */ +- snprintf(vcm_name, sizeof(vcm_name), "%s-%u", +- cio2_vcm_types[sensor->ssdb.vcmtype - 1], +- sensor->ssdb.link); +- nodes[SWNODE_VCM] = NODE_VCM(vcm_name); +- } +- +- cio2_bridge_init_swnode_group(sensor); +-} +- +-static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor) +-{ +- struct i2c_board_info board_info = { }; +- char name[16]; +- +- if (!sensor->ssdb.vcmtype) +- return; +- +- snprintf(name, sizeof(name), "%s-VCM", acpi_dev_name(sensor->adev)); +- board_info.dev_name = name; +- strscpy(board_info.type, cio2_vcm_types[sensor->ssdb.vcmtype - 1], +- ARRAY_SIZE(board_info.type)); +- board_info.swnode = &sensor->swnodes[SWNODE_VCM]; +- +- sensor->vcm_i2c_client = +- i2c_acpi_new_device_by_fwnode(acpi_fwnode_handle(sensor->adev), +- 1, &board_info); +- if (IS_ERR(sensor->vcm_i2c_client)) { +- dev_warn(&sensor->adev->dev, "Error instantiation VCM i2c-client: %ld\n", +- PTR_ERR(sensor->vcm_i2c_client)); +- sensor->vcm_i2c_client = NULL; +- } +-} +- +-static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge) +-{ +- struct cio2_sensor *sensor; +- unsigned int i; +- +- for (i = 0; i < bridge->n_sensors; i++) { +- sensor = &bridge->sensors[i]; +- software_node_unregister_node_group(sensor->group); +- ACPI_FREE(sensor->pld); +- acpi_dev_put(sensor->adev); +- i2c_unregister_device(sensor->vcm_i2c_client); +- } +-} +- +-static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, +- struct cio2_bridge *bridge, +- struct pci_dev *cio2) +-{ +- struct fwnode_handle *fwnode, *primary; +- struct cio2_sensor *sensor; +- struct acpi_device *adev; +- acpi_status status; +- int ret; +- +- for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { +- if (!adev->status.enabled) +- continue; +- +- if (bridge->n_sensors >= CIO2_NUM_PORTS) { +- acpi_dev_put(adev); +- dev_err(&cio2->dev, "Exceeded available CIO2 ports\n"); +- return -EINVAL; +- } +- +- sensor = &bridge->sensors[bridge->n_sensors]; +- +- ret = cio2_bridge_read_acpi_buffer(adev, "SSDB", +- &sensor->ssdb, +- sizeof(sensor->ssdb)); +- if (ret) +- goto err_put_adev; +- +- snprintf(sensor->name, sizeof(sensor->name), "%s-%u", +- cfg->hid, sensor->ssdb.link); +- +- if (sensor->ssdb.vcmtype > ARRAY_SIZE(cio2_vcm_types)) { +- dev_warn(&adev->dev, "Unknown VCM type %d\n", +- sensor->ssdb.vcmtype); +- sensor->ssdb.vcmtype = 0; +- } +- +- status = acpi_get_physical_device_location(adev->handle, &sensor->pld); +- if (ACPI_FAILURE(status)) { +- ret = -ENODEV; +- goto err_put_adev; +- } +- +- if (sensor->ssdb.lanes > CIO2_MAX_LANES) { +- dev_err(&adev->dev, +- "Number of lanes in SSDB is invalid\n"); +- ret = -EINVAL; +- goto err_free_pld; +- } +- +- cio2_bridge_create_fwnode_properties(sensor, bridge, cfg); +- cio2_bridge_create_connection_swnodes(bridge, sensor); +- +- ret = software_node_register_node_group(sensor->group); +- if (ret) +- goto err_free_pld; +- +- fwnode = software_node_fwnode(&sensor->swnodes[ +- SWNODE_SENSOR_HID]); +- if (!fwnode) { +- ret = -ENODEV; +- goto err_free_swnodes; +- } +- +- sensor->adev = acpi_dev_get(adev); +- +- primary = acpi_fwnode_handle(adev); +- primary->secondary = fwnode; +- +- cio2_bridge_instantiate_vcm_i2c_client(sensor); +- +- dev_info(&cio2->dev, "Found supported sensor %s\n", +- acpi_dev_name(adev)); +- +- bridge->n_sensors++; +- } +- +- return 0; +- +-err_free_swnodes: +- software_node_unregister_node_group(sensor->group); +-err_free_pld: +- ACPI_FREE(sensor->pld); +-err_put_adev: +- acpi_dev_put(adev); +- return ret; +-} +- +-static int cio2_bridge_connect_sensors(struct cio2_bridge *bridge, +- struct pci_dev *cio2) +-{ +- unsigned int i; +- int ret; +- +- for (i = 0; i < ARRAY_SIZE(cio2_supported_sensors); i++) { +- const struct cio2_sensor_config *cfg = +- &cio2_supported_sensors[i]; +- +- ret = cio2_bridge_connect_sensor(cfg, bridge, cio2); +- if (ret) +- goto err_unregister_sensors; +- } +- +- return 0; +- +-err_unregister_sensors: +- cio2_bridge_unregister_sensors(bridge); +- return ret; +-} +- +-/* +- * The VCM cannot be probed until the PMIC is completely setup. We cannot rely +- * on -EPROBE_DEFER for this, since the consumer<->supplier relations between +- * the VCM and regulators/clks are not described in ACPI, instead they are +- * passed as board-data to the PMIC drivers. Since -PROBE_DEFER does not work +- * for the clks/regulators the VCM i2c-clients must not be instantiated until +- * the PMIC is fully setup. +- * +- * The sensor/VCM ACPI device has an ACPI _DEP on the PMIC, check this using the +- * acpi_dev_ready_for_enumeration() helper, like the i2c-core-acpi code does +- * for the sensors. +- */ +-static int cio2_bridge_sensors_are_ready(void) +-{ +- struct acpi_device *adev; +- bool ready = true; +- unsigned int i; +- +- for (i = 0; i < ARRAY_SIZE(cio2_supported_sensors); i++) { +- const struct cio2_sensor_config *cfg = +- &cio2_supported_sensors[i]; +- +- for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { +- if (!adev->status.enabled) +- continue; +- +- if (!acpi_dev_ready_for_enumeration(adev)) +- ready = false; +- } +- } +- +- return ready; +-} +- +-int cio2_bridge_init(struct pci_dev *cio2) +-{ +- struct device *dev = &cio2->dev; +- struct fwnode_handle *fwnode; +- struct cio2_bridge *bridge; +- unsigned int i; +- int ret; +- +- if (!cio2_bridge_sensors_are_ready()) +- return -EPROBE_DEFER; +- +- bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); +- if (!bridge) +- return -ENOMEM; +- +- strscpy(bridge->cio2_node_name, CIO2_HID, +- sizeof(bridge->cio2_node_name)); +- bridge->cio2_hid_node.name = bridge->cio2_node_name; +- +- ret = software_node_register(&bridge->cio2_hid_node); +- if (ret < 0) { +- dev_err(dev, "Failed to register the CIO2 HID node\n"); +- goto err_free_bridge; +- } +- +- /* +- * Map the lane arrangement, which is fixed for the IPU3 (meaning we +- * only need one, rather than one per sensor). We include it as a +- * member of the struct cio2_bridge rather than a global variable so +- * that it survives if the module is unloaded along with the rest of +- * the struct. +- */ +- for (i = 0; i < CIO2_MAX_LANES; i++) +- bridge->data_lanes[i] = i + 1; +- +- ret = cio2_bridge_connect_sensors(bridge, cio2); +- if (ret || bridge->n_sensors == 0) +- goto err_unregister_cio2; +- +- dev_info(dev, "Connected %d cameras\n", bridge->n_sensors); +- +- fwnode = software_node_fwnode(&bridge->cio2_hid_node); +- if (!fwnode) { +- dev_err(dev, "Error getting fwnode from cio2 software_node\n"); +- ret = -ENODEV; +- goto err_unregister_sensors; +- } +- +- set_secondary_fwnode(dev, fwnode); +- +- return 0; +- +-err_unregister_sensors: +- cio2_bridge_unregister_sensors(bridge); +-err_unregister_cio2: +- software_node_unregister(&bridge->cio2_hid_node); +-err_free_bridge: +- kfree(bridge); +- +- return ret; +-} +diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h +deleted file mode 100644 +index b76ed8a641e20..0000000000000 +--- a/drivers/media/pci/intel/ipu3/cio2-bridge.h ++++ /dev/null +@@ -1,146 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* Author: Dan Scally <djrscally@gmail.com> */ +-#ifndef __CIO2_BRIDGE_H +-#define __CIO2_BRIDGE_H +- +-#include <linux/property.h> +-#include <linux/types.h> +- +-#include "ipu3-cio2.h" +- +-struct i2c_client; +- +-#define CIO2_HID "INT343E" +-#define CIO2_MAX_LANES 4 +-#define MAX_NUM_LINK_FREQS 3 +- +-/* Values are educated guesses as we don't have a spec */ +-#define CIO2_SENSOR_ROTATION_NORMAL 0 +-#define CIO2_SENSOR_ROTATION_INVERTED 1 +- +-#define CIO2_SENSOR_CONFIG(_HID, _NR, ...) \ +- (const struct cio2_sensor_config) { \ +- .hid = _HID, \ +- .nr_link_freqs = _NR, \ +- .link_freqs = { __VA_ARGS__ } \ +- } +- +-#define NODE_SENSOR(_HID, _PROPS) \ +- (const struct software_node) { \ +- .name = _HID, \ +- .properties = _PROPS, \ +- } +- +-#define NODE_PORT(_PORT, _SENSOR_NODE) \ +- (const struct software_node) { \ +- .name = _PORT, \ +- .parent = _SENSOR_NODE, \ +- } +- +-#define NODE_ENDPOINT(_EP, _PORT, _PROPS) \ +- (const struct software_node) { \ +- .name = _EP, \ +- .parent = _PORT, \ +- .properties = _PROPS, \ +- } +- +-#define NODE_VCM(_TYPE) \ +- (const struct software_node) { \ +- .name = _TYPE, \ +- } +- +-enum cio2_sensor_swnodes { +- SWNODE_SENSOR_HID, +- SWNODE_SENSOR_PORT, +- SWNODE_SENSOR_ENDPOINT, +- SWNODE_CIO2_PORT, +- SWNODE_CIO2_ENDPOINT, +- /* Must be last because it is optional / maybe empty */ +- SWNODE_VCM, +- SWNODE_COUNT +-}; +- +-/* Data representation as it is in ACPI SSDB buffer */ +-struct cio2_sensor_ssdb { +- u8 version; +- u8 sku; +- u8 guid_csi2[16]; +- u8 devfunction; +- u8 bus; +- u32 dphylinkenfuses; +- u32 clockdiv; +- u8 link; +- u8 lanes; +- u32 csiparams[10]; +- u32 maxlanespeed; +- u8 sensorcalibfileidx; +- u8 sensorcalibfileidxInMBZ[3]; +- u8 romtype; +- u8 vcmtype; +- u8 platforminfo; +- u8 platformsubinfo; +- u8 flash; +- u8 privacyled; +- u8 degree; +- u8 mipilinkdefined; +- u32 mclkspeed; +- u8 controllogicid; +- u8 reserved1[3]; +- u8 mclkport; +- u8 reserved2[13]; +-} __packed; +- +-struct cio2_property_names { +- char clock_frequency[16]; +- char rotation[9]; +- char orientation[12]; +- char bus_type[9]; +- char data_lanes[11]; +- char remote_endpoint[16]; +- char link_frequencies[17]; +-}; +- +-struct cio2_node_names { +- char port[7]; +- char endpoint[11]; +- char remote_port[7]; +-}; +- +-struct cio2_sensor_config { +- const char *hid; +- const u8 nr_link_freqs; +- const u64 link_freqs[MAX_NUM_LINK_FREQS]; +-}; +- +-struct cio2_sensor { +- /* append ssdb.link(u8) in "-%u" format as suffix of HID */ +- char name[ACPI_ID_LEN + 4]; +- struct acpi_device *adev; +- struct i2c_client *vcm_i2c_client; +- +- /* SWNODE_COUNT + 1 for terminating NULL */ +- const struct software_node *group[SWNODE_COUNT + 1]; +- struct software_node swnodes[SWNODE_COUNT]; +- struct cio2_node_names node_names; +- +- struct cio2_sensor_ssdb ssdb; +- struct acpi_pld_info *pld; +- +- struct cio2_property_names prop_names; +- struct property_entry ep_properties[5]; +- struct property_entry dev_properties[5]; +- struct property_entry cio2_properties[3]; +- struct software_node_ref_args local_ref[1]; +- struct software_node_ref_args remote_ref[1]; +- struct software_node_ref_args vcm_ref[1]; +-}; +- +-struct cio2_bridge { +- char cio2_node_name[ACPI_ID_LEN]; +- struct software_node cio2_hid_node; +- u32 data_lanes[4]; +- unsigned int n_sensors; +- struct cio2_sensor sensors[CIO2_NUM_PORTS]; +-}; +- +-#endif +diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +index 3c84cb1216320..03a7ab4d2e693 100644 +--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c ++++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +@@ -29,6 +29,7 @@ + #include <media/v4l2-ioctl.h> + #include <media/videobuf2-dma-sg.h> + ++#include "../ipu-bridge.h" + #include "ipu3-cio2.h" + + struct ipu3_cio2_fmt { +@@ -1727,7 +1728,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, + return -EINVAL; + } + +- r = cio2_bridge_init(pci_dev); ++ r = ipu_bridge_init(pci_dev); + if (r) + return r; + } +@@ -2060,3 +2061,4 @@ MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>"); + MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); + MODULE_LICENSE("GPL v2"); + MODULE_DESCRIPTION("IPU3 CIO2 driver"); ++MODULE_IMPORT_NS(INTEL_IPU_BRIDGE); +diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h +index 3a1f394e05aa7..d731ce8adbe31 100644 +--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h ++++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h +@@ -459,10 +459,4 @@ static inline struct cio2_queue *vb2q_to_cio2_queue(struct vb2_queue *vq) + return container_of(vq, struct cio2_queue, vbq); + } + +-#if IS_ENABLED(CONFIG_CIO2_BRIDGE) +-int cio2_bridge_init(struct pci_dev *cio2); +-#else +-static inline int cio2_bridge_init(struct pci_dev *cio2) { return 0; } +-#endif +- + #endif +diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c +index 6515f3cdb7a74..133d77d1ea0c3 100644 +--- a/drivers/media/platform/amphion/vdec.c ++++ b/drivers/media/platform/amphion/vdec.c +@@ -299,7 +299,8 @@ static int vdec_update_state(struct vpu_inst *inst, enum vpu_codec_state state, + vdec->state = VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE; + + if (inst->state != pre_state) +- vpu_trace(inst->dev, "[%d] %d -> %d\n", inst->id, pre_state, inst->state); ++ vpu_trace(inst->dev, "[%d] %s -> %s\n", inst->id, ++ vpu_codec_state_name(pre_state), vpu_codec_state_name(inst->state)); + + if (inst->state == VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) + vdec_handle_resolution_change(inst); +@@ -741,6 +742,21 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) + dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id); + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED); + vdec->decoded_frame_count++; ++ if (vdec->params.display_delay_enable) { ++ struct vpu_format *cur_fmt; ++ ++ cur_fmt = vpu_get_format(inst, inst->cap_format.type); ++ vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); ++ for (int i = 0; i < vbuf->vb2_buf.num_planes; i++) ++ vb2_set_plane_payload(&vbuf->vb2_buf, ++ i, vpu_get_fmt_plane_size(cur_fmt, i)); ++ vbuf->field = cur_fmt->field; ++ vbuf->sequence = vdec->sequence++; ++ dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); ++ ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); ++ vdec->display_frame_count++; ++ } + exit: + vpu_inst_unlock(inst); + +@@ -768,14 +784,14 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) + struct vpu_format *cur_fmt; + struct vpu_vb2_buffer *vpu_buf; + struct vb2_v4l2_buffer *vbuf; +- u32 sequence; + int i; + + if (!frame) + return; + + vpu_inst_lock(inst); +- sequence = vdec->sequence++; ++ if (!vdec->params.display_delay_enable) ++ vdec->sequence++; + vpu_buf = vdec_find_buffer(inst, frame->luma); + vpu_inst_unlock(inst); + if (!vpu_buf) { +@@ -794,13 +810,17 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) + dev_err(inst->dev, "[%d] buffer id(%d, %d) dismatch\n", + inst->id, vbuf->vb2_buf.index, frame->id); + ++ if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_READY && vdec->params.display_delay_enable) ++ return; ++ + if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED) + dev_err(inst->dev, "[%d] buffer(%d) ready without decoded\n", inst->id, frame->id); ++ + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); + for (i = 0; i < vbuf->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&vbuf->vb2_buf, i, vpu_get_fmt_plane_size(cur_fmt, i)); + vbuf->field = cur_fmt->field; +- vbuf->sequence = sequence; ++ vbuf->sequence = vdec->sequence; + dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); + + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); +@@ -999,6 +1019,7 @@ static int vdec_response_frame_abnormal(struct vpu_inst *inst) + { + struct vdec_t *vdec = inst->priv; + struct vpu_fs_info info; ++ int ret; + + if (!vdec->req_frame_count) + return 0; +@@ -1006,7 +1027,9 @@ static int vdec_response_frame_abnormal(struct vpu_inst *inst) + memset(&info, 0, sizeof(info)); + info.type = MEM_RES_FRAME; + info.tag = vdec->seq_tag + 0xf0; +- vpu_session_alloc_fs(inst, &info); ++ ret = vpu_session_alloc_fs(inst, &info); ++ if (ret) ++ return ret; + vdec->req_frame_count--; + + return 0; +@@ -1037,8 +1060,8 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb + return -EINVAL; + } + +- dev_dbg(inst->dev, "[%d] state = %d, alloc fs %d, tag = 0x%x\n", +- inst->id, inst->state, vbuf->vb2_buf.index, vdec->seq_tag); ++ dev_dbg(inst->dev, "[%d] state = %s, alloc fs %d, tag = 0x%x\n", ++ inst->id, vpu_codec_state_name(inst->state), vbuf->vb2_buf.index, vdec->seq_tag); + vpu_buf = to_vpu_vb2_buffer(vbuf); + + memset(&info, 0, sizeof(info)); +@@ -1400,7 +1423,7 @@ static void vdec_abort(struct vpu_inst *inst) + struct vpu_rpc_buffer_desc desc; + int ret; + +- vpu_trace(inst->dev, "[%d] state = %d\n", inst->id, inst->state); ++ vpu_trace(inst->dev, "[%d] state = %s\n", inst->id, vpu_codec_state_name(inst->state)); + + vdec->aborting = true; + vpu_iface_add_scode(inst, SCODE_PADDING_ABORT); +@@ -1453,9 +1476,7 @@ static void vdec_release(struct vpu_inst *inst) + { + if (inst->id != VPU_INST_NULL_ID) + vpu_trace(inst->dev, "[%d]\n", inst->id); +- vpu_inst_lock(inst); + vdec_stop(inst, true); +- vpu_inst_unlock(inst); + } + + static void vdec_cleanup(struct vpu_inst *inst) +diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c +index 58480e2755ec4..4eb57d793a9c0 100644 +--- a/drivers/media/platform/amphion/venc.c ++++ b/drivers/media/platform/amphion/venc.c +@@ -268,7 +268,7 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm + { + struct vpu_inst *inst = to_inst(file); + struct venc_t *venc = inst->priv; +- struct v4l2_fract *timeperframe = &parm->parm.capture.timeperframe; ++ struct v4l2_fract *timeperframe; + + if (!parm) + return -EINVAL; +@@ -279,6 +279,7 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm + if (!vpu_helper_check_type(inst, parm->type)) + return -EINVAL; + ++ timeperframe = &parm->parm.capture.timeperframe; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.readbuffers = 0; + timeperframe->numerator = venc->params.frame_rate.numerator; +@@ -291,7 +292,7 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm + { + struct vpu_inst *inst = to_inst(file); + struct venc_t *venc = inst->priv; +- struct v4l2_fract *timeperframe = &parm->parm.capture.timeperframe; ++ struct v4l2_fract *timeperframe; + unsigned long n, d; + + if (!parm) +@@ -303,6 +304,7 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm + if (!vpu_helper_check_type(inst, parm->type)) + return -EINVAL; + ++ timeperframe = &parm->parm.capture.timeperframe; + if (!timeperframe->numerator) + timeperframe->numerator = venc->params.frame_rate.numerator; + if (!timeperframe->denominator) +diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h +index 3bfe193722af4..5a701f64289ef 100644 +--- a/drivers/media/platform/amphion/vpu.h ++++ b/drivers/media/platform/amphion/vpu.h +@@ -355,6 +355,9 @@ void vpu_inst_record_flow(struct vpu_inst *inst, u32 flow); + int vpu_core_driver_init(void); + void vpu_core_driver_exit(void); + ++const char *vpu_id_name(u32 id); ++const char *vpu_codec_state_name(enum vpu_codec_state state); ++ + extern bool debug; + #define vpu_trace(dev, fmt, arg...) \ + do { \ +diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c +index fa581ba6bab2d..235b71398d403 100644 +--- a/drivers/media/platform/amphion/vpu_cmds.c ++++ b/drivers/media/platform/amphion/vpu_cmds.c +@@ -98,7 +98,7 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data + cmd->id = id; + ret = vpu_iface_pack_cmd(inst->core, cmd->pkt, inst->id, id, data); + if (ret) { +- dev_err(inst->dev, "iface pack cmd(%d) fail\n", id); ++ dev_err(inst->dev, "iface pack cmd %s fail\n", vpu_id_name(id)); + vfree(cmd->pkt); + vfree(cmd); + return NULL; +@@ -125,14 +125,14 @@ static int vpu_session_process_cmd(struct vpu_inst *inst, struct vpu_cmd_t *cmd) + { + int ret; + +- dev_dbg(inst->dev, "[%d]send cmd(0x%x)\n", inst->id, cmd->id); ++ dev_dbg(inst->dev, "[%d]send cmd %s\n", inst->id, vpu_id_name(cmd->id)); + vpu_iface_pre_send_cmd(inst); + ret = vpu_cmd_send(inst->core, cmd->pkt); + if (!ret) { + vpu_iface_post_send_cmd(inst); + vpu_inst_record_flow(inst, cmd->id); + } else { +- dev_err(inst->dev, "[%d] iface send cmd(0x%x) fail\n", inst->id, cmd->id); ++ dev_err(inst->dev, "[%d] iface send cmd %s fail\n", inst->id, vpu_id_name(cmd->id)); + } + + return ret; +@@ -149,7 +149,8 @@ static void vpu_process_cmd_request(struct vpu_inst *inst) + list_for_each_entry_safe(cmd, tmp, &inst->cmd_q, list) { + list_del_init(&cmd->list); + if (vpu_session_process_cmd(inst, cmd)) +- dev_err(inst->dev, "[%d] process cmd(%d) fail\n", inst->id, cmd->id); ++ dev_err(inst->dev, "[%d] process cmd %s fail\n", ++ inst->id, vpu_id_name(cmd->id)); + if (cmd->request) { + inst->pending = (void *)cmd; + break; +@@ -305,7 +306,8 @@ static void vpu_core_keep_active(struct vpu_core *core) + + dev_dbg(core->dev, "try to wake up\n"); + mutex_lock(&core->cmd_lock); +- vpu_cmd_send(core, &pkt); ++ if (vpu_cmd_send(core, &pkt)) ++ dev_err(core->dev, "fail to keep active\n"); + mutex_unlock(&core->cmd_lock); + } + +@@ -313,7 +315,7 @@ static int vpu_session_send_cmd(struct vpu_inst *inst, u32 id, void *data) + { + unsigned long key; + int sync = false; +- int ret = -EINVAL; ++ int ret; + + if (inst->id < 0) + return -EINVAL; +@@ -339,7 +341,7 @@ static int vpu_session_send_cmd(struct vpu_inst *inst, u32 id, void *data) + + exit: + if (ret) +- dev_err(inst->dev, "[%d] send cmd(0x%x) fail\n", inst->id, id); ++ dev_err(inst->dev, "[%d] send cmd %s fail\n", inst->id, vpu_id_name(id)); + + return ret; + } +diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c +index 82bf8b3be66a2..bfdebf2449a5c 100644 +--- a/drivers/media/platform/amphion/vpu_core.c ++++ b/drivers/media/platform/amphion/vpu_core.c +@@ -88,6 +88,8 @@ static int vpu_core_boot_done(struct vpu_core *core) + + core->supported_instance_count = min(core->supported_instance_count, count); + } ++ if (core->supported_instance_count >= BITS_PER_TYPE(core->instance_mask)) ++ core->supported_instance_count = BITS_PER_TYPE(core->instance_mask); + core->fw_version = fw_version; + vpu_core_set_state(core, VPU_CORE_ACTIVE); + +diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c +index 44b830ae01d8c..982c2c777484c 100644 +--- a/drivers/media/platform/amphion/vpu_dbg.c ++++ b/drivers/media/platform/amphion/vpu_dbg.c +@@ -50,6 +50,13 @@ static char *vpu_stat_name[] = { + [VPU_BUF_STATE_ERROR] = "error", + }; + ++static inline const char *to_vpu_stat_name(int state) ++{ ++ if (state <= VPU_BUF_STATE_ERROR) ++ return vpu_stat_name[state]; ++ return "unknown"; ++} ++ + static int vpu_dbg_instance(struct seq_file *s, void *data) + { + struct vpu_inst *inst = s->private; +@@ -67,7 +74,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) + num = scnprintf(str, sizeof(str), "tgig = %d,pid = %d\n", inst->tgid, inst->pid); + if (seq_write(s, str, num)) + return 0; +- num = scnprintf(str, sizeof(str), "state = %d\n", inst->state); ++ num = scnprintf(str, sizeof(str), "state = %s\n", vpu_codec_state_name(inst->state)); + if (seq_write(s, str, num)) + return 0; + num = scnprintf(str, sizeof(str), +@@ -141,7 +148,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) + num = scnprintf(str, sizeof(str), + "output [%2d] state = %10s, %8s\n", + i, vb2_stat_name[vb->state], +- vpu_stat_name[vpu_get_buffer_state(vbuf)]); ++ to_vpu_stat_name(vpu_get_buffer_state(vbuf))); + if (seq_write(s, str, num)) + return 0; + } +@@ -156,7 +163,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) + num = scnprintf(str, sizeof(str), + "capture[%2d] state = %10s, %8s\n", + i, vb2_stat_name[vb->state], +- vpu_stat_name[vpu_get_buffer_state(vbuf)]); ++ to_vpu_stat_name(vpu_get_buffer_state(vbuf))); + if (seq_write(s, str, num)) + return 0; + } +@@ -188,9 +195,9 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) + + if (!inst->flows[idx]) + continue; +- num = scnprintf(str, sizeof(str), "\t[%s]0x%x\n", ++ num = scnprintf(str, sizeof(str), "\t[%s] %s\n", + inst->flows[idx] >= VPU_MSG_ID_NOOP ? "M" : "C", +- inst->flows[idx]); ++ vpu_id_name(inst->flows[idx])); + if (seq_write(s, str, num)) { + mutex_unlock(&inst->core->cmd_lock); + return 0; +diff --git a/drivers/media/platform/amphion/vpu_helpers.c b/drivers/media/platform/amphion/vpu_helpers.c +index 019c77e84514c..af3b336e5dc32 100644 +--- a/drivers/media/platform/amphion/vpu_helpers.c ++++ b/drivers/media/platform/amphion/vpu_helpers.c +@@ -11,6 +11,7 @@ + #include <linux/module.h> + #include <linux/platform_device.h> + #include "vpu.h" ++#include "vpu_defs.h" + #include "vpu_core.h" + #include "vpu_rpc.h" + #include "vpu_helpers.h" +@@ -447,3 +448,63 @@ int vpu_find_src_by_dst(struct vpu_pair *pairs, u32 cnt, u32 dst) + + return -EINVAL; + } ++ ++const char *vpu_id_name(u32 id) ++{ ++ switch (id) { ++ case VPU_CMD_ID_NOOP: return "noop"; ++ case VPU_CMD_ID_CONFIGURE_CODEC: return "configure codec"; ++ case VPU_CMD_ID_START: return "start"; ++ case VPU_CMD_ID_STOP: return "stop"; ++ case VPU_CMD_ID_ABORT: return "abort"; ++ case VPU_CMD_ID_RST_BUF: return "reset buf"; ++ case VPU_CMD_ID_SNAPSHOT: return "snapshot"; ++ case VPU_CMD_ID_FIRM_RESET: return "reset firmware"; ++ case VPU_CMD_ID_UPDATE_PARAMETER: return "update parameter"; ++ case VPU_CMD_ID_FRAME_ENCODE: return "encode frame"; ++ case VPU_CMD_ID_SKIP: return "skip"; ++ case VPU_CMD_ID_FS_ALLOC: return "alloc fb"; ++ case VPU_CMD_ID_FS_RELEASE: return "release fb"; ++ case VPU_CMD_ID_TIMESTAMP: return "timestamp"; ++ case VPU_CMD_ID_DEBUG: return "debug"; ++ case VPU_MSG_ID_RESET_DONE: return "reset done"; ++ case VPU_MSG_ID_START_DONE: return "start done"; ++ case VPU_MSG_ID_STOP_DONE: return "stop done"; ++ case VPU_MSG_ID_ABORT_DONE: return "abort done"; ++ case VPU_MSG_ID_BUF_RST: return "buf reset done"; ++ case VPU_MSG_ID_MEM_REQUEST: return "mem request"; ++ case VPU_MSG_ID_PARAM_UPD_DONE: return "param upd done"; ++ case VPU_MSG_ID_FRAME_INPUT_DONE: return "frame input done"; ++ case VPU_MSG_ID_ENC_DONE: return "encode done"; ++ case VPU_MSG_ID_DEC_DONE: return "frame display"; ++ case VPU_MSG_ID_FRAME_REQ: return "fb request"; ++ case VPU_MSG_ID_FRAME_RELEASE: return "fb release"; ++ case VPU_MSG_ID_SEQ_HDR_FOUND: return "seq hdr found"; ++ case VPU_MSG_ID_RES_CHANGE: return "resolution change"; ++ case VPU_MSG_ID_PIC_HDR_FOUND: return "pic hdr found"; ++ case VPU_MSG_ID_PIC_DECODED: return "picture decoded"; ++ case VPU_MSG_ID_PIC_EOS: return "eos"; ++ case VPU_MSG_ID_FIFO_LOW: return "fifo low"; ++ case VPU_MSG_ID_BS_ERROR: return "bs error"; ++ case VPU_MSG_ID_UNSUPPORTED: return "unsupported"; ++ case VPU_MSG_ID_FIRMWARE_XCPT: return "exception"; ++ case VPU_MSG_ID_PIC_SKIPPED: return "skipped"; ++ } ++ return "<unknown>"; ++} ++ ++const char *vpu_codec_state_name(enum vpu_codec_state state) ++{ ++ switch (state) { ++ case VPU_CODEC_STATE_DEINIT: return "initialization"; ++ case VPU_CODEC_STATE_CONFIGURED: return "configured"; ++ case VPU_CODEC_STATE_START: return "start"; ++ case VPU_CODEC_STATE_STARTED: return "started"; ++ case VPU_CODEC_STATE_ACTIVE: return "active"; ++ case VPU_CODEC_STATE_SEEK: return "seek"; ++ case VPU_CODEC_STATE_STOP: return "stop"; ++ case VPU_CODEC_STATE_DRAIN: return "drain"; ++ case VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE: return "resolution change"; ++ } ++ return "<unknown>"; ++} +diff --git a/drivers/media/platform/amphion/vpu_mbox.c b/drivers/media/platform/amphion/vpu_mbox.c +index bf759eb2fd46d..b6d5b4844f672 100644 +--- a/drivers/media/platform/amphion/vpu_mbox.c ++++ b/drivers/media/platform/amphion/vpu_mbox.c +@@ -46,11 +46,10 @@ static int vpu_mbox_request_channel(struct device *dev, struct vpu_mbox *mbox) + cl->rx_callback = vpu_mbox_rx_callback; + + ch = mbox_request_channel_byname(cl, mbox->name); +- if (IS_ERR(ch)) { +- dev_err(dev, "Failed to request mbox chan %s, ret : %ld\n", +- mbox->name, PTR_ERR(ch)); +- return PTR_ERR(ch); +- } ++ if (IS_ERR(ch)) ++ return dev_err_probe(dev, PTR_ERR(ch), ++ "Failed to request mbox chan %s\n", ++ mbox->name); + + mbox->ch = ch; + return 0; +diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c +index 92672a802b492..d0ead051f7d18 100644 +--- a/drivers/media/platform/amphion/vpu_msgs.c ++++ b/drivers/media/platform/amphion/vpu_msgs.c +@@ -32,7 +32,7 @@ static void vpu_session_handle_start_done(struct vpu_inst *inst, struct vpu_rpc_ + + static void vpu_session_handle_mem_request(struct vpu_inst *inst, struct vpu_rpc_event *pkt) + { +- struct vpu_pkt_mem_req_data req_data; ++ struct vpu_pkt_mem_req_data req_data = { 0 }; + + vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&req_data); + vpu_trace(inst->dev, "[%d] %d:%d %d:%d %d:%d\n", +@@ -80,7 +80,7 @@ static void vpu_session_handle_resolution_change(struct vpu_inst *inst, struct v + + static void vpu_session_handle_enc_frame_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt) + { +- struct vpu_enc_pic_info info; ++ struct vpu_enc_pic_info info = { 0 }; + + vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info); + dev_dbg(inst->dev, "[%d] frame id = %d, wptr = 0x%x, size = %d\n", +@@ -90,7 +90,7 @@ static void vpu_session_handle_enc_frame_done(struct vpu_inst *inst, struct vpu_ + + static void vpu_session_handle_frame_request(struct vpu_inst *inst, struct vpu_rpc_event *pkt) + { +- struct vpu_fs_info fs; ++ struct vpu_fs_info fs = { 0 }; + + vpu_iface_unpack_msg_data(inst->core, pkt, &fs); + call_void_vop(inst, event_notify, VPU_MSG_ID_FRAME_REQ, &fs); +@@ -107,7 +107,7 @@ static void vpu_session_handle_frame_release(struct vpu_inst *inst, struct vpu_r + info.type = inst->out_format.type; + call_void_vop(inst, buf_done, &info); + } else if (inst->core->type == VPU_CORE_TYPE_DEC) { +- struct vpu_fs_info fs; ++ struct vpu_fs_info fs = { 0 }; + + vpu_iface_unpack_msg_data(inst->core, pkt, &fs); + call_void_vop(inst, event_notify, VPU_MSG_ID_FRAME_RELEASE, &fs); +@@ -122,7 +122,7 @@ static void vpu_session_handle_input_done(struct vpu_inst *inst, struct vpu_rpc_ + + static void vpu_session_handle_pic_decoded(struct vpu_inst *inst, struct vpu_rpc_event *pkt) + { +- struct vpu_dec_pic_info info; ++ struct vpu_dec_pic_info info = { 0 }; + + vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info); + call_void_vop(inst, get_one_frame, &info); +@@ -130,7 +130,7 @@ static void vpu_session_handle_pic_decoded(struct vpu_inst *inst, struct vpu_rpc + + static void vpu_session_handle_pic_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt) + { +- struct vpu_dec_pic_info info; ++ struct vpu_dec_pic_info info = { 0 }; + struct vpu_frame_info frame; + + memset(&frame, 0, sizeof(frame)); +@@ -210,7 +210,7 @@ static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *m + return -EINVAL; + + msg_id = ret; +- dev_dbg(inst->dev, "[%d] receive event(0x%x)\n", inst->id, msg_id); ++ dev_dbg(inst->dev, "[%d] receive event(%s)\n", inst->id, vpu_id_name(msg_id)); + + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + if (handlers[i].id == msg_id) { +diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c +index 810e93d2c954a..8c9028df3bf42 100644 +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -489,6 +489,11 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq, + for (i = 0; i < cur_fmt->mem_planes; i++) + psize[i] = vpu_get_fmt_plane_size(cur_fmt, i); + ++ if (V4L2_TYPE_IS_OUTPUT(vq->type) && inst->state == VPU_CODEC_STATE_SEEK) { ++ vpu_trace(inst->dev, "reinit when VIDIOC_REQBUFS(OUTPUT, 0)\n"); ++ call_void_vop(inst, release); ++ } ++ + return 0; + } + +@@ -773,9 +778,9 @@ int vpu_v4l2_close(struct file *file) + v4l2_m2m_ctx_release(inst->fh.m2m_ctx); + inst->fh.m2m_ctx = NULL; + } ++ call_void_vop(inst, release); + vpu_inst_unlock(inst); + +- call_void_vop(inst, release); + vpu_inst_unregister(inst); + vpu_inst_put(inst); + +diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +index 60425c99a2b8b..7194f88edc0fb 100644 +--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c ++++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +@@ -1403,6 +1403,7 @@ static void mtk_jpeg_remove(struct platform_device *pdev) + { + struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev); + ++ cancel_delayed_work_sync(&jpeg->job_timeout_work); + pm_runtime_disable(&pdev->dev); + video_unregister_device(jpeg->vdev); + v4l2_m2m_release(jpeg->m2m_dev); +diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_if.c +index 70b8383f7c8ec..a27a109d8d144 100644 +--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_if.c ++++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_if.c +@@ -226,10 +226,11 @@ static struct vdec_fb *vp9_rm_from_fb_use_list(struct vdec_vp9_inst + if (fb->base_y.va == addr) { + list_move_tail(&node->list, + &inst->available_fb_node_list); +- break; ++ return fb; + } + } +- return fb; ++ ++ return NULL; + } + + static void vp9_add_to_fb_free_list(struct vdec_vp9_inst *inst, +diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c +index 03f8d7cd8eddc..a81212c0ade9d 100644 +--- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c ++++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c +@@ -246,6 +246,7 @@ void vdec_msg_queue_deinit(struct vdec_msg_queue *msg_queue, + mtk_vcodec_mem_free(ctx, mem); + + kfree(lat_buf->private_data); ++ lat_buf->private_data = NULL; + } + } + +@@ -312,6 +313,7 @@ int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue, + err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr); + if (err) { + mtk_v4l2_err("failed to allocate wdma_addr buf"); ++ msg_queue->wdma_addr.size = 0; + return -ENOMEM; + } + msg_queue->wdma_rptr_addr = msg_queue->wdma_addr.dma_addr; +diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +index ed15ea348f97b..a2b4fb9e29e7d 100644 +--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h ++++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +@@ -58,7 +58,6 @@ + #define CAST_OFBSIZE_LO CAST_STATUS18 + #define CAST_OFBSIZE_HI CAST_STATUS19 + +-#define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/ + /* JPEG-Decoder Wrapper Slot Registers 0..3 */ + #define SLOT_BASE 0x10000 + #define SLOT_STATUS 0x0 +diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +index c0e49be42450a..9512c0a619667 100644 +--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c ++++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +@@ -745,87 +745,77 @@ static void notify_src_chg(struct mxc_jpeg_ctx *ctx) + v4l2_event_queue_fh(&ctx->fh, &ev); + } + +-static int mxc_get_free_slot(struct mxc_jpeg_slot_data slot_data[], int n) ++static int mxc_get_free_slot(struct mxc_jpeg_slot_data *slot_data) + { +- int free_slot = 0; +- +- while (slot_data[free_slot].used && free_slot < n) +- free_slot++; +- +- return free_slot; /* >=n when there are no more free slots */ ++ if (!slot_data->used) ++ return slot_data->slot; ++ return -1; + } + +-static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg, +- unsigned int slot) ++static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg) + { + struct mxc_jpeg_desc *desc; + struct mxc_jpeg_desc *cfg_desc; + void *cfg_stm; + +- if (jpeg->slot_data[slot].desc) ++ if (jpeg->slot_data.desc) + goto skip_alloc; /* already allocated, reuse it */ + + /* allocate descriptor for decoding/encoding phase */ + desc = dma_alloc_coherent(jpeg->dev, + sizeof(struct mxc_jpeg_desc), +- &jpeg->slot_data[slot].desc_handle, ++ &jpeg->slot_data.desc_handle, + GFP_ATOMIC); + if (!desc) + goto err; +- jpeg->slot_data[slot].desc = desc; ++ jpeg->slot_data.desc = desc; + + /* allocate descriptor for configuration phase (encoder only) */ + cfg_desc = dma_alloc_coherent(jpeg->dev, + sizeof(struct mxc_jpeg_desc), +- &jpeg->slot_data[slot].cfg_desc_handle, ++ &jpeg->slot_data.cfg_desc_handle, + GFP_ATOMIC); + if (!cfg_desc) + goto err; +- jpeg->slot_data[slot].cfg_desc = cfg_desc; ++ jpeg->slot_data.cfg_desc = cfg_desc; + + /* allocate configuration stream */ + cfg_stm = dma_alloc_coherent(jpeg->dev, + MXC_JPEG_MAX_CFG_STREAM, +- &jpeg->slot_data[slot].cfg_stream_handle, ++ &jpeg->slot_data.cfg_stream_handle, + GFP_ATOMIC); + if (!cfg_stm) + goto err; +- jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm; ++ jpeg->slot_data.cfg_stream_vaddr = cfg_stm; + + skip_alloc: +- jpeg->slot_data[slot].used = true; ++ jpeg->slot_data.used = true; + + return true; + err: +- dev_err(jpeg->dev, "Could not allocate descriptors for slot %d", slot); ++ dev_err(jpeg->dev, "Could not allocate descriptors for slot %d", jpeg->slot_data.slot); + + return false; + } + +-static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg, +- unsigned int slot) ++static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg) + { +- if (slot >= MXC_MAX_SLOTS) { +- dev_err(jpeg->dev, "Invalid slot %d, nothing to free.", slot); +- return; +- } +- + /* free descriptor for decoding/encoding phase */ + dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), +- jpeg->slot_data[slot].desc, +- jpeg->slot_data[slot].desc_handle); ++ jpeg->slot_data.desc, ++ jpeg->slot_data.desc_handle); + + /* free descriptor for encoder configuration phase / decoder DHT */ + dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), +- jpeg->slot_data[slot].cfg_desc, +- jpeg->slot_data[slot].cfg_desc_handle); ++ jpeg->slot_data.cfg_desc, ++ jpeg->slot_data.cfg_desc_handle); + + /* free configuration stream */ + dma_free_coherent(jpeg->dev, MXC_JPEG_MAX_CFG_STREAM, +- jpeg->slot_data[slot].cfg_stream_vaddr, +- jpeg->slot_data[slot].cfg_stream_handle); ++ jpeg->slot_data.cfg_stream_vaddr, ++ jpeg->slot_data.cfg_stream_handle); + +- jpeg->slot_data[slot].used = false; ++ jpeg->slot_data.used = false; + } + + static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx, +@@ -855,7 +845,7 @@ static void mxc_jpeg_job_finish(struct mxc_jpeg_ctx *ctx, enum vb2_buffer_state + v4l2_m2m_buf_done(dst_buf, state); + + mxc_jpeg_disable_irq(reg, ctx->slot); +- ctx->mxc_jpeg->slot_data[ctx->slot].used = false; ++ jpeg->slot_data.used = false; + if (reset) + mxc_jpeg_sw_reset(reg); + } +@@ -919,7 +909,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) + goto job_unlock; + } + +- if (!jpeg->slot_data[slot].used) ++ if (!jpeg->slot_data.used) + goto job_unlock; + + dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); +@@ -1179,13 +1169,13 @@ static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf, + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + void __iomem *reg = jpeg->base_reg; + unsigned int slot = ctx->slot; +- struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc; +- struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc; +- dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle; +- dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle; +- dma_addr_t cfg_stream_handle = jpeg->slot_data[slot].cfg_stream_handle; +- unsigned int *cfg_size = &jpeg->slot_data[slot].cfg_stream_size; +- void *cfg_stream_vaddr = jpeg->slot_data[slot].cfg_stream_vaddr; ++ struct mxc_jpeg_desc *desc = jpeg->slot_data.desc; ++ struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data.cfg_desc; ++ dma_addr_t desc_handle = jpeg->slot_data.desc_handle; ++ dma_addr_t cfg_desc_handle = jpeg->slot_data.cfg_desc_handle; ++ dma_addr_t cfg_stream_handle = jpeg->slot_data.cfg_stream_handle; ++ unsigned int *cfg_size = &jpeg->slot_data.cfg_stream_size; ++ void *cfg_stream_vaddr = jpeg->slot_data.cfg_stream_vaddr; + struct mxc_jpeg_src_buf *jpeg_src_buf; + + jpeg_src_buf = vb2_to_mxc_buf(src_buf); +@@ -1245,18 +1235,18 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + void __iomem *reg = jpeg->base_reg; + unsigned int slot = ctx->slot; +- struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc; +- struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc; +- dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle; +- dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle; +- void *cfg_stream_vaddr = jpeg->slot_data[slot].cfg_stream_vaddr; ++ struct mxc_jpeg_desc *desc = jpeg->slot_data.desc; ++ struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data.cfg_desc; ++ dma_addr_t desc_handle = jpeg->slot_data.desc_handle; ++ dma_addr_t cfg_desc_handle = jpeg->slot_data.cfg_desc_handle; ++ void *cfg_stream_vaddr = jpeg->slot_data.cfg_stream_vaddr; + struct mxc_jpeg_q_data *q_data; + enum mxc_jpeg_image_format img_fmt; + int w, h; + + q_data = mxc_jpeg_get_q_data(ctx, src_buf->vb2_queue->type); + +- jpeg->slot_data[slot].cfg_stream_size = ++ jpeg->slot_data.cfg_stream_size = + mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr, + q_data->fmt->fourcc, + q_data->crop.width, +@@ -1265,7 +1255,7 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, + /* chain the config descriptor with the encoding descriptor */ + cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN; + +- cfg_desc->buf_base0 = jpeg->slot_data[slot].cfg_stream_handle; ++ cfg_desc->buf_base0 = jpeg->slot_data.cfg_stream_handle; + cfg_desc->buf_base1 = 0; + cfg_desc->line_pitch = 0; + cfg_desc->stm_bufbase = 0; /* no output expected */ +@@ -1408,7 +1398,7 @@ static void mxc_jpeg_device_run_timeout(struct work_struct *work) + unsigned long flags; + + spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags); +- if (ctx->slot < MXC_MAX_SLOTS && ctx->mxc_jpeg->slot_data[ctx->slot].used) { ++ if (ctx->mxc_jpeg->slot_data.used) { + dev_warn(jpeg->dev, "%s timeout, cancel it\n", + ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? "decode" : "encode"); + mxc_jpeg_job_finish(ctx, VB2_BUF_STATE_ERROR, true); +@@ -1476,12 +1466,12 @@ static void mxc_jpeg_device_run(void *priv) + mxc_jpeg_enable(reg); + mxc_jpeg_set_l_endian(reg, 1); + +- ctx->slot = mxc_get_free_slot(jpeg->slot_data, MXC_MAX_SLOTS); +- if (ctx->slot >= MXC_MAX_SLOTS) { ++ ctx->slot = mxc_get_free_slot(&jpeg->slot_data); ++ if (ctx->slot < 0) { + dev_err(dev, "No more free slots\n"); + goto end; + } +- if (!mxc_jpeg_alloc_slot_data(jpeg, ctx->slot)) { ++ if (!mxc_jpeg_alloc_slot_data(jpeg)) { + dev_err(dev, "Cannot allocate slot data\n"); + goto end; + } +@@ -2101,7 +2091,7 @@ static int mxc_jpeg_open(struct file *file) + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + mxc_jpeg_set_default_params(ctx); +- ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */ ++ ctx->slot = -1; /* slot not allocated yet */ + INIT_DELAYED_WORK(&ctx->task_timer, mxc_jpeg_device_run_timeout); + + if (mxc_jpeg->mode == MXC_JPEG_DECODE) +@@ -2677,6 +2667,11 @@ static int mxc_jpeg_attach_pm_domains(struct mxc_jpeg_dev *jpeg) + dev_err(dev, "No power domains defined for jpeg node\n"); + return jpeg->num_domains; + } ++ if (jpeg->num_domains == 1) { ++ /* genpd_dev_pm_attach() attach automatically if power domains count is 1 */ ++ jpeg->num_domains = 0; ++ return 0; ++ } + + jpeg->pd_dev = devm_kmalloc_array(dev, jpeg->num_domains, + sizeof(*jpeg->pd_dev), GFP_KERNEL); +@@ -2718,7 +2713,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev) + int ret; + int mode; + const struct of_device_id *of_id; +- unsigned int slot; + + of_id = of_match_node(mxc_jpeg_match, dev->of_node); + if (!of_id) +@@ -2742,19 +2736,22 @@ static int mxc_jpeg_probe(struct platform_device *pdev) + if (IS_ERR(jpeg->base_reg)) + return PTR_ERR(jpeg->base_reg); + +- for (slot = 0; slot < MXC_MAX_SLOTS; slot++) { +- dec_irq = platform_get_irq(pdev, slot); +- if (dec_irq < 0) { +- ret = dec_irq; +- goto err_irq; +- } +- ret = devm_request_irq(&pdev->dev, dec_irq, mxc_jpeg_dec_irq, +- 0, pdev->name, jpeg); +- if (ret) { +- dev_err(&pdev->dev, "Failed to request irq %d (%d)\n", +- dec_irq, ret); +- goto err_irq; +- } ++ ret = of_property_read_u32_index(pdev->dev.of_node, "slot", 0, &jpeg->slot_data.slot); ++ if (ret) ++ jpeg->slot_data.slot = 0; ++ dev_info(&pdev->dev, "choose slot %d\n", jpeg->slot_data.slot); ++ dec_irq = platform_get_irq(pdev, 0); ++ if (dec_irq < 0) { ++ dev_err(&pdev->dev, "Failed to get irq %d\n", dec_irq); ++ ret = dec_irq; ++ goto err_irq; ++ } ++ ret = devm_request_irq(&pdev->dev, dec_irq, mxc_jpeg_dec_irq, ++ 0, pdev->name, jpeg); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to request irq %d (%d)\n", ++ dec_irq, ret); ++ goto err_irq; + } + + jpeg->pdev = pdev; +@@ -2914,11 +2911,9 @@ static const struct dev_pm_ops mxc_jpeg_pm_ops = { + + static void mxc_jpeg_remove(struct platform_device *pdev) + { +- unsigned int slot; + struct mxc_jpeg_dev *jpeg = platform_get_drvdata(pdev); + +- for (slot = 0; slot < MXC_MAX_SLOTS; slot++) +- mxc_jpeg_free_slot_data(jpeg, slot); ++ mxc_jpeg_free_slot_data(jpeg); + + pm_runtime_disable(&pdev->dev); + video_unregister_device(jpeg->dec_vdev); +diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +index 87157db780826..d80e94cc9d992 100644 +--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h ++++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +@@ -97,7 +97,7 @@ struct mxc_jpeg_ctx { + struct mxc_jpeg_q_data cap_q; + struct v4l2_fh fh; + enum mxc_jpeg_enc_state enc_state; +- unsigned int slot; ++ int slot; + unsigned int source_change; + bool header_parsed; + struct v4l2_ctrl_handler ctrl_handler; +@@ -106,6 +106,7 @@ struct mxc_jpeg_ctx { + }; + + struct mxc_jpeg_slot_data { ++ int slot; + bool used; + struct mxc_jpeg_desc *desc; // enc/dec descriptor + struct mxc_jpeg_desc *cfg_desc; // configuration descriptor +@@ -128,7 +129,7 @@ struct mxc_jpeg_dev { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *dec_vdev; +- struct mxc_jpeg_slot_data slot_data[MXC_MAX_SLOTS]; ++ struct mxc_jpeg_slot_data slot_data; + int num_domains; + struct device **pd_dev; + struct device_link **pd_link; +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +index b5ffde46f31b6..641c802adcc33 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +@@ -483,7 +483,7 @@ int mxc_isi_crossbar_init(struct mxc_isi_dev *isi) + + xbar->inputs = kcalloc(xbar->num_sinks, sizeof(*xbar->inputs), + GFP_KERNEL); +- if (!xbar->pads) { ++ if (!xbar->inputs) { + ret = -ENOMEM; + goto err_free; + } +diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c +index 2ad40b3945b0b..8fc8f46dc3908 100644 +--- a/drivers/media/platform/qcom/venus/hfi_venus.c ++++ b/drivers/media/platform/qcom/venus/hfi_venus.c +@@ -131,7 +131,6 @@ struct venus_hfi_device { + + static bool venus_pkt_debug; + int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL; +-static bool venus_sys_idle_indicator; + static bool venus_fw_low_power_mode = true; + static int venus_hw_rsp_timeout = 1000; + static bool venus_fw_coverage; +@@ -454,7 +453,6 @@ static int venus_boot_core(struct venus_hfi_device *hdev) + void __iomem *wrapper_base = hdev->core->wrapper_base; + int ret = 0; + +- writel(BIT(VIDC_CTRL_INIT_CTRL_SHIFT), cpu_cs_base + VIDC_CTRL_INIT); + if (IS_V6(hdev->core)) { + mask_val = readl(wrapper_base + WRAPPER_INTR_MASK); + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BASK_V6 | +@@ -465,6 +463,7 @@ static int venus_boot_core(struct venus_hfi_device *hdev) + writel(mask_val, wrapper_base + WRAPPER_INTR_MASK); + writel(1, cpu_cs_base + CPU_CS_SCIACMDARG3); + ++ writel(BIT(VIDC_CTRL_INIT_CTRL_SHIFT), cpu_cs_base + VIDC_CTRL_INIT); + while (!ctrl_status && count < max_tries) { + ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0); + if ((ctrl_status & CPU_CS_SCIACMDARG0_ERROR_STATUS_MASK) == 4) { +@@ -947,17 +946,12 @@ static int venus_sys_set_default_properties(struct venus_hfi_device *hdev) + if (ret) + dev_warn(dev, "setting fw debug msg ON failed (%d)\n", ret); + +- /* +- * Idle indicator is disabled by default on some 4xx firmware versions, +- * enable it explicitly in order to make suspend functional by checking +- * WFI (wait-for-interrupt) bit. +- */ +- if (IS_V4(hdev->core) || IS_V6(hdev->core)) +- venus_sys_idle_indicator = true; +- +- ret = venus_sys_set_idle_message(hdev, venus_sys_idle_indicator); +- if (ret) +- dev_warn(dev, "setting idle response ON failed (%d)\n", ret); ++ /* HFI_PROPERTY_SYS_IDLE_INDICATOR is not supported beyond 8916 (HFI V1) */ ++ if (IS_V1(hdev->core)) { ++ ret = venus_sys_set_idle_message(hdev, false); ++ if (ret) ++ dev_warn(dev, "setting idle response ON failed (%d)\n", ret); ++ } + + ret = venus_sys_set_power_control(hdev, venus_fw_low_power_mode); + if (ret) +diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c +index 61cfaaf4e927b..e56d58fe28022 100644 +--- a/drivers/media/platform/verisilicon/hantro_v4l2.c ++++ b/drivers/media/platform/verisilicon/hantro_v4l2.c +@@ -276,6 +276,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + enum v4l2_buf_type type) + { + const struct hantro_fmt *fmt; ++ const struct hantro_fmt *vpu_fmt; + bool capture = V4L2_TYPE_IS_CAPTURE(type); + bool coded; + +@@ -295,19 +296,23 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + + if (coded) { + pix_mp->num_planes = 1; +- } else if (!ctx->is_encoder) { ++ vpu_fmt = fmt; ++ } else if (ctx->is_encoder) { ++ vpu_fmt = hantro_find_format(ctx, ctx->dst_fmt.pixelformat); ++ } else { + /* + * Width/height on the CAPTURE end of a decoder are ignored and + * replaced by the OUTPUT ones. + */ + pix_mp->width = ctx->src_fmt.width; + pix_mp->height = ctx->src_fmt.height; ++ vpu_fmt = fmt; + } + + pix_mp->field = V4L2_FIELD_NONE; + + v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height, +- &fmt->frmsize); ++ &vpu_fmt->frmsize); + + if (!coded) { + /* Fill remaining fields */ +diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c +index eaa3bbc903d7e..3d3b54be29557 100644 +--- a/drivers/media/tuners/fc0011.c ++++ b/drivers/media/tuners/fc0011.c +@@ -499,7 +499,7 @@ struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(fc0011_attach); ++EXPORT_SYMBOL_GPL(fc0011_attach); + + MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); + MODULE_AUTHOR("Michael Buesch <m@bues.ch>"); +diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c +index 4429d5e8c5796..81e65acbdb170 100644 +--- a/drivers/media/tuners/fc0012.c ++++ b/drivers/media/tuners/fc0012.c +@@ -495,7 +495,7 @@ err: + + return fe; + } +-EXPORT_SYMBOL(fc0012_attach); ++EXPORT_SYMBOL_GPL(fc0012_attach); + + MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver"); + MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>"); +diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c +index 29dd9b55ff333..1006a2798eefc 100644 +--- a/drivers/media/tuners/fc0013.c ++++ b/drivers/media/tuners/fc0013.c +@@ -608,7 +608,7 @@ struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(fc0013_attach); ++EXPORT_SYMBOL_GPL(fc0013_attach); + + MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver"); + MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>"); +diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c +index 1c746bed51fee..1575ab94e1c8b 100644 +--- a/drivers/media/tuners/max2165.c ++++ b/drivers/media/tuners/max2165.c +@@ -410,7 +410,7 @@ struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(max2165_attach); ++EXPORT_SYMBOL_GPL(max2165_attach); + + MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); + MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); +diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c +index 0c9161516abdf..ed8bdf7ebd99d 100644 +--- a/drivers/media/tuners/mc44s803.c ++++ b/drivers/media/tuners/mc44s803.c +@@ -356,7 +356,7 @@ error: + kfree(priv); + return NULL; + } +-EXPORT_SYMBOL(mc44s803_attach); ++EXPORT_SYMBOL_GPL(mc44s803_attach); + + MODULE_AUTHOR("Jochen Friedrich"); + MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); +diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c +index e5d86874adb34..1a1635238b6ca 100644 +--- a/drivers/media/tuners/mt2060.c ++++ b/drivers/media/tuners/mt2060.c +@@ -440,7 +440,7 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter + + return fe; + } +-EXPORT_SYMBOL(mt2060_attach); ++EXPORT_SYMBOL_GPL(mt2060_attach); + + static int mt2060_probe(struct i2c_client *client) + { +diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c +index 37f50ff6c0bd2..eebc060883414 100644 +--- a/drivers/media/tuners/mt2131.c ++++ b/drivers/media/tuners/mt2131.c +@@ -274,7 +274,7 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + fe->tuner_priv = priv; + return fe; + } +-EXPORT_SYMBOL(mt2131_attach); ++EXPORT_SYMBOL_GPL(mt2131_attach); + + MODULE_AUTHOR("Steven Toth"); + MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +diff --git a/drivers/media/tuners/mt2266.c b/drivers/media/tuners/mt2266.c +index 6136f20fa9b7f..2e92885a6bcb9 100644 +--- a/drivers/media/tuners/mt2266.c ++++ b/drivers/media/tuners/mt2266.c +@@ -336,7 +336,7 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter + mt2266_calibrate(priv); + return fe; + } +-EXPORT_SYMBOL(mt2266_attach); ++EXPORT_SYMBOL_GPL(mt2266_attach); + + MODULE_AUTHOR("Olivier DANET"); + MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c +index 06dfab9fb8cbc..d9bfa257a0054 100644 +--- a/drivers/media/tuners/mxl5005s.c ++++ b/drivers/media/tuners/mxl5005s.c +@@ -4120,7 +4120,7 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + fe->tuner_priv = state; + return fe; + } +-EXPORT_SYMBOL(mxl5005s_attach); ++EXPORT_SYMBOL_GPL(mxl5005s_attach); + + MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); + MODULE_AUTHOR("Steven Toth"); +diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c +index 3853a3d43d4f2..60931367b82ca 100644 +--- a/drivers/media/tuners/qt1010.c ++++ b/drivers/media/tuners/qt1010.c +@@ -440,7 +440,7 @@ struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, + fe->tuner_priv = priv; + return fe; + } +-EXPORT_SYMBOL(qt1010_attach); ++EXPORT_SYMBOL_GPL(qt1010_attach); + + MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); + MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c +index 4ed94646116fa..7d8d84dcb2459 100644 +--- a/drivers/media/tuners/tda18218.c ++++ b/drivers/media/tuners/tda18218.c +@@ -336,7 +336,7 @@ struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, + + return fe; + } +-EXPORT_SYMBOL(tda18218_attach); ++EXPORT_SYMBOL_GPL(tda18218_attach); + + MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); + MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +diff --git a/drivers/media/tuners/xc2028.c b/drivers/media/tuners/xc2028.c +index 69c2e1b99bf17..5a967edceca93 100644 +--- a/drivers/media/tuners/xc2028.c ++++ b/drivers/media/tuners/xc2028.c +@@ -1512,7 +1512,7 @@ fail: + return NULL; + } + +-EXPORT_SYMBOL(xc2028_attach); ++EXPORT_SYMBOL_GPL(xc2028_attach); + + MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); + MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>"); +diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c +index d59b4ab774302..57ded9ff3f043 100644 +--- a/drivers/media/tuners/xc4000.c ++++ b/drivers/media/tuners/xc4000.c +@@ -1742,7 +1742,7 @@ fail2: + xc4000_release(fe); + return NULL; + } +-EXPORT_SYMBOL(xc4000_attach); ++EXPORT_SYMBOL_GPL(xc4000_attach); + + MODULE_AUTHOR("Steven Toth, Davide Ferri"); + MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); +diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c +index 7b7d9fe4f9453..2182e5b7b6064 100644 +--- a/drivers/media/tuners/xc5000.c ++++ b/drivers/media/tuners/xc5000.c +@@ -1460,7 +1460,7 @@ fail: + xc5000_release(fe); + return NULL; + } +-EXPORT_SYMBOL(xc5000_attach); ++EXPORT_SYMBOL_GPL(xc5000_attach); + + MODULE_AUTHOR("Steven Toth"); + MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); +diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c +index fea5bcf72a31a..c88a202daf5fc 100644 +--- a/drivers/media/usb/dvb-usb/m920x.c ++++ b/drivers/media/usb/dvb-usb/m920x.c +@@ -277,7 +277,6 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu + char *read = kmalloc(1, GFP_KERNEL); + if (!read) { + ret = -ENOMEM; +- kfree(read); + goto unlock; + } + +@@ -288,8 +287,10 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu + + if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, + 0x20 | stop, +- read, 1)) != 0) ++ read, 1)) != 0) { ++ kfree(read); + goto unlock; ++ } + msg[i].buf[j] = read[0]; + } + +diff --git a/drivers/media/usb/go7007/go7007-i2c.c b/drivers/media/usb/go7007/go7007-i2c.c +index 38339dd2f83f7..2880370e45c8b 100644 +--- a/drivers/media/usb/go7007/go7007-i2c.c ++++ b/drivers/media/usb/go7007/go7007-i2c.c +@@ -165,8 +165,6 @@ static int go7007_i2c_master_xfer(struct i2c_adapter *adapter, + } else if (msgs[i].len == 3) { + if (msgs[i].flags & I2C_M_RD) + return -EIO; +- if (msgs[i].len != 3) +- return -EIO; + if (go7007_i2c_xfer(go, msgs[i].addr, 0, + (msgs[i].buf[0] << 8) | msgs[i].buf[1], + 0x01, &msgs[i].buf[2]) < 0) +diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c +index 640737d3b8aeb..8a39cac76c585 100644 +--- a/drivers/media/usb/siano/smsusb.c ++++ b/drivers/media/usb/siano/smsusb.c +@@ -455,12 +455,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) + rc = smscore_register_device(¶ms, &dev->coredev, 0, mdev); + if (rc < 0) { + pr_err("smscore_register_device(...) failed, rc %d\n", rc); +- smsusb_term_device(intf); +-#ifdef CONFIG_MEDIA_CONTROLLER_DVB +- media_device_unregister(mdev); +-#endif +- kfree(mdev); +- return rc; ++ goto err_unregister_device; + } + + smscore_set_board_id(dev->coredev, board_id); +@@ -477,8 +472,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) + rc = smsusb_start_streaming(dev); + if (rc < 0) { + pr_err("smsusb_start_streaming(...) failed\n"); +- smsusb_term_device(intf); +- return rc; ++ goto err_unregister_device; + } + + dev->state = SMSUSB_ACTIVE; +@@ -486,13 +480,20 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) + rc = smscore_start_device(dev->coredev); + if (rc < 0) { + pr_err("smscore_start_device(...) failed\n"); +- smsusb_term_device(intf); +- return rc; ++ goto err_unregister_device; + } + + pr_debug("device 0x%p created\n", dev); + + return rc; ++ ++err_unregister_device: ++ smsusb_term_device(intf); ++#ifdef CONFIG_MEDIA_CONTROLLER_DVB ++ media_device_unregister(mdev); ++#endif ++ kfree(mdev); ++ return rc; + } + + static int smsusb_probe(struct usb_interface *intf, +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index 049c2f2001eaa..4fa9225aa3d93 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -568,19 +568,29 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, + link->local_id = fwep.id; + link->local_port = fwep.port; + link->local_node = fwnode_graph_get_port_parent(fwnode); ++ if (!link->local_node) ++ return -ENOLINK; + + fwnode = fwnode_graph_get_remote_endpoint(fwnode); +- if (!fwnode) { +- fwnode_handle_put(fwnode); +- return -ENOLINK; +- } ++ if (!fwnode) ++ goto err_put_local_node; + + fwnode_graph_parse_endpoint(fwnode, &fwep); + link->remote_id = fwep.id; + link->remote_port = fwep.port; + link->remote_node = fwnode_graph_get_port_parent(fwnode); ++ if (!link->remote_node) ++ goto err_put_remote_endpoint; + + return 0; ++ ++err_put_remote_endpoint: ++ fwnode_handle_put(fwnode); ++ ++err_put_local_node: ++ fwnode_handle_put(link->local_node); ++ ++ return -ENOLINK; + } + EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link); + +diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c +index 9666d28037e18..5a134fa8a174c 100644 +--- a/drivers/misc/fastrpc.c ++++ b/drivers/misc/fastrpc.c +@@ -1322,13 +1322,18 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, + return 0; + err_invoke: + if (fl->cctx->vmcount) { +- struct qcom_scm_vmperm perm; ++ u64 src_perms = 0; ++ struct qcom_scm_vmperm dst_perms; ++ u32 i; + +- perm.vmid = QCOM_SCM_VMID_HLOS; +- perm.perm = QCOM_SCM_PERM_RWX; ++ for (i = 0; i < fl->cctx->vmcount; i++) ++ src_perms |= BIT(fl->cctx->vmperms[i].vmid); ++ ++ dst_perms.vmid = QCOM_SCM_VMID_HLOS; ++ dst_perms.perm = QCOM_SCM_PERM_RWX; + err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys, + (u64)fl->cctx->remote_heap->size, +- &fl->cctx->perms, &perm, 1); ++ &src_perms, &dst_perms, 1); + if (err) + dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", + fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err); +diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c +index 345934e4f59e6..2d5ef9c37d769 100644 +--- a/drivers/mmc/host/renesas_sdhi_core.c ++++ b/drivers/mmc/host/renesas_sdhi_core.c +@@ -1006,6 +1006,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, + host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; + host->sdcard_irq_mask_all = TMIO_MASK_ALL_RCAR2; + host->reset = renesas_sdhi_reset; ++ } else { ++ host->sdcard_irq_mask_all = TMIO_MASK_ALL; + } + + /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ +@@ -1100,9 +1102,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, + host->ops.hs400_complete = renesas_sdhi_hs400_complete; + } + +- ret = tmio_mmc_host_probe(host); +- if (ret < 0) +- goto edisclk; ++ sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all); + + num_irqs = platform_irq_count(pdev); + if (num_irqs < 0) { +@@ -1129,6 +1129,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, + goto eirq; + } + ++ ret = tmio_mmc_host_probe(host); ++ if (ret < 0) ++ goto edisclk; ++ + dev_info(&pdev->dev, "%s base at %pa, max clock rate %u MHz\n", + mmc_hostname(host->mmc), &res->start, host->mmc->f_max / 1000000); + +diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +index 2e9c2e2d9c9f7..d8418d7fcc372 100644 +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -2612,6 +2612,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) + struct nand_chip *chip = &host->chip; + const struct nand_ecc_props *requirements = + nanddev_get_ecc_requirements(&chip->base); ++ struct nand_memory_organization *memorg = ++ nanddev_get_memorg(&chip->base); + struct brcmnand_controller *ctrl = host->ctrl; + struct brcmnand_cfg *cfg = &host->hwcfg; + char msg[128]; +@@ -2633,10 +2635,11 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) + if (cfg->spare_area_size > ctrl->max_oob) + cfg->spare_area_size = ctrl->max_oob; + /* +- * Set oobsize to be consistent with controller's spare_area_size, as +- * the rest is inaccessible. ++ * Set mtd and memorg oobsize to be consistent with controller's ++ * spare_area_size, as the rest is inaccessible. + */ + mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT); ++ memorg->oobsize = mtd->oobsize; + + cfg->device_size = mtd->size; + cfg->block_size = mtd->erasesize; +diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c +index 7b4742420dfcb..2e33ae77502a0 100644 +--- a/drivers/mtd/nand/raw/fsmc_nand.c ++++ b/drivers/mtd/nand/raw/fsmc_nand.c +@@ -1200,9 +1200,14 @@ static int fsmc_nand_suspend(struct device *dev) + static int fsmc_nand_resume(struct device *dev) + { + struct fsmc_nand_data *host = dev_get_drvdata(dev); ++ int ret; + + if (host) { +- clk_prepare_enable(host->clk); ++ ret = clk_prepare_enable(host->clk); ++ if (ret) { ++ dev_err(dev, "failed to enable clk\n"); ++ return ret; ++ } + if (host->dev_timings) + fsmc_nand_setup(host, host->dev_timings); + nand_reset(&host->nand, 0); +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 5f29fac8669a3..55f4a902b8be9 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -870,21 +870,22 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) + ret = spi_nor_read_cr(nor, &sr_cr[1]); + if (ret) + return ret; +- } else if (nor->params->quad_enable) { ++ } else if (spi_nor_get_protocol_width(nor->read_proto) == 4 && ++ spi_nor_get_protocol_width(nor->write_proto) == 4 && ++ nor->params->quad_enable) { + /* + * If the Status Register 2 Read command (35h) is not + * supported, we should at least be sure we don't + * change the value of the SR2 Quad Enable bit. + * +- * We can safely assume that when the Quad Enable method is +- * set, the value of the QE bit is one, as a consequence of the +- * nor->params->quad_enable() call. ++ * When the Quad Enable method is set and the buswidth is 4, we ++ * can safely assume that the value of the QE bit is one, as a ++ * consequence of the nor->params->quad_enable() call. + * +- * We can safely assume that the Quad Enable bit is present in +- * the Status Register 2 at BIT(1). According to the JESD216 +- * revB standard, BFPT DWORDS[15], bits 22:20, the 16-bit +- * Write Status (01h) command is available just for the cases +- * in which the QE bit is described in SR2 at BIT(1). ++ * According to the JESD216 revB standard, BFPT DWORDS[15], ++ * bits 22:20, the 16-bit Write Status (01h) command is ++ * available just for the cases in which the QE bit is ++ * described in SR2 at BIT(1). + */ + sr_cr[1] = SR2_QUAD_EN_BIT1; + } else { +diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c +index 1bad1866ae462..a48220f91a2df 100644 +--- a/drivers/net/arcnet/arcnet.c ++++ b/drivers/net/arcnet/arcnet.c +@@ -468,7 +468,7 @@ static void arcnet_reply_tasklet(struct tasklet_struct *t) + + ret = sock_queue_err_skb(sk, ackskb); + if (ret) +- kfree_skb(ackskb); ++ dev_kfree_skb_irq(ackskb); + + local_irq_enable(); + }; +diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c +index 2b218ce04e9f2..fafa6daa67e69 100644 +--- a/drivers/net/can/m_can/tcan4x5x-regmap.c ++++ b/drivers/net/can/m_can/tcan4x5x-regmap.c +@@ -95,7 +95,6 @@ static const struct regmap_range tcan4x5x_reg_table_wr_range[] = { + regmap_reg_range(0x000c, 0x0010), + /* Device configuration registers and Interrupt Flags*/ + regmap_reg_range(0x0800, 0x080c), +- regmap_reg_range(0x0814, 0x0814), + regmap_reg_range(0x0820, 0x0820), + regmap_reg_range(0x0830, 0x0830), + /* M_CAN */ +diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c +index bd9eb066ecf15..129ef60a577c8 100644 +--- a/drivers/net/can/usb/gs_usb.c ++++ b/drivers/net/can/usb/gs_usb.c +@@ -633,6 +633,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) + } + + if (hf->flags & GS_CAN_FLAG_OVERFLOW) { ++ stats->rx_over_errors++; ++ stats->rx_errors++; ++ + skb = alloc_can_err_skb(netdev, &cf); + if (!skb) + goto resubmit_urb; +@@ -640,8 +643,6 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) + cf->can_id |= CAN_ERR_CRTL; + cf->len = CAN_ERR_DLC; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; +- stats->rx_over_errors++; +- stats->rx_errors++; + netif_rx(skb); + } + +diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c +index a0ba2605bb620..f87ed14fa2ab2 100644 +--- a/drivers/net/dsa/microchip/ksz_common.c ++++ b/drivers/net/dsa/microchip/ksz_common.c +@@ -635,10 +635,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { + regmap_reg_range(0x1030, 0x1030), + regmap_reg_range(0x1100, 0x1115), + regmap_reg_range(0x111a, 0x111f), +- regmap_reg_range(0x1122, 0x1127), +- regmap_reg_range(0x112a, 0x112b), +- regmap_reg_range(0x1136, 0x1139), +- regmap_reg_range(0x113e, 0x113f), ++ regmap_reg_range(0x1120, 0x112b), ++ regmap_reg_range(0x1134, 0x113b), ++ regmap_reg_range(0x113c, 0x113f), + regmap_reg_range(0x1400, 0x1401), + regmap_reg_range(0x1403, 0x1403), + regmap_reg_range(0x1410, 0x1417), +@@ -669,10 +668,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { + regmap_reg_range(0x2030, 0x2030), + regmap_reg_range(0x2100, 0x2115), + regmap_reg_range(0x211a, 0x211f), +- regmap_reg_range(0x2122, 0x2127), +- regmap_reg_range(0x212a, 0x212b), +- regmap_reg_range(0x2136, 0x2139), +- regmap_reg_range(0x213e, 0x213f), ++ regmap_reg_range(0x2120, 0x212b), ++ regmap_reg_range(0x2134, 0x213b), ++ regmap_reg_range(0x213c, 0x213f), + regmap_reg_range(0x2400, 0x2401), + regmap_reg_range(0x2403, 0x2403), + regmap_reg_range(0x2410, 0x2417), +@@ -703,10 +701,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { + regmap_reg_range(0x3030, 0x3030), + regmap_reg_range(0x3100, 0x3115), + regmap_reg_range(0x311a, 0x311f), +- regmap_reg_range(0x3122, 0x3127), +- regmap_reg_range(0x312a, 0x312b), +- regmap_reg_range(0x3136, 0x3139), +- regmap_reg_range(0x313e, 0x313f), ++ regmap_reg_range(0x3120, 0x312b), ++ regmap_reg_range(0x3134, 0x313b), ++ regmap_reg_range(0x313c, 0x313f), + regmap_reg_range(0x3400, 0x3401), + regmap_reg_range(0x3403, 0x3403), + regmap_reg_range(0x3410, 0x3417), +@@ -737,10 +734,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { + regmap_reg_range(0x4030, 0x4030), + regmap_reg_range(0x4100, 0x4115), + regmap_reg_range(0x411a, 0x411f), +- regmap_reg_range(0x4122, 0x4127), +- regmap_reg_range(0x412a, 0x412b), +- regmap_reg_range(0x4136, 0x4139), +- regmap_reg_range(0x413e, 0x413f), ++ regmap_reg_range(0x4120, 0x412b), ++ regmap_reg_range(0x4134, 0x413b), ++ regmap_reg_range(0x413c, 0x413f), + regmap_reg_range(0x4400, 0x4401), + regmap_reg_range(0x4403, 0x4403), + regmap_reg_range(0x4410, 0x4417), +@@ -771,10 +767,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { + regmap_reg_range(0x5030, 0x5030), + regmap_reg_range(0x5100, 0x5115), + regmap_reg_range(0x511a, 0x511f), +- regmap_reg_range(0x5122, 0x5127), +- regmap_reg_range(0x512a, 0x512b), +- regmap_reg_range(0x5136, 0x5139), +- regmap_reg_range(0x513e, 0x513f), ++ regmap_reg_range(0x5120, 0x512b), ++ regmap_reg_range(0x5134, 0x513b), ++ regmap_reg_range(0x513c, 0x513f), + regmap_reg_range(0x5400, 0x5401), + regmap_reg_range(0x5403, 0x5403), + regmap_reg_range(0x5410, 0x5417), +diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c +index 483a070d96fa9..d06934edc265e 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.c ++++ b/drivers/net/ethernet/amd/pds_core/core.c +@@ -464,7 +464,8 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing) + { + int i; + +- pdsc_devcmd_reset(pdsc); ++ if (!pdsc->pdev->is_virtfn) ++ pdsc_devcmd_reset(pdsc); + pdsc_qcq_free(pdsc, &pdsc->notifyqcq); + pdsc_qcq_free(pdsc, &pdsc->adminqcq); + +@@ -524,7 +525,8 @@ static void pdsc_fw_down(struct pdsc *pdsc) + } + + /* Notify clients of fw_down */ +- devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc); ++ if (pdsc->fw_reporter) ++ devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc); + pdsc_notify(PDS_EVENT_RESET, &reset_event); + + pdsc_stop(pdsc); +@@ -554,8 +556,9 @@ static void pdsc_fw_up(struct pdsc *pdsc) + + /* Notify clients of fw_up */ + pdsc->fw_recoveries++; +- devlink_health_reporter_state_update(pdsc->fw_reporter, +- DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); ++ if (pdsc->fw_reporter) ++ devlink_health_reporter_state_update(pdsc->fw_reporter, ++ DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); + pdsc_notify(PDS_EVENT_RESET, &reset_event); + + return; +diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c +index debe5216fe29e..f77cd9f5a2fda 100644 +--- a/drivers/net/ethernet/amd/pds_core/dev.c ++++ b/drivers/net/ethernet/amd/pds_core/dev.c +@@ -121,7 +121,7 @@ static const char *pdsc_devcmd_str(int opcode) + } + } + +-static int pdsc_devcmd_wait(struct pdsc *pdsc, int max_seconds) ++static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + { + struct device *dev = pdsc->dev; + unsigned long start_time; +@@ -131,9 +131,6 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, int max_seconds) + int done = 0; + int err = 0; + int status; +- int opcode; +- +- opcode = ioread8(&pdsc->cmd_regs->cmd.opcode); + + start_time = jiffies; + max_wait = start_time + (max_seconds * HZ); +@@ -180,10 +177,10 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, + + memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd)); + pdsc_devcmd_dbell(pdsc); +- err = pdsc_devcmd_wait(pdsc, max_seconds); ++ err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds); + memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp)); + +- if (err == -ENXIO || err == -ETIMEDOUT) ++ if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq) + queue_work(pdsc->wq, &pdsc->health_work); + + return err; +diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c +index 9c6b3653c1c7c..d9607033bbf21 100644 +--- a/drivers/net/ethernet/amd/pds_core/devlink.c ++++ b/drivers/net/ethernet/amd/pds_core/devlink.c +@@ -10,6 +10,9 @@ pdsc_viftype *pdsc_dl_find_viftype_by_id(struct pdsc *pdsc, + { + int vt; + ++ if (!pdsc->viftype_status) ++ return NULL; ++ + for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) { + if (pdsc->viftype_status[vt].dl_id == dl_id) + return &pdsc->viftype_status[vt]; +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +index 4a288799633f8..940c5d1ff9cfc 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +@@ -2094,8 +2094,11 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter, + real_len = (((unsigned char *)ip_hdr(skb) - skb->data) + + ntohs(ip_hdr(skb)->tot_len)); + +- if (real_len < skb->len) +- pskb_trim(skb, real_len); ++ if (real_len < skb->len) { ++ err = pskb_trim(skb, real_len); ++ if (err) ++ return err; ++ } + + hdr_len = skb_tcp_all_headers(skb); + if (unlikely(skb->len == hdr_len)) { +diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c +index 392ec09a1d8a6..3e4fb3c3e8342 100644 +--- a/drivers/net/ethernet/broadcom/b44.c ++++ b/drivers/net/ethernet/broadcom/b44.c +@@ -1793,11 +1793,9 @@ static int b44_nway_reset(struct net_device *dev) + b44_readphy(bp, MII_BMCR, &bmcr); + b44_readphy(bp, MII_BMCR, &bmcr); + r = -EINVAL; +- if (bmcr & BMCR_ANENABLE) { +- b44_writephy(bp, MII_BMCR, +- bmcr | BMCR_ANRESTART); +- r = 0; +- } ++ if (bmcr & BMCR_ANENABLE) ++ r = b44_writephy(bp, MII_BMCR, ++ bmcr | BMCR_ANRESTART); + spin_unlock_irq(&bp->lock); + + return r; +diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile +index 6efea46628587..e214bfaece1f3 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/Makefile ++++ b/drivers/net/ethernet/hisilicon/hns3/Makefile +@@ -17,11 +17,11 @@ hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o + + obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o + +-hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o \ ++hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o hns3vf/hclgevf_regs.o \ + hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o + + obj-$(CONFIG_HNS3_HCLGE) += hclge.o +-hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o \ ++hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_regs.o \ + hns3pf/hclge_mbx.o hns3pf/hclge_err.o hns3pf/hclge_debugfs.o hns3pf/hclge_ptp.o hns3pf/hclge_devlink.o \ + hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h +index 06f29e80104c0..e9c108128bb3b 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h +@@ -102,6 +102,7 @@ enum HNAE3_DEV_CAP_BITS { + HNAE3_DEV_SUPPORT_FEC_STATS_B, + HNAE3_DEV_SUPPORT_LANE_NUM_B, + HNAE3_DEV_SUPPORT_WOL_B, ++ HNAE3_DEV_SUPPORT_TM_FLUSH_B, + }; + + #define hnae3_ae_dev_fd_supported(ae_dev) \ +@@ -173,6 +174,9 @@ enum HNAE3_DEV_CAP_BITS { + #define hnae3_ae_dev_wol_supported(ae_dev) \ + test_bit(HNAE3_DEV_SUPPORT_WOL_B, (ae_dev)->caps) + ++#define hnae3_ae_dev_tm_flush_supported(hdev) \ ++ test_bit(HNAE3_DEV_SUPPORT_TM_FLUSH_B, (hdev)->ae_dev->caps) ++ + enum HNAE3_PF_CAP_BITS { + HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0, + }; +@@ -378,6 +382,7 @@ struct hnae3_dev_specs { + u16 umv_size; + u16 mc_mac_size; + u32 mac_stats_num; ++ u8 tnl_num; + }; + + struct hnae3_client_ops { +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c +index 16ba98ff2c9b1..dcecb23daac6e 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c +@@ -156,6 +156,7 @@ static const struct hclge_comm_caps_bit_map hclge_pf_cmd_caps[] = { + {HCLGE_COMM_CAP_FEC_STATS_B, HNAE3_DEV_SUPPORT_FEC_STATS_B}, + {HCLGE_COMM_CAP_LANE_NUM_B, HNAE3_DEV_SUPPORT_LANE_NUM_B}, + {HCLGE_COMM_CAP_WOL_B, HNAE3_DEV_SUPPORT_WOL_B}, ++ {HCLGE_COMM_CAP_TM_FLUSH_B, HNAE3_DEV_SUPPORT_TM_FLUSH_B}, + }; + + static const struct hclge_comm_caps_bit_map hclge_vf_cmd_caps[] = { +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +index 18f1b4bf362da..2b7197ce0ae8f 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +@@ -153,6 +153,7 @@ enum hclge_opcode_type { + HCLGE_OPC_TM_INTERNAL_STS = 0x0850, + HCLGE_OPC_TM_INTERNAL_CNT = 0x0851, + HCLGE_OPC_TM_INTERNAL_STS_1 = 0x0852, ++ HCLGE_OPC_TM_FLUSH = 0x0872, + + /* Packet buffer allocate commands */ + HCLGE_OPC_TX_BUFF_ALLOC = 0x0901, +@@ -349,6 +350,7 @@ enum HCLGE_COMM_CAP_BITS { + HCLGE_COMM_CAP_FEC_STATS_B = 25, + HCLGE_COMM_CAP_LANE_NUM_B = 27, + HCLGE_COMM_CAP_WOL_B = 28, ++ HCLGE_COMM_CAP_TM_FLUSH_B = 31, + }; + + enum HCLGE_COMM_API_CAP_BITS { +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +index 207b2e3f3fc2b..dce158d4aeef6 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +@@ -411,6 +411,9 @@ static struct hns3_dbg_cap_info hns3_dbg_cap[] = { + }, { + .name = "support wake on lan", + .cap_bit = HNAE3_DEV_SUPPORT_WOL_B, ++ }, { ++ .name = "support tm flush", ++ .cap_bit = HNAE3_DEV_SUPPORT_TM_FLUSH_B, + } + }; + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +index 91c173f40701a..d5cfdc4c082d8 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +@@ -826,7 +826,9 @@ struct hclge_dev_specs_1_cmd { + u8 rsv0[2]; + __le16 umv_size; + __le16 mc_mac_size; +- u8 rsv1[12]; ++ u8 rsv1[6]; ++ u8 tnl_num; ++ u8 rsv2[5]; + }; + + /* mac speed type defined in firmware command */ +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +index 09362823140d5..fad5a5ff3cda5 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +@@ -227,6 +227,10 @@ static int hclge_notify_down_uinit(struct hclge_dev *hdev) + if (ret) + return ret; + ++ ret = hclge_tm_flush_cfg(hdev, true); ++ if (ret) ++ return ret; ++ + return hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT); + } + +@@ -238,6 +242,10 @@ static int hclge_notify_init_up(struct hclge_dev *hdev) + if (ret) + return ret; + ++ ret = hclge_tm_flush_cfg(hdev, false); ++ if (ret) ++ return ret; ++ + return hclge_notify_client(hdev, HNAE3_UP_CLIENT); + } + +@@ -324,6 +332,7 @@ static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc) + struct net_device *netdev = h->kinfo.netdev; + struct hclge_dev *hdev = vport->back; + u8 i, j, pfc_map, *prio_tc; ++ int last_bad_ret = 0; + int ret; + + if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) +@@ -361,13 +370,28 @@ static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc) + if (ret) + return ret; + +- ret = hclge_buffer_alloc(hdev); +- if (ret) { +- hclge_notify_client(hdev, HNAE3_UP_CLIENT); ++ ret = hclge_tm_flush_cfg(hdev, true); ++ if (ret) + return ret; +- } + +- return hclge_notify_client(hdev, HNAE3_UP_CLIENT); ++ /* No matter whether the following operations are performed ++ * successfully or not, disabling the tm flush and notify ++ * the network status to up are necessary. ++ * Do not return immediately. ++ */ ++ ret = hclge_buffer_alloc(hdev); ++ if (ret) ++ last_bad_ret = ret; ++ ++ ret = hclge_tm_flush_cfg(hdev, false); ++ if (ret) ++ last_bad_ret = ret; ++ ++ ret = hclge_notify_client(hdev, HNAE3_UP_CLIENT); ++ if (ret) ++ last_bad_ret = ret; ++ ++ return last_bad_ret; + } + + static int hclge_ieee_setapp(struct hnae3_handle *h, struct dcb_app *app) +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +index 0fb2eaee3e8a0..f01a7a9ee02ca 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +@@ -7,6 +7,7 @@ + #include "hclge_debugfs.h" + #include "hclge_err.h" + #include "hclge_main.h" ++#include "hclge_regs.h" + #include "hclge_tm.h" + #include "hnae3.h" + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +index c3e94598f3983..0d56dc2e9960e 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +@@ -20,6 +20,7 @@ + #include "hclge_main.h" + #include "hclge_mbx.h" + #include "hclge_mdio.h" ++#include "hclge_regs.h" + #include "hclge_tm.h" + #include "hclge_err.h" + #include "hnae3.h" +@@ -40,20 +41,6 @@ + #define HCLGE_PF_RESET_SYNC_TIME 20 + #define HCLGE_PF_RESET_SYNC_CNT 1500 + +-/* Get DFX BD number offset */ +-#define HCLGE_DFX_BIOS_BD_OFFSET 1 +-#define HCLGE_DFX_SSU_0_BD_OFFSET 2 +-#define HCLGE_DFX_SSU_1_BD_OFFSET 3 +-#define HCLGE_DFX_IGU_BD_OFFSET 4 +-#define HCLGE_DFX_RPU_0_BD_OFFSET 5 +-#define HCLGE_DFX_RPU_1_BD_OFFSET 6 +-#define HCLGE_DFX_NCSI_BD_OFFSET 7 +-#define HCLGE_DFX_RTC_BD_OFFSET 8 +-#define HCLGE_DFX_PPP_BD_OFFSET 9 +-#define HCLGE_DFX_RCB_BD_OFFSET 10 +-#define HCLGE_DFX_TQP_BD_OFFSET 11 +-#define HCLGE_DFX_SSU_2_BD_OFFSET 12 +- + #define HCLGE_LINK_STATUS_MS 10 + + static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps); +@@ -94,62 +81,6 @@ static const struct pci_device_id ae_algo_pci_tbl[] = { + + MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl); + +-static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG, +- HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG, +- HCLGE_COMM_NIC_CSQ_DEPTH_REG, +- HCLGE_COMM_NIC_CSQ_TAIL_REG, +- HCLGE_COMM_NIC_CSQ_HEAD_REG, +- HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG, +- HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG, +- HCLGE_COMM_NIC_CRQ_DEPTH_REG, +- HCLGE_COMM_NIC_CRQ_TAIL_REG, +- HCLGE_COMM_NIC_CRQ_HEAD_REG, +- HCLGE_COMM_VECTOR0_CMDQ_SRC_REG, +- HCLGE_COMM_CMDQ_INTR_STS_REG, +- HCLGE_COMM_CMDQ_INTR_EN_REG, +- HCLGE_COMM_CMDQ_INTR_GEN_REG}; +- +-static const u32 common_reg_addr_list[] = {HCLGE_MISC_VECTOR_REG_BASE, +- HCLGE_PF_OTHER_INT_REG, +- HCLGE_MISC_RESET_STS_REG, +- HCLGE_MISC_VECTOR_INT_STS, +- HCLGE_GLOBAL_RESET_REG, +- HCLGE_FUN_RST_ING, +- HCLGE_GRO_EN_REG}; +- +-static const u32 ring_reg_addr_list[] = {HCLGE_RING_RX_ADDR_L_REG, +- HCLGE_RING_RX_ADDR_H_REG, +- HCLGE_RING_RX_BD_NUM_REG, +- HCLGE_RING_RX_BD_LENGTH_REG, +- HCLGE_RING_RX_MERGE_EN_REG, +- HCLGE_RING_RX_TAIL_REG, +- HCLGE_RING_RX_HEAD_REG, +- HCLGE_RING_RX_FBD_NUM_REG, +- HCLGE_RING_RX_OFFSET_REG, +- HCLGE_RING_RX_FBD_OFFSET_REG, +- HCLGE_RING_RX_STASH_REG, +- HCLGE_RING_RX_BD_ERR_REG, +- HCLGE_RING_TX_ADDR_L_REG, +- HCLGE_RING_TX_ADDR_H_REG, +- HCLGE_RING_TX_BD_NUM_REG, +- HCLGE_RING_TX_PRIORITY_REG, +- HCLGE_RING_TX_TC_REG, +- HCLGE_RING_TX_MERGE_EN_REG, +- HCLGE_RING_TX_TAIL_REG, +- HCLGE_RING_TX_HEAD_REG, +- HCLGE_RING_TX_FBD_NUM_REG, +- HCLGE_RING_TX_OFFSET_REG, +- HCLGE_RING_TX_EBD_NUM_REG, +- HCLGE_RING_TX_EBD_OFFSET_REG, +- HCLGE_RING_TX_BD_ERR_REG, +- HCLGE_RING_EN_REG}; +- +-static const u32 tqp_intr_reg_addr_list[] = {HCLGE_TQP_INTR_CTRL_REG, +- HCLGE_TQP_INTR_GL0_REG, +- HCLGE_TQP_INTR_GL1_REG, +- HCLGE_TQP_INTR_GL2_REG, +- HCLGE_TQP_INTR_RL_REG}; +- + static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = { + "External Loopback test", + "App Loopback test", +@@ -375,36 +306,6 @@ static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = { + }, + }; + +-static const u32 hclge_dfx_bd_offset_list[] = { +- HCLGE_DFX_BIOS_BD_OFFSET, +- HCLGE_DFX_SSU_0_BD_OFFSET, +- HCLGE_DFX_SSU_1_BD_OFFSET, +- HCLGE_DFX_IGU_BD_OFFSET, +- HCLGE_DFX_RPU_0_BD_OFFSET, +- HCLGE_DFX_RPU_1_BD_OFFSET, +- HCLGE_DFX_NCSI_BD_OFFSET, +- HCLGE_DFX_RTC_BD_OFFSET, +- HCLGE_DFX_PPP_BD_OFFSET, +- HCLGE_DFX_RCB_BD_OFFSET, +- HCLGE_DFX_TQP_BD_OFFSET, +- HCLGE_DFX_SSU_2_BD_OFFSET +-}; +- +-static const enum hclge_opcode_type hclge_dfx_reg_opcode_list[] = { +- HCLGE_OPC_DFX_BIOS_COMMON_REG, +- HCLGE_OPC_DFX_SSU_REG_0, +- HCLGE_OPC_DFX_SSU_REG_1, +- HCLGE_OPC_DFX_IGU_EGU_REG, +- HCLGE_OPC_DFX_RPU_REG_0, +- HCLGE_OPC_DFX_RPU_REG_1, +- HCLGE_OPC_DFX_NCSI_REG, +- HCLGE_OPC_DFX_RTC_REG, +- HCLGE_OPC_DFX_PPP_REG, +- HCLGE_OPC_DFX_RCB_REG, +- HCLGE_OPC_DFX_TQP_REG, +- HCLGE_OPC_DFX_SSU_REG_2 +-}; +- + static const struct key_info meta_data_key_info[] = { + { PACKET_TYPE_ID, 6 }, + { IP_FRAGEMENT, 1 }, +@@ -1426,6 +1327,7 @@ static void hclge_set_default_dev_specs(struct hclge_dev *hdev) + ae_dev->dev_specs.max_frm_size = HCLGE_MAC_MAX_FRAME; + ae_dev->dev_specs.max_qset_num = HCLGE_MAX_QSET_NUM; + ae_dev->dev_specs.umv_size = HCLGE_DEFAULT_UMV_SPACE_PER_PF; ++ ae_dev->dev_specs.tnl_num = 0; + } + + static void hclge_parse_dev_specs(struct hclge_dev *hdev, +@@ -1449,6 +1351,7 @@ static void hclge_parse_dev_specs(struct hclge_dev *hdev, + ae_dev->dev_specs.max_frm_size = le16_to_cpu(req1->max_frm_size); + ae_dev->dev_specs.umv_size = le16_to_cpu(req1->umv_size); + ae_dev->dev_specs.mc_mac_size = le16_to_cpu(req1->mc_mac_size); ++ ae_dev->dev_specs.tnl_num = req1->tnl_num; + } + + static void hclge_check_dev_specs(struct hclge_dev *hdev) +@@ -10936,9 +10839,12 @@ int hclge_cfg_flowctrl(struct hclge_dev *hdev) + u32 rx_pause, tx_pause; + u8 flowctl; + +- if (!phydev->link || !phydev->autoneg) ++ if (!phydev->link) + return 0; + ++ if (!phydev->autoneg) ++ return hclge_mac_pause_setup_hw(hdev); ++ + local_advertising = linkmode_adv_to_lcl_adv_t(phydev->advertising); + + if (phydev->pause) +@@ -12389,463 +12295,6 @@ out: + return ret; + } + +-static int hclge_get_regs_num(struct hclge_dev *hdev, u32 *regs_num_32_bit, +- u32 *regs_num_64_bit) +-{ +- struct hclge_desc desc; +- u32 total_num; +- int ret; +- +- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_REG_NUM, true); +- ret = hclge_cmd_send(&hdev->hw, &desc, 1); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Query register number cmd failed, ret = %d.\n", ret); +- return ret; +- } +- +- *regs_num_32_bit = le32_to_cpu(desc.data[0]); +- *regs_num_64_bit = le32_to_cpu(desc.data[1]); +- +- total_num = *regs_num_32_bit + *regs_num_64_bit; +- if (!total_num) +- return -EINVAL; +- +- return 0; +-} +- +-static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num, +- void *data) +-{ +-#define HCLGE_32_BIT_REG_RTN_DATANUM 8 +-#define HCLGE_32_BIT_DESC_NODATA_LEN 2 +- +- struct hclge_desc *desc; +- u32 *reg_val = data; +- __le32 *desc_data; +- int nodata_num; +- int cmd_num; +- int i, k, n; +- int ret; +- +- if (regs_num == 0) +- return 0; +- +- nodata_num = HCLGE_32_BIT_DESC_NODATA_LEN; +- cmd_num = DIV_ROUND_UP(regs_num + nodata_num, +- HCLGE_32_BIT_REG_RTN_DATANUM); +- desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL); +- if (!desc) +- return -ENOMEM; +- +- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_32_BIT_REG, true); +- ret = hclge_cmd_send(&hdev->hw, desc, cmd_num); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Query 32 bit register cmd failed, ret = %d.\n", ret); +- kfree(desc); +- return ret; +- } +- +- for (i = 0; i < cmd_num; i++) { +- if (i == 0) { +- desc_data = (__le32 *)(&desc[i].data[0]); +- n = HCLGE_32_BIT_REG_RTN_DATANUM - nodata_num; +- } else { +- desc_data = (__le32 *)(&desc[i]); +- n = HCLGE_32_BIT_REG_RTN_DATANUM; +- } +- for (k = 0; k < n; k++) { +- *reg_val++ = le32_to_cpu(*desc_data++); +- +- regs_num--; +- if (!regs_num) +- break; +- } +- } +- +- kfree(desc); +- return 0; +-} +- +-static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num, +- void *data) +-{ +-#define HCLGE_64_BIT_REG_RTN_DATANUM 4 +-#define HCLGE_64_BIT_DESC_NODATA_LEN 1 +- +- struct hclge_desc *desc; +- u64 *reg_val = data; +- __le64 *desc_data; +- int nodata_len; +- int cmd_num; +- int i, k, n; +- int ret; +- +- if (regs_num == 0) +- return 0; +- +- nodata_len = HCLGE_64_BIT_DESC_NODATA_LEN; +- cmd_num = DIV_ROUND_UP(regs_num + nodata_len, +- HCLGE_64_BIT_REG_RTN_DATANUM); +- desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL); +- if (!desc) +- return -ENOMEM; +- +- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_64_BIT_REG, true); +- ret = hclge_cmd_send(&hdev->hw, desc, cmd_num); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Query 64 bit register cmd failed, ret = %d.\n", ret); +- kfree(desc); +- return ret; +- } +- +- for (i = 0; i < cmd_num; i++) { +- if (i == 0) { +- desc_data = (__le64 *)(&desc[i].data[0]); +- n = HCLGE_64_BIT_REG_RTN_DATANUM - nodata_len; +- } else { +- desc_data = (__le64 *)(&desc[i]); +- n = HCLGE_64_BIT_REG_RTN_DATANUM; +- } +- for (k = 0; k < n; k++) { +- *reg_val++ = le64_to_cpu(*desc_data++); +- +- regs_num--; +- if (!regs_num) +- break; +- } +- } +- +- kfree(desc); +- return 0; +-} +- +-#define MAX_SEPARATE_NUM 4 +-#define SEPARATOR_VALUE 0xFDFCFBFA +-#define REG_NUM_PER_LINE 4 +-#define REG_LEN_PER_LINE (REG_NUM_PER_LINE * sizeof(u32)) +-#define REG_SEPARATOR_LINE 1 +-#define REG_NUM_REMAIN_MASK 3 +- +-int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc) +-{ +- int i; +- +- /* initialize command BD except the last one */ +- for (i = 0; i < HCLGE_GET_DFX_REG_TYPE_CNT - 1; i++) { +- hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, +- true); +- desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); +- } +- +- /* initialize the last command BD */ +- hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, true); +- +- return hclge_cmd_send(&hdev->hw, desc, HCLGE_GET_DFX_REG_TYPE_CNT); +-} +- +-static int hclge_get_dfx_reg_bd_num(struct hclge_dev *hdev, +- int *bd_num_list, +- u32 type_num) +-{ +- u32 entries_per_desc, desc_index, index, offset, i; +- struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT]; +- int ret; +- +- ret = hclge_query_bd_num_cmd_send(hdev, desc); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get dfx bd num fail, status is %d.\n", ret); +- return ret; +- } +- +- entries_per_desc = ARRAY_SIZE(desc[0].data); +- for (i = 0; i < type_num; i++) { +- offset = hclge_dfx_bd_offset_list[i]; +- index = offset % entries_per_desc; +- desc_index = offset / entries_per_desc; +- bd_num_list[i] = le32_to_cpu(desc[desc_index].data[index]); +- } +- +- return ret; +-} +- +-static int hclge_dfx_reg_cmd_send(struct hclge_dev *hdev, +- struct hclge_desc *desc_src, int bd_num, +- enum hclge_opcode_type cmd) +-{ +- struct hclge_desc *desc = desc_src; +- int i, ret; +- +- hclge_cmd_setup_basic_desc(desc, cmd, true); +- for (i = 0; i < bd_num - 1; i++) { +- desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); +- desc++; +- hclge_cmd_setup_basic_desc(desc, cmd, true); +- } +- +- desc = desc_src; +- ret = hclge_cmd_send(&hdev->hw, desc, bd_num); +- if (ret) +- dev_err(&hdev->pdev->dev, +- "Query dfx reg cmd(0x%x) send fail, status is %d.\n", +- cmd, ret); +- +- return ret; +-} +- +-static int hclge_dfx_reg_fetch_data(struct hclge_desc *desc_src, int bd_num, +- void *data) +-{ +- int entries_per_desc, reg_num, separator_num, desc_index, index, i; +- struct hclge_desc *desc = desc_src; +- u32 *reg = data; +- +- entries_per_desc = ARRAY_SIZE(desc->data); +- reg_num = entries_per_desc * bd_num; +- separator_num = REG_NUM_PER_LINE - (reg_num & REG_NUM_REMAIN_MASK); +- for (i = 0; i < reg_num; i++) { +- index = i % entries_per_desc; +- desc_index = i / entries_per_desc; +- *reg++ = le32_to_cpu(desc[desc_index].data[index]); +- } +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- +- return reg_num + separator_num; +-} +- +-static int hclge_get_dfx_reg_len(struct hclge_dev *hdev, int *len) +-{ +- u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list); +- int data_len_per_desc, bd_num, i; +- int *bd_num_list; +- u32 data_len; +- int ret; +- +- bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL); +- if (!bd_num_list) +- return -ENOMEM; +- +- ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get dfx reg bd num fail, status is %d.\n", ret); +- goto out; +- } +- +- data_len_per_desc = sizeof_field(struct hclge_desc, data); +- *len = 0; +- for (i = 0; i < dfx_reg_type_num; i++) { +- bd_num = bd_num_list[i]; +- data_len = data_len_per_desc * bd_num; +- *len += (data_len / REG_LEN_PER_LINE + 1) * REG_LEN_PER_LINE; +- } +- +-out: +- kfree(bd_num_list); +- return ret; +-} +- +-static int hclge_get_dfx_reg(struct hclge_dev *hdev, void *data) +-{ +- u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list); +- int bd_num, bd_num_max, buf_len, i; +- struct hclge_desc *desc_src; +- int *bd_num_list; +- u32 *reg = data; +- int ret; +- +- bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL); +- if (!bd_num_list) +- return -ENOMEM; +- +- ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get dfx reg bd num fail, status is %d.\n", ret); +- goto out; +- } +- +- bd_num_max = bd_num_list[0]; +- for (i = 1; i < dfx_reg_type_num; i++) +- bd_num_max = max_t(int, bd_num_max, bd_num_list[i]); +- +- buf_len = sizeof(*desc_src) * bd_num_max; +- desc_src = kzalloc(buf_len, GFP_KERNEL); +- if (!desc_src) { +- ret = -ENOMEM; +- goto out; +- } +- +- for (i = 0; i < dfx_reg_type_num; i++) { +- bd_num = bd_num_list[i]; +- ret = hclge_dfx_reg_cmd_send(hdev, desc_src, bd_num, +- hclge_dfx_reg_opcode_list[i]); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get dfx reg fail, status is %d.\n", ret); +- break; +- } +- +- reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg); +- } +- +- kfree(desc_src); +-out: +- kfree(bd_num_list); +- return ret; +-} +- +-static int hclge_fetch_pf_reg(struct hclge_dev *hdev, void *data, +- struct hnae3_knic_private_info *kinfo) +-{ +-#define HCLGE_RING_REG_OFFSET 0x200 +-#define HCLGE_RING_INT_REG_OFFSET 0x4 +- +- int i, j, reg_num, separator_num; +- int data_num_sum; +- u32 *reg = data; +- +- /* fetching per-PF registers valus from PF PCIe register space */ +- reg_num = ARRAY_SIZE(cmdq_reg_addr_list); +- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK); +- for (i = 0; i < reg_num; i++) +- *reg++ = hclge_read_dev(&hdev->hw, cmdq_reg_addr_list[i]); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- data_num_sum = reg_num + separator_num; +- +- reg_num = ARRAY_SIZE(common_reg_addr_list); +- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK); +- for (i = 0; i < reg_num; i++) +- *reg++ = hclge_read_dev(&hdev->hw, common_reg_addr_list[i]); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- data_num_sum += reg_num + separator_num; +- +- reg_num = ARRAY_SIZE(ring_reg_addr_list); +- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK); +- for (j = 0; j < kinfo->num_tqps; j++) { +- for (i = 0; i < reg_num; i++) +- *reg++ = hclge_read_dev(&hdev->hw, +- ring_reg_addr_list[i] + +- HCLGE_RING_REG_OFFSET * j); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- } +- data_num_sum += (reg_num + separator_num) * kinfo->num_tqps; +- +- reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list); +- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK); +- for (j = 0; j < hdev->num_msi_used - 1; j++) { +- for (i = 0; i < reg_num; i++) +- *reg++ = hclge_read_dev(&hdev->hw, +- tqp_intr_reg_addr_list[i] + +- HCLGE_RING_INT_REG_OFFSET * j); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- } +- data_num_sum += (reg_num + separator_num) * (hdev->num_msi_used - 1); +- +- return data_num_sum; +-} +- +-static int hclge_get_regs_len(struct hnae3_handle *handle) +-{ +- int cmdq_lines, common_lines, ring_lines, tqp_intr_lines; +- struct hnae3_knic_private_info *kinfo = &handle->kinfo; +- struct hclge_vport *vport = hclge_get_vport(handle); +- struct hclge_dev *hdev = vport->back; +- int regs_num_32_bit, regs_num_64_bit, dfx_regs_len; +- int regs_lines_32_bit, regs_lines_64_bit; +- int ret; +- +- ret = hclge_get_regs_num(hdev, ®s_num_32_bit, ®s_num_64_bit); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get register number failed, ret = %d.\n", ret); +- return ret; +- } +- +- ret = hclge_get_dfx_reg_len(hdev, &dfx_regs_len); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get dfx reg len failed, ret = %d.\n", ret); +- return ret; +- } +- +- cmdq_lines = sizeof(cmdq_reg_addr_list) / REG_LEN_PER_LINE + +- REG_SEPARATOR_LINE; +- common_lines = sizeof(common_reg_addr_list) / REG_LEN_PER_LINE + +- REG_SEPARATOR_LINE; +- ring_lines = sizeof(ring_reg_addr_list) / REG_LEN_PER_LINE + +- REG_SEPARATOR_LINE; +- tqp_intr_lines = sizeof(tqp_intr_reg_addr_list) / REG_LEN_PER_LINE + +- REG_SEPARATOR_LINE; +- regs_lines_32_bit = regs_num_32_bit * sizeof(u32) / REG_LEN_PER_LINE + +- REG_SEPARATOR_LINE; +- regs_lines_64_bit = regs_num_64_bit * sizeof(u64) / REG_LEN_PER_LINE + +- REG_SEPARATOR_LINE; +- +- return (cmdq_lines + common_lines + ring_lines * kinfo->num_tqps + +- tqp_intr_lines * (hdev->num_msi_used - 1) + regs_lines_32_bit + +- regs_lines_64_bit) * REG_LEN_PER_LINE + dfx_regs_len; +-} +- +-static void hclge_get_regs(struct hnae3_handle *handle, u32 *version, +- void *data) +-{ +- struct hnae3_knic_private_info *kinfo = &handle->kinfo; +- struct hclge_vport *vport = hclge_get_vport(handle); +- struct hclge_dev *hdev = vport->back; +- u32 regs_num_32_bit, regs_num_64_bit; +- int i, reg_num, separator_num, ret; +- u32 *reg = data; +- +- *version = hdev->fw_version; +- +- ret = hclge_get_regs_num(hdev, ®s_num_32_bit, ®s_num_64_bit); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get register number failed, ret = %d.\n", ret); +- return; +- } +- +- reg += hclge_fetch_pf_reg(hdev, reg, kinfo); +- +- ret = hclge_get_32_bit_regs(hdev, regs_num_32_bit, reg); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get 32 bit register failed, ret = %d.\n", ret); +- return; +- } +- reg_num = regs_num_32_bit; +- reg += reg_num; +- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- +- ret = hclge_get_64_bit_regs(hdev, regs_num_64_bit, reg); +- if (ret) { +- dev_err(&hdev->pdev->dev, +- "Get 64 bit register failed, ret = %d.\n", ret); +- return; +- } +- reg_num = regs_num_64_bit * 2; +- reg += reg_num; +- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- +- ret = hclge_get_dfx_reg(hdev, reg); +- if (ret) +- dev_err(&hdev->pdev->dev, +- "Get dfx register failed, ret = %d.\n", ret); +-} +- + static int hclge_set_led_status(struct hclge_dev *hdev, u8 locate_led_status) + { + struct hclge_set_led_state_cmd *req; +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +index 81aa6b0facf5a..e292a1253dd72 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +@@ -1147,8 +1147,6 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid, + u16 state, + struct hclge_vlan_info *vlan_info); + void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time); +-int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, +- struct hclge_desc *desc); + void hclge_report_hw_error(struct hclge_dev *hdev, + enum hnae3_hw_error_type type); + void hclge_inform_vf_promisc_info(struct hclge_vport *vport); +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c +new file mode 100644 +index 0000000000000..43c1c18fa81f8 +--- /dev/null ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c +@@ -0,0 +1,668 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2023 Hisilicon Limited. ++ ++#include "hclge_cmd.h" ++#include "hclge_main.h" ++#include "hclge_regs.h" ++#include "hnae3.h" ++ ++static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG, ++ HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG, ++ HCLGE_COMM_NIC_CSQ_DEPTH_REG, ++ HCLGE_COMM_NIC_CSQ_TAIL_REG, ++ HCLGE_COMM_NIC_CSQ_HEAD_REG, ++ HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG, ++ HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG, ++ HCLGE_COMM_NIC_CRQ_DEPTH_REG, ++ HCLGE_COMM_NIC_CRQ_TAIL_REG, ++ HCLGE_COMM_NIC_CRQ_HEAD_REG, ++ HCLGE_COMM_VECTOR0_CMDQ_SRC_REG, ++ HCLGE_COMM_CMDQ_INTR_STS_REG, ++ HCLGE_COMM_CMDQ_INTR_EN_REG, ++ HCLGE_COMM_CMDQ_INTR_GEN_REG}; ++ ++static const u32 common_reg_addr_list[] = {HCLGE_MISC_VECTOR_REG_BASE, ++ HCLGE_PF_OTHER_INT_REG, ++ HCLGE_MISC_RESET_STS_REG, ++ HCLGE_MISC_VECTOR_INT_STS, ++ HCLGE_GLOBAL_RESET_REG, ++ HCLGE_FUN_RST_ING, ++ HCLGE_GRO_EN_REG}; ++ ++static const u32 ring_reg_addr_list[] = {HCLGE_RING_RX_ADDR_L_REG, ++ HCLGE_RING_RX_ADDR_H_REG, ++ HCLGE_RING_RX_BD_NUM_REG, ++ HCLGE_RING_RX_BD_LENGTH_REG, ++ HCLGE_RING_RX_MERGE_EN_REG, ++ HCLGE_RING_RX_TAIL_REG, ++ HCLGE_RING_RX_HEAD_REG, ++ HCLGE_RING_RX_FBD_NUM_REG, ++ HCLGE_RING_RX_OFFSET_REG, ++ HCLGE_RING_RX_FBD_OFFSET_REG, ++ HCLGE_RING_RX_STASH_REG, ++ HCLGE_RING_RX_BD_ERR_REG, ++ HCLGE_RING_TX_ADDR_L_REG, ++ HCLGE_RING_TX_ADDR_H_REG, ++ HCLGE_RING_TX_BD_NUM_REG, ++ HCLGE_RING_TX_PRIORITY_REG, ++ HCLGE_RING_TX_TC_REG, ++ HCLGE_RING_TX_MERGE_EN_REG, ++ HCLGE_RING_TX_TAIL_REG, ++ HCLGE_RING_TX_HEAD_REG, ++ HCLGE_RING_TX_FBD_NUM_REG, ++ HCLGE_RING_TX_OFFSET_REG, ++ HCLGE_RING_TX_EBD_NUM_REG, ++ HCLGE_RING_TX_EBD_OFFSET_REG, ++ HCLGE_RING_TX_BD_ERR_REG, ++ HCLGE_RING_EN_REG}; ++ ++static const u32 tqp_intr_reg_addr_list[] = {HCLGE_TQP_INTR_CTRL_REG, ++ HCLGE_TQP_INTR_GL0_REG, ++ HCLGE_TQP_INTR_GL1_REG, ++ HCLGE_TQP_INTR_GL2_REG, ++ HCLGE_TQP_INTR_RL_REG}; ++ ++/* Get DFX BD number offset */ ++#define HCLGE_DFX_BIOS_BD_OFFSET 1 ++#define HCLGE_DFX_SSU_0_BD_OFFSET 2 ++#define HCLGE_DFX_SSU_1_BD_OFFSET 3 ++#define HCLGE_DFX_IGU_BD_OFFSET 4 ++#define HCLGE_DFX_RPU_0_BD_OFFSET 5 ++#define HCLGE_DFX_RPU_1_BD_OFFSET 6 ++#define HCLGE_DFX_NCSI_BD_OFFSET 7 ++#define HCLGE_DFX_RTC_BD_OFFSET 8 ++#define HCLGE_DFX_PPP_BD_OFFSET 9 ++#define HCLGE_DFX_RCB_BD_OFFSET 10 ++#define HCLGE_DFX_TQP_BD_OFFSET 11 ++#define HCLGE_DFX_SSU_2_BD_OFFSET 12 ++ ++static const u32 hclge_dfx_bd_offset_list[] = { ++ HCLGE_DFX_BIOS_BD_OFFSET, ++ HCLGE_DFX_SSU_0_BD_OFFSET, ++ HCLGE_DFX_SSU_1_BD_OFFSET, ++ HCLGE_DFX_IGU_BD_OFFSET, ++ HCLGE_DFX_RPU_0_BD_OFFSET, ++ HCLGE_DFX_RPU_1_BD_OFFSET, ++ HCLGE_DFX_NCSI_BD_OFFSET, ++ HCLGE_DFX_RTC_BD_OFFSET, ++ HCLGE_DFX_PPP_BD_OFFSET, ++ HCLGE_DFX_RCB_BD_OFFSET, ++ HCLGE_DFX_TQP_BD_OFFSET, ++ HCLGE_DFX_SSU_2_BD_OFFSET ++}; ++ ++static const enum hclge_opcode_type hclge_dfx_reg_opcode_list[] = { ++ HCLGE_OPC_DFX_BIOS_COMMON_REG, ++ HCLGE_OPC_DFX_SSU_REG_0, ++ HCLGE_OPC_DFX_SSU_REG_1, ++ HCLGE_OPC_DFX_IGU_EGU_REG, ++ HCLGE_OPC_DFX_RPU_REG_0, ++ HCLGE_OPC_DFX_RPU_REG_1, ++ HCLGE_OPC_DFX_NCSI_REG, ++ HCLGE_OPC_DFX_RTC_REG, ++ HCLGE_OPC_DFX_PPP_REG, ++ HCLGE_OPC_DFX_RCB_REG, ++ HCLGE_OPC_DFX_TQP_REG, ++ HCLGE_OPC_DFX_SSU_REG_2 ++}; ++ ++enum hclge_reg_tag { ++ HCLGE_REG_TAG_CMDQ = 0, ++ HCLGE_REG_TAG_COMMON, ++ HCLGE_REG_TAG_RING, ++ HCLGE_REG_TAG_TQP_INTR, ++ HCLGE_REG_TAG_QUERY_32_BIT, ++ HCLGE_REG_TAG_QUERY_64_BIT, ++ HCLGE_REG_TAG_DFX_BIOS_COMMON, ++ HCLGE_REG_TAG_DFX_SSU_0, ++ HCLGE_REG_TAG_DFX_SSU_1, ++ HCLGE_REG_TAG_DFX_IGU_EGU, ++ HCLGE_REG_TAG_DFX_RPU_0, ++ HCLGE_REG_TAG_DFX_RPU_1, ++ HCLGE_REG_TAG_DFX_NCSI, ++ HCLGE_REG_TAG_DFX_RTC, ++ HCLGE_REG_TAG_DFX_PPP, ++ HCLGE_REG_TAG_DFX_RCB, ++ HCLGE_REG_TAG_DFX_TQP, ++ HCLGE_REG_TAG_DFX_SSU_2, ++ HCLGE_REG_TAG_RPU_TNL, ++}; ++ ++#pragma pack(4) ++struct hclge_reg_tlv { ++ u16 tag; ++ u16 len; ++}; ++ ++struct hclge_reg_header { ++ u64 magic_number; ++ u8 is_vf; ++ u8 rsv[7]; ++}; ++ ++#pragma pack() ++ ++#define HCLGE_REG_TLV_SIZE sizeof(struct hclge_reg_tlv) ++#define HCLGE_REG_HEADER_SIZE sizeof(struct hclge_reg_header) ++#define HCLGE_REG_TLV_SPACE (sizeof(struct hclge_reg_tlv) / sizeof(u32)) ++#define HCLGE_REG_HEADER_SPACE (sizeof(struct hclge_reg_header) / sizeof(u32)) ++#define HCLGE_REG_MAGIC_NUMBER 0x686e733372656773 /* meaning is hns3regs */ ++ ++#define HCLGE_REG_RPU_TNL_ID_0 1 ++ ++static u32 hclge_reg_get_header(void *data) ++{ ++ struct hclge_reg_header *header = data; ++ ++ header->magic_number = HCLGE_REG_MAGIC_NUMBER; ++ header->is_vf = 0x0; ++ ++ return HCLGE_REG_HEADER_SPACE; ++} ++ ++static u32 hclge_reg_get_tlv(u32 tag, u32 regs_num, void *data) ++{ ++ struct hclge_reg_tlv *tlv = data; ++ ++ tlv->tag = tag; ++ tlv->len = regs_num * sizeof(u32) + HCLGE_REG_TLV_SIZE; ++ ++ return HCLGE_REG_TLV_SPACE; ++} ++ ++static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num, ++ void *data) ++{ ++#define HCLGE_32_BIT_REG_RTN_DATANUM 8 ++#define HCLGE_32_BIT_DESC_NODATA_LEN 2 ++ ++ struct hclge_desc *desc; ++ u32 *reg_val = data; ++ __le32 *desc_data; ++ int nodata_num; ++ int cmd_num; ++ int i, k, n; ++ int ret; ++ ++ if (regs_num == 0) ++ return 0; ++ ++ nodata_num = HCLGE_32_BIT_DESC_NODATA_LEN; ++ cmd_num = DIV_ROUND_UP(regs_num + nodata_num, ++ HCLGE_32_BIT_REG_RTN_DATANUM); ++ desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_32_BIT_REG, true); ++ ret = hclge_cmd_send(&hdev->hw, desc, cmd_num); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Query 32 bit register cmd failed, ret = %d.\n", ret); ++ kfree(desc); ++ return ret; ++ } ++ ++ for (i = 0; i < cmd_num; i++) { ++ if (i == 0) { ++ desc_data = (__le32 *)(&desc[i].data[0]); ++ n = HCLGE_32_BIT_REG_RTN_DATANUM - nodata_num; ++ } else { ++ desc_data = (__le32 *)(&desc[i]); ++ n = HCLGE_32_BIT_REG_RTN_DATANUM; ++ } ++ for (k = 0; k < n; k++) { ++ *reg_val++ = le32_to_cpu(*desc_data++); ++ ++ regs_num--; ++ if (!regs_num) ++ break; ++ } ++ } ++ ++ kfree(desc); ++ return 0; ++} ++ ++static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num, ++ void *data) ++{ ++#define HCLGE_64_BIT_REG_RTN_DATANUM 4 ++#define HCLGE_64_BIT_DESC_NODATA_LEN 1 ++ ++ struct hclge_desc *desc; ++ u64 *reg_val = data; ++ __le64 *desc_data; ++ int nodata_len; ++ int cmd_num; ++ int i, k, n; ++ int ret; ++ ++ if (regs_num == 0) ++ return 0; ++ ++ nodata_len = HCLGE_64_BIT_DESC_NODATA_LEN; ++ cmd_num = DIV_ROUND_UP(regs_num + nodata_len, ++ HCLGE_64_BIT_REG_RTN_DATANUM); ++ desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_64_BIT_REG, true); ++ ret = hclge_cmd_send(&hdev->hw, desc, cmd_num); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Query 64 bit register cmd failed, ret = %d.\n", ret); ++ kfree(desc); ++ return ret; ++ } ++ ++ for (i = 0; i < cmd_num; i++) { ++ if (i == 0) { ++ desc_data = (__le64 *)(&desc[i].data[0]); ++ n = HCLGE_64_BIT_REG_RTN_DATANUM - nodata_len; ++ } else { ++ desc_data = (__le64 *)(&desc[i]); ++ n = HCLGE_64_BIT_REG_RTN_DATANUM; ++ } ++ for (k = 0; k < n; k++) { ++ *reg_val++ = le64_to_cpu(*desc_data++); ++ ++ regs_num--; ++ if (!regs_num) ++ break; ++ } ++ } ++ ++ kfree(desc); ++ return 0; ++} ++ ++int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc) ++{ ++ int i; ++ ++ /* initialize command BD except the last one */ ++ for (i = 0; i < HCLGE_GET_DFX_REG_TYPE_CNT - 1; i++) { ++ hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, ++ true); ++ desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); ++ } ++ ++ /* initialize the last command BD */ ++ hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, true); ++ ++ return hclge_cmd_send(&hdev->hw, desc, HCLGE_GET_DFX_REG_TYPE_CNT); ++} ++ ++static int hclge_get_dfx_reg_bd_num(struct hclge_dev *hdev, ++ int *bd_num_list, ++ u32 type_num) ++{ ++ u32 entries_per_desc, desc_index, index, offset, i; ++ struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT]; ++ int ret; ++ ++ ret = hclge_query_bd_num_cmd_send(hdev, desc); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get dfx bd num fail, status is %d.\n", ret); ++ return ret; ++ } ++ ++ entries_per_desc = ARRAY_SIZE(desc[0].data); ++ for (i = 0; i < type_num; i++) { ++ offset = hclge_dfx_bd_offset_list[i]; ++ index = offset % entries_per_desc; ++ desc_index = offset / entries_per_desc; ++ bd_num_list[i] = le32_to_cpu(desc[desc_index].data[index]); ++ } ++ ++ return ret; ++} ++ ++static int hclge_dfx_reg_cmd_send(struct hclge_dev *hdev, ++ struct hclge_desc *desc_src, int bd_num, ++ enum hclge_opcode_type cmd) ++{ ++ struct hclge_desc *desc = desc_src; ++ int i, ret; ++ ++ hclge_cmd_setup_basic_desc(desc, cmd, true); ++ for (i = 0; i < bd_num - 1; i++) { ++ desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); ++ desc++; ++ hclge_cmd_setup_basic_desc(desc, cmd, true); ++ } ++ ++ desc = desc_src; ++ ret = hclge_cmd_send(&hdev->hw, desc, bd_num); ++ if (ret) ++ dev_err(&hdev->pdev->dev, ++ "Query dfx reg cmd(0x%x) send fail, status is %d.\n", ++ cmd, ret); ++ ++ return ret; ++} ++ ++/* tnl_id = 0 means get sum of all tnl reg's value */ ++static int hclge_dfx_reg_rpu_tnl_cmd_send(struct hclge_dev *hdev, u32 tnl_id, ++ struct hclge_desc *desc, int bd_num) ++{ ++ int i, ret; ++ ++ for (i = 0; i < bd_num; i++) { ++ hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_RPU_REG_0, ++ true); ++ if (i != bd_num - 1) ++ desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); ++ } ++ ++ desc[0].data[0] = cpu_to_le32(tnl_id); ++ ret = hclge_cmd_send(&hdev->hw, desc, bd_num); ++ if (ret) ++ dev_err(&hdev->pdev->dev, ++ "failed to query dfx rpu tnl reg, ret = %d\n", ++ ret); ++ return ret; ++} ++ ++static int hclge_dfx_reg_fetch_data(struct hclge_desc *desc_src, int bd_num, ++ void *data) ++{ ++ int entries_per_desc, reg_num, desc_index, index, i; ++ struct hclge_desc *desc = desc_src; ++ u32 *reg = data; ++ ++ entries_per_desc = ARRAY_SIZE(desc->data); ++ reg_num = entries_per_desc * bd_num; ++ for (i = 0; i < reg_num; i++) { ++ index = i % entries_per_desc; ++ desc_index = i / entries_per_desc; ++ *reg++ = le32_to_cpu(desc[desc_index].data[index]); ++ } ++ ++ return reg_num; ++} ++ ++static int hclge_get_dfx_reg_len(struct hclge_dev *hdev, int *len) ++{ ++ u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list); ++ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); ++ int data_len_per_desc; ++ int *bd_num_list; ++ int ret; ++ u32 i; ++ ++ bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL); ++ if (!bd_num_list) ++ return -ENOMEM; ++ ++ ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get dfx reg bd num fail, status is %d.\n", ret); ++ goto out; ++ } ++ ++ data_len_per_desc = sizeof_field(struct hclge_desc, data); ++ *len = 0; ++ for (i = 0; i < dfx_reg_type_num; i++) ++ *len += bd_num_list[i] * data_len_per_desc + HCLGE_REG_TLV_SIZE; ++ ++ /** ++ * the num of dfx_rpu_0 is reused by each dfx_rpu_tnl ++ * HCLGE_DFX_BD_OFFSET is starting at 1, but the array subscript is ++ * starting at 0, so offset need '- 1'. ++ */ ++ *len += (bd_num_list[HCLGE_DFX_RPU_0_BD_OFFSET - 1] * data_len_per_desc + ++ HCLGE_REG_TLV_SIZE) * ae_dev->dev_specs.tnl_num; ++ ++out: ++ kfree(bd_num_list); ++ return ret; ++} ++ ++static int hclge_get_dfx_rpu_tnl_reg(struct hclge_dev *hdev, u32 *reg, ++ struct hclge_desc *desc_src, ++ int bd_num) ++{ ++ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); ++ int ret = 0; ++ u8 i; ++ ++ for (i = HCLGE_REG_RPU_TNL_ID_0; i <= ae_dev->dev_specs.tnl_num; i++) { ++ ret = hclge_dfx_reg_rpu_tnl_cmd_send(hdev, i, desc_src, bd_num); ++ if (ret) ++ break; ++ ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_RPU_TNL, ++ ARRAY_SIZE(desc_src->data) * bd_num, ++ reg); ++ reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg); ++ } ++ ++ return ret; ++} ++ ++static int hclge_get_dfx_reg(struct hclge_dev *hdev, void *data) ++{ ++ u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list); ++ int bd_num, bd_num_max, buf_len; ++ struct hclge_desc *desc_src; ++ int *bd_num_list; ++ u32 *reg = data; ++ int ret; ++ u32 i; ++ ++ bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL); ++ if (!bd_num_list) ++ return -ENOMEM; ++ ++ ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get dfx reg bd num fail, status is %d.\n", ret); ++ goto out; ++ } ++ ++ bd_num_max = bd_num_list[0]; ++ for (i = 1; i < dfx_reg_type_num; i++) ++ bd_num_max = max_t(int, bd_num_max, bd_num_list[i]); ++ ++ buf_len = sizeof(*desc_src) * bd_num_max; ++ desc_src = kzalloc(buf_len, GFP_KERNEL); ++ if (!desc_src) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ for (i = 0; i < dfx_reg_type_num; i++) { ++ bd_num = bd_num_list[i]; ++ ret = hclge_dfx_reg_cmd_send(hdev, desc_src, bd_num, ++ hclge_dfx_reg_opcode_list[i]); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get dfx reg fail, status is %d.\n", ret); ++ goto free; ++ } ++ ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_DFX_BIOS_COMMON + i, ++ ARRAY_SIZE(desc_src->data) * bd_num, ++ reg); ++ reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg); ++ } ++ ++ /** ++ * HCLGE_DFX_BD_OFFSET is starting at 1, but the array subscript is ++ * starting at 0, so offset need '- 1'. ++ */ ++ bd_num = bd_num_list[HCLGE_DFX_RPU_0_BD_OFFSET - 1]; ++ ret = hclge_get_dfx_rpu_tnl_reg(hdev, reg, desc_src, bd_num); ++ ++free: ++ kfree(desc_src); ++out: ++ kfree(bd_num_list); ++ return ret; ++} ++ ++static int hclge_fetch_pf_reg(struct hclge_dev *hdev, void *data, ++ struct hnae3_knic_private_info *kinfo) ++{ ++#define HCLGE_RING_REG_OFFSET 0x200 ++#define HCLGE_RING_INT_REG_OFFSET 0x4 ++ ++ int i, j, reg_num; ++ int data_num_sum; ++ u32 *reg = data; ++ ++ /* fetching per-PF registers valus from PF PCIe register space */ ++ reg_num = ARRAY_SIZE(cmdq_reg_addr_list); ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_CMDQ, reg_num, reg); ++ for (i = 0; i < reg_num; i++) ++ *reg++ = hclge_read_dev(&hdev->hw, cmdq_reg_addr_list[i]); ++ data_num_sum = reg_num + HCLGE_REG_TLV_SPACE; ++ ++ reg_num = ARRAY_SIZE(common_reg_addr_list); ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_COMMON, reg_num, reg); ++ for (i = 0; i < reg_num; i++) ++ *reg++ = hclge_read_dev(&hdev->hw, common_reg_addr_list[i]); ++ data_num_sum += reg_num + HCLGE_REG_TLV_SPACE; ++ ++ reg_num = ARRAY_SIZE(ring_reg_addr_list); ++ for (j = 0; j < kinfo->num_tqps; j++) { ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_RING, reg_num, reg); ++ for (i = 0; i < reg_num; i++) ++ *reg++ = hclge_read_dev(&hdev->hw, ++ ring_reg_addr_list[i] + ++ HCLGE_RING_REG_OFFSET * j); ++ } ++ data_num_sum += (reg_num + HCLGE_REG_TLV_SPACE) * kinfo->num_tqps; ++ ++ reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list); ++ for (j = 0; j < hdev->num_msi_used - 1; j++) { ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_TQP_INTR, reg_num, reg); ++ for (i = 0; i < reg_num; i++) ++ *reg++ = hclge_read_dev(&hdev->hw, ++ tqp_intr_reg_addr_list[i] + ++ HCLGE_RING_INT_REG_OFFSET * j); ++ } ++ data_num_sum += (reg_num + HCLGE_REG_TLV_SPACE) * ++ (hdev->num_msi_used - 1); ++ ++ return data_num_sum; ++} ++ ++static int hclge_get_regs_num(struct hclge_dev *hdev, u32 *regs_num_32_bit, ++ u32 *regs_num_64_bit) ++{ ++ struct hclge_desc desc; ++ u32 total_num; ++ int ret; ++ ++ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_REG_NUM, true); ++ ret = hclge_cmd_send(&hdev->hw, &desc, 1); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Query register number cmd failed, ret = %d.\n", ret); ++ return ret; ++ } ++ ++ *regs_num_32_bit = le32_to_cpu(desc.data[0]); ++ *regs_num_64_bit = le32_to_cpu(desc.data[1]); ++ ++ total_num = *regs_num_32_bit + *regs_num_64_bit; ++ if (!total_num) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++int hclge_get_regs_len(struct hnae3_handle *handle) ++{ ++ struct hnae3_knic_private_info *kinfo = &handle->kinfo; ++ struct hclge_vport *vport = hclge_get_vport(handle); ++ int regs_num_32_bit, regs_num_64_bit, dfx_regs_len; ++ int cmdq_len, common_len, ring_len, tqp_intr_len; ++ int regs_len_32_bit, regs_len_64_bit; ++ struct hclge_dev *hdev = vport->back; ++ int ret; ++ ++ ret = hclge_get_regs_num(hdev, ®s_num_32_bit, ®s_num_64_bit); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get register number failed, ret = %d.\n", ret); ++ return ret; ++ } ++ ++ ret = hclge_get_dfx_reg_len(hdev, &dfx_regs_len); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get dfx reg len failed, ret = %d.\n", ret); ++ return ret; ++ } ++ ++ cmdq_len = HCLGE_REG_TLV_SIZE + sizeof(cmdq_reg_addr_list); ++ common_len = HCLGE_REG_TLV_SIZE + sizeof(common_reg_addr_list); ++ ring_len = HCLGE_REG_TLV_SIZE + sizeof(ring_reg_addr_list); ++ tqp_intr_len = HCLGE_REG_TLV_SIZE + sizeof(tqp_intr_reg_addr_list); ++ regs_len_32_bit = HCLGE_REG_TLV_SIZE + regs_num_32_bit * sizeof(u32); ++ regs_len_64_bit = HCLGE_REG_TLV_SIZE + regs_num_64_bit * sizeof(u64); ++ ++ /* return the total length of all register values */ ++ return HCLGE_REG_HEADER_SIZE + cmdq_len + common_len + ring_len * ++ kinfo->num_tqps + tqp_intr_len * (hdev->num_msi_used - 1) + ++ regs_len_32_bit + regs_len_64_bit + dfx_regs_len; ++} ++ ++void hclge_get_regs(struct hnae3_handle *handle, u32 *version, ++ void *data) ++{ ++#define HCLGE_REG_64_BIT_SPACE_MULTIPLE 2 ++ ++ struct hnae3_knic_private_info *kinfo = &handle->kinfo; ++ struct hclge_vport *vport = hclge_get_vport(handle); ++ struct hclge_dev *hdev = vport->back; ++ u32 regs_num_32_bit, regs_num_64_bit; ++ u32 *reg = data; ++ int ret; ++ ++ *version = hdev->fw_version; ++ ++ ret = hclge_get_regs_num(hdev, ®s_num_32_bit, ®s_num_64_bit); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get register number failed, ret = %d.\n", ret); ++ return; ++ } ++ ++ reg += hclge_reg_get_header(reg); ++ reg += hclge_fetch_pf_reg(hdev, reg, kinfo); ++ ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_QUERY_32_BIT, ++ regs_num_32_bit, reg); ++ ret = hclge_get_32_bit_regs(hdev, regs_num_32_bit, reg); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get 32 bit register failed, ret = %d.\n", ret); ++ return; ++ } ++ reg += regs_num_32_bit; ++ ++ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_QUERY_64_BIT, ++ regs_num_64_bit * ++ HCLGE_REG_64_BIT_SPACE_MULTIPLE, reg); ++ ret = hclge_get_64_bit_regs(hdev, regs_num_64_bit, reg); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "Get 64 bit register failed, ret = %d.\n", ret); ++ return; ++ } ++ reg += regs_num_64_bit * HCLGE_REG_64_BIT_SPACE_MULTIPLE; ++ ++ ret = hclge_get_dfx_reg(hdev, reg); ++ if (ret) ++ dev_err(&hdev->pdev->dev, ++ "Get dfx register failed, ret = %d.\n", ret); ++} +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h +new file mode 100644 +index 0000000000000..b6bc1ecb8054e +--- /dev/null ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++// Copyright (c) 2023 Hisilicon Limited. ++ ++#ifndef __HCLGE_REGS_H ++#define __HCLGE_REGS_H ++#include <linux/types.h> ++#include "hclge_comm_cmd.h" ++ ++struct hnae3_handle; ++struct hclge_dev; ++ ++int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, ++ struct hclge_desc *desc); ++int hclge_get_regs_len(struct hnae3_handle *handle); ++void hclge_get_regs(struct hnae3_handle *handle, u32 *version, ++ void *data); ++#endif +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +index 150f146fa24fb..c58c312217628 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +@@ -1485,7 +1485,11 @@ int hclge_tm_schd_setup_hw(struct hclge_dev *hdev) + return ret; + + /* Cfg schd mode for each level schd */ +- return hclge_tm_schd_mode_hw(hdev); ++ ret = hclge_tm_schd_mode_hw(hdev); ++ if (ret) ++ return ret; ++ ++ return hclge_tm_flush_cfg(hdev, false); + } + + static int hclge_pause_param_setup_hw(struct hclge_dev *hdev) +@@ -1549,7 +1553,7 @@ static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc) + return 0; + } + +-static int hclge_mac_pause_setup_hw(struct hclge_dev *hdev) ++int hclge_mac_pause_setup_hw(struct hclge_dev *hdev) + { + bool tx_en, rx_en; + +@@ -2114,3 +2118,28 @@ int hclge_tm_get_port_shaper(struct hclge_dev *hdev, + + return 0; + } ++ ++int hclge_tm_flush_cfg(struct hclge_dev *hdev, bool enable) ++{ ++ struct hclge_desc desc; ++ int ret; ++ ++ if (!hnae3_ae_dev_tm_flush_supported(hdev)) ++ return 0; ++ ++ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_FLUSH, false); ++ ++ desc.data[0] = cpu_to_le32(enable ? HCLGE_TM_FLUSH_EN_MSK : 0); ++ ++ ret = hclge_cmd_send(&hdev->hw, &desc, 1); ++ if (ret) { ++ dev_err(&hdev->pdev->dev, ++ "failed to config tm flush, ret = %d\n", ret); ++ return ret; ++ } ++ ++ if (enable) ++ msleep(HCLGE_TM_FLUSH_TIME_MS); ++ ++ return ret; ++} +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +index dd6f1fd486cf2..53eec6df51946 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +@@ -33,6 +33,9 @@ enum hclge_opcode_type; + #define HCLGE_DSCP_MAP_TC_BD_NUM 2 + #define HCLGE_DSCP_TC_SHIFT(n) (((n) & 1) * 4) + ++#define HCLGE_TM_FLUSH_TIME_MS 10 ++#define HCLGE_TM_FLUSH_EN_MSK BIT(0) ++ + struct hclge_pg_to_pri_link_cmd { + u8 pg_id; + u8 rsvd1[3]; +@@ -242,6 +245,7 @@ int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap, + u8 pfc_bitmap); + int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx); + int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr); ++int hclge_mac_pause_setup_hw(struct hclge_dev *hdev); + void hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats); + void hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats); + int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate); +@@ -272,4 +276,5 @@ int hclge_tm_get_port_shaper(struct hclge_dev *hdev, + struct hclge_tm_shaper_para *para); + int hclge_up_to_tc_map(struct hclge_dev *hdev); + int hclge_dscp_to_tc_map(struct hclge_dev *hdev); ++int hclge_tm_flush_cfg(struct hclge_dev *hdev, bool enable); + #endif +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +index dd08989a4c7c1..de42a0e1b54b8 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +@@ -6,6 +6,7 @@ + #include <net/rtnetlink.h> + #include "hclgevf_cmd.h" + #include "hclgevf_main.h" ++#include "hclgevf_regs.h" + #include "hclge_mbx.h" + #include "hnae3.h" + #include "hclgevf_devlink.h" +@@ -33,58 +34,6 @@ static const struct pci_device_id ae_algovf_pci_tbl[] = { + + MODULE_DEVICE_TABLE(pci, ae_algovf_pci_tbl); + +-static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG, +- HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG, +- HCLGE_COMM_NIC_CSQ_DEPTH_REG, +- HCLGE_COMM_NIC_CSQ_TAIL_REG, +- HCLGE_COMM_NIC_CSQ_HEAD_REG, +- HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG, +- HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG, +- HCLGE_COMM_NIC_CRQ_DEPTH_REG, +- HCLGE_COMM_NIC_CRQ_TAIL_REG, +- HCLGE_COMM_NIC_CRQ_HEAD_REG, +- HCLGE_COMM_VECTOR0_CMDQ_SRC_REG, +- HCLGE_COMM_VECTOR0_CMDQ_STATE_REG, +- HCLGE_COMM_CMDQ_INTR_EN_REG, +- HCLGE_COMM_CMDQ_INTR_GEN_REG}; +- +-static const u32 common_reg_addr_list[] = {HCLGEVF_MISC_VECTOR_REG_BASE, +- HCLGEVF_RST_ING, +- HCLGEVF_GRO_EN_REG}; +- +-static const u32 ring_reg_addr_list[] = {HCLGEVF_RING_RX_ADDR_L_REG, +- HCLGEVF_RING_RX_ADDR_H_REG, +- HCLGEVF_RING_RX_BD_NUM_REG, +- HCLGEVF_RING_RX_BD_LENGTH_REG, +- HCLGEVF_RING_RX_MERGE_EN_REG, +- HCLGEVF_RING_RX_TAIL_REG, +- HCLGEVF_RING_RX_HEAD_REG, +- HCLGEVF_RING_RX_FBD_NUM_REG, +- HCLGEVF_RING_RX_OFFSET_REG, +- HCLGEVF_RING_RX_FBD_OFFSET_REG, +- HCLGEVF_RING_RX_STASH_REG, +- HCLGEVF_RING_RX_BD_ERR_REG, +- HCLGEVF_RING_TX_ADDR_L_REG, +- HCLGEVF_RING_TX_ADDR_H_REG, +- HCLGEVF_RING_TX_BD_NUM_REG, +- HCLGEVF_RING_TX_PRIORITY_REG, +- HCLGEVF_RING_TX_TC_REG, +- HCLGEVF_RING_TX_MERGE_EN_REG, +- HCLGEVF_RING_TX_TAIL_REG, +- HCLGEVF_RING_TX_HEAD_REG, +- HCLGEVF_RING_TX_FBD_NUM_REG, +- HCLGEVF_RING_TX_OFFSET_REG, +- HCLGEVF_RING_TX_EBD_NUM_REG, +- HCLGEVF_RING_TX_EBD_OFFSET_REG, +- HCLGEVF_RING_TX_BD_ERR_REG, +- HCLGEVF_RING_EN_REG}; +- +-static const u32 tqp_intr_reg_addr_list[] = {HCLGEVF_TQP_INTR_CTRL_REG, +- HCLGEVF_TQP_INTR_GL0_REG, +- HCLGEVF_TQP_INTR_GL1_REG, +- HCLGEVF_TQP_INTR_GL2_REG, +- HCLGEVF_TQP_INTR_RL_REG}; +- + /* hclgevf_cmd_send - send command to command queue + * @hw: pointer to the hw struct + * @desc: prefilled descriptor for describing the command +@@ -111,7 +60,7 @@ void hclgevf_arq_init(struct hclgevf_dev *hdev) + spin_unlock(&cmdq->crq.lock); + } + +-static struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle) ++struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle) + { + if (!handle->client) + return container_of(handle, struct hclgevf_dev, nic); +@@ -3262,72 +3211,6 @@ static void hclgevf_get_link_mode(struct hnae3_handle *handle, + *advertising = hdev->hw.mac.advertising; + } + +-#define MAX_SEPARATE_NUM 4 +-#define SEPARATOR_VALUE 0xFDFCFBFA +-#define REG_NUM_PER_LINE 4 +-#define REG_LEN_PER_LINE (REG_NUM_PER_LINE * sizeof(u32)) +- +-static int hclgevf_get_regs_len(struct hnae3_handle *handle) +-{ +- int cmdq_lines, common_lines, ring_lines, tqp_intr_lines; +- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); +- +- cmdq_lines = sizeof(cmdq_reg_addr_list) / REG_LEN_PER_LINE + 1; +- common_lines = sizeof(common_reg_addr_list) / REG_LEN_PER_LINE + 1; +- ring_lines = sizeof(ring_reg_addr_list) / REG_LEN_PER_LINE + 1; +- tqp_intr_lines = sizeof(tqp_intr_reg_addr_list) / REG_LEN_PER_LINE + 1; +- +- return (cmdq_lines + common_lines + ring_lines * hdev->num_tqps + +- tqp_intr_lines * (hdev->num_msi_used - 1)) * REG_LEN_PER_LINE; +-} +- +-static void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version, +- void *data) +-{ +- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); +- int i, j, reg_um, separator_num; +- u32 *reg = data; +- +- *version = hdev->fw_version; +- +- /* fetching per-VF registers values from VF PCIe register space */ +- reg_um = sizeof(cmdq_reg_addr_list) / sizeof(u32); +- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; +- for (i = 0; i < reg_um; i++) +- *reg++ = hclgevf_read_dev(&hdev->hw, cmdq_reg_addr_list[i]); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- +- reg_um = sizeof(common_reg_addr_list) / sizeof(u32); +- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; +- for (i = 0; i < reg_um; i++) +- *reg++ = hclgevf_read_dev(&hdev->hw, common_reg_addr_list[i]); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- +- reg_um = sizeof(ring_reg_addr_list) / sizeof(u32); +- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; +- for (j = 0; j < hdev->num_tqps; j++) { +- for (i = 0; i < reg_um; i++) +- *reg++ = hclgevf_read_dev(&hdev->hw, +- ring_reg_addr_list[i] + +- HCLGEVF_TQP_REG_SIZE * j); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- } +- +- reg_um = sizeof(tqp_intr_reg_addr_list) / sizeof(u32); +- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; +- for (j = 0; j < hdev->num_msi_used - 1; j++) { +- for (i = 0; i < reg_um; i++) +- *reg++ = hclgevf_read_dev(&hdev->hw, +- tqp_intr_reg_addr_list[i] + +- 4 * j); +- for (i = 0; i < separator_num; i++) +- *reg++ = SEPARATOR_VALUE; +- } +-} +- + void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state, + struct hclge_mbx_port_base_vlan *port_base_vlan) + { +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +index 59ca6c794d6db..81c16b8c8da29 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +@@ -294,4 +294,5 @@ void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev); + void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev); + void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state, + struct hclge_mbx_port_base_vlan *port_base_vlan); ++struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle); + #endif +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c +new file mode 100644 +index 0000000000000..197ab733306b5 +--- /dev/null ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c +@@ -0,0 +1,127 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2023 Hisilicon Limited. ++ ++#include "hclgevf_main.h" ++#include "hclgevf_regs.h" ++#include "hnae3.h" ++ ++static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG, ++ HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG, ++ HCLGE_COMM_NIC_CSQ_DEPTH_REG, ++ HCLGE_COMM_NIC_CSQ_TAIL_REG, ++ HCLGE_COMM_NIC_CSQ_HEAD_REG, ++ HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG, ++ HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG, ++ HCLGE_COMM_NIC_CRQ_DEPTH_REG, ++ HCLGE_COMM_NIC_CRQ_TAIL_REG, ++ HCLGE_COMM_NIC_CRQ_HEAD_REG, ++ HCLGE_COMM_VECTOR0_CMDQ_SRC_REG, ++ HCLGE_COMM_VECTOR0_CMDQ_STATE_REG, ++ HCLGE_COMM_CMDQ_INTR_EN_REG, ++ HCLGE_COMM_CMDQ_INTR_GEN_REG}; ++ ++static const u32 common_reg_addr_list[] = {HCLGEVF_MISC_VECTOR_REG_BASE, ++ HCLGEVF_RST_ING, ++ HCLGEVF_GRO_EN_REG}; ++ ++static const u32 ring_reg_addr_list[] = {HCLGEVF_RING_RX_ADDR_L_REG, ++ HCLGEVF_RING_RX_ADDR_H_REG, ++ HCLGEVF_RING_RX_BD_NUM_REG, ++ HCLGEVF_RING_RX_BD_LENGTH_REG, ++ HCLGEVF_RING_RX_MERGE_EN_REG, ++ HCLGEVF_RING_RX_TAIL_REG, ++ HCLGEVF_RING_RX_HEAD_REG, ++ HCLGEVF_RING_RX_FBD_NUM_REG, ++ HCLGEVF_RING_RX_OFFSET_REG, ++ HCLGEVF_RING_RX_FBD_OFFSET_REG, ++ HCLGEVF_RING_RX_STASH_REG, ++ HCLGEVF_RING_RX_BD_ERR_REG, ++ HCLGEVF_RING_TX_ADDR_L_REG, ++ HCLGEVF_RING_TX_ADDR_H_REG, ++ HCLGEVF_RING_TX_BD_NUM_REG, ++ HCLGEVF_RING_TX_PRIORITY_REG, ++ HCLGEVF_RING_TX_TC_REG, ++ HCLGEVF_RING_TX_MERGE_EN_REG, ++ HCLGEVF_RING_TX_TAIL_REG, ++ HCLGEVF_RING_TX_HEAD_REG, ++ HCLGEVF_RING_TX_FBD_NUM_REG, ++ HCLGEVF_RING_TX_OFFSET_REG, ++ HCLGEVF_RING_TX_EBD_NUM_REG, ++ HCLGEVF_RING_TX_EBD_OFFSET_REG, ++ HCLGEVF_RING_TX_BD_ERR_REG, ++ HCLGEVF_RING_EN_REG}; ++ ++static const u32 tqp_intr_reg_addr_list[] = {HCLGEVF_TQP_INTR_CTRL_REG, ++ HCLGEVF_TQP_INTR_GL0_REG, ++ HCLGEVF_TQP_INTR_GL1_REG, ++ HCLGEVF_TQP_INTR_GL2_REG, ++ HCLGEVF_TQP_INTR_RL_REG}; ++ ++#define MAX_SEPARATE_NUM 4 ++#define SEPARATOR_VALUE 0xFDFCFBFA ++#define REG_NUM_PER_LINE 4 ++#define REG_LEN_PER_LINE (REG_NUM_PER_LINE * sizeof(u32)) ++ ++int hclgevf_get_regs_len(struct hnae3_handle *handle) ++{ ++ int cmdq_lines, common_lines, ring_lines, tqp_intr_lines; ++ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); ++ ++ cmdq_lines = sizeof(cmdq_reg_addr_list) / REG_LEN_PER_LINE + 1; ++ common_lines = sizeof(common_reg_addr_list) / REG_LEN_PER_LINE + 1; ++ ring_lines = sizeof(ring_reg_addr_list) / REG_LEN_PER_LINE + 1; ++ tqp_intr_lines = sizeof(tqp_intr_reg_addr_list) / REG_LEN_PER_LINE + 1; ++ ++ return (cmdq_lines + common_lines + ring_lines * hdev->num_tqps + ++ tqp_intr_lines * (hdev->num_msi_used - 1)) * REG_LEN_PER_LINE; ++} ++ ++void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version, ++ void *data) ++{ ++#define HCLGEVF_RING_REG_OFFSET 0x200 ++#define HCLGEVF_RING_INT_REG_OFFSET 0x4 ++ ++ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); ++ int i, j, reg_um, separator_num; ++ u32 *reg = data; ++ ++ *version = hdev->fw_version; ++ ++ /* fetching per-VF registers values from VF PCIe register space */ ++ reg_um = sizeof(cmdq_reg_addr_list) / sizeof(u32); ++ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; ++ for (i = 0; i < reg_um; i++) ++ *reg++ = hclgevf_read_dev(&hdev->hw, cmdq_reg_addr_list[i]); ++ for (i = 0; i < separator_num; i++) ++ *reg++ = SEPARATOR_VALUE; ++ ++ reg_um = sizeof(common_reg_addr_list) / sizeof(u32); ++ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; ++ for (i = 0; i < reg_um; i++) ++ *reg++ = hclgevf_read_dev(&hdev->hw, common_reg_addr_list[i]); ++ for (i = 0; i < separator_num; i++) ++ *reg++ = SEPARATOR_VALUE; ++ ++ reg_um = sizeof(ring_reg_addr_list) / sizeof(u32); ++ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; ++ for (j = 0; j < hdev->num_tqps; j++) { ++ for (i = 0; i < reg_um; i++) ++ *reg++ = hclgevf_read_dev(&hdev->hw, ++ ring_reg_addr_list[i] + ++ HCLGEVF_RING_REG_OFFSET * j); ++ for (i = 0; i < separator_num; i++) ++ *reg++ = SEPARATOR_VALUE; ++ } ++ ++ reg_um = sizeof(tqp_intr_reg_addr_list) / sizeof(u32); ++ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE; ++ for (j = 0; j < hdev->num_msi_used - 1; j++) { ++ for (i = 0; i < reg_um; i++) ++ *reg++ = hclgevf_read_dev(&hdev->hw, ++ tqp_intr_reg_addr_list[i] + ++ HCLGEVF_RING_INT_REG_OFFSET * j); ++ for (i = 0; i < separator_num; i++) ++ *reg++ = SEPARATOR_VALUE; ++ } ++} +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h +new file mode 100644 +index 0000000000000..77bdcf60a1afe +--- /dev/null ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* Copyright (c) 2023 Hisilicon Limited. */ ++ ++#ifndef __HCLGEVF_REGS_H ++#define __HCLGEVF_REGS_H ++#include <linux/types.h> ++ ++struct hnae3_handle; ++ ++int hclgevf_get_regs_len(struct hnae3_handle *handle); ++void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version, ++ void *data); ++#endif +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index cfb76612bd2f9..66bd06ea0a703 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -1346,6 +1346,7 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout, + static void ice_aq_check_events(struct ice_pf *pf, u16 opcode, + struct ice_rq_event_info *event) + { ++ struct ice_rq_event_info *task_ev; + struct ice_aq_task *task; + bool found = false; + +@@ -1354,15 +1355,15 @@ static void ice_aq_check_events(struct ice_pf *pf, u16 opcode, + if (task->state || task->opcode != opcode) + continue; + +- memcpy(&task->event->desc, &event->desc, sizeof(event->desc)); +- task->event->msg_len = event->msg_len; ++ task_ev = task->event; ++ memcpy(&task_ev->desc, &event->desc, sizeof(event->desc)); ++ task_ev->msg_len = event->msg_len; + + /* Only copy the data buffer if a destination was set */ +- if (task->event->msg_buf && +- task->event->buf_len > event->buf_len) { +- memcpy(task->event->msg_buf, event->msg_buf, ++ if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) { ++ memcpy(task_ev->msg_buf, event->msg_buf, + event->buf_len); +- task->event->buf_len = event->buf_len; ++ task_ev->buf_len = event->buf_len; + } + + task->state = ICE_AQ_TASK_COMPLETE; +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index a38614d21ea8f..de1d83300481d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -131,6 +131,8 @@ static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) + case READ_TIME: + cmd_val |= GLTSYN_CMD_READ_TIME; + break; ++ case ICE_PTP_NOP: ++ break; + } + + wr32(hw, GLTSYN_CMD, cmd_val); +@@ -1226,18 +1228,18 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) + } + + /** +- * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command ++ * ice_ptp_write_port_cmd_e822 - Prepare a single PHY port for a timer command + * @hw: pointer to HW struct + * @port: Port to which cmd has to be sent + * @cmd: Command to be sent to the port + * + * Prepare the requested port for an upcoming timer sync command. + * +- * Note there is no equivalent of this operation on E810, as that device +- * always handles all external PHYs internally. ++ * Do not use this function directly. If you want to configure exactly one ++ * port, use ice_ptp_one_port_cmd() instead. + */ + static int +-ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) ++ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) + { + u32 cmd_val, val; + u8 tmr_idx; +@@ -1261,6 +1263,8 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) + case ADJ_TIME_AT_TIME: + cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; + break; ++ case ICE_PTP_NOP: ++ break; + } + + /* Tx case */ +@@ -1306,6 +1310,39 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) + return 0; + } + ++/** ++ * ice_ptp_one_port_cmd - Prepare one port for a timer command ++ * @hw: pointer to the HW struct ++ * @configured_port: the port to configure with configured_cmd ++ * @configured_cmd: timer command to prepare on the configured_port ++ * ++ * Prepare the configured_port for the configured_cmd, and prepare all other ++ * ports for ICE_PTP_NOP. This causes the configured_port to execute the ++ * desired command while all other ports perform no operation. ++ */ ++static int ++ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, ++ enum ice_ptp_tmr_cmd configured_cmd) ++{ ++ u8 port; ++ ++ for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { ++ enum ice_ptp_tmr_cmd cmd; ++ int err; ++ ++ if (port == configured_port) ++ cmd = configured_cmd; ++ else ++ cmd = ICE_PTP_NOP; ++ ++ err = ice_ptp_write_port_cmd_e822(hw, port, cmd); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ + /** + * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command + * @hw: pointer to the HW struct +@@ -1322,7 +1359,7 @@ ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) + for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { + int err; + +- err = ice_ptp_one_port_cmd(hw, port, cmd); ++ err = ice_ptp_write_port_cmd_e822(hw, port, cmd); + if (err) + return err; + } +@@ -2252,6 +2289,9 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) + if (err) + goto err_unlock; + ++ /* Do not perform any action on the main timer */ ++ ice_ptp_src_cmd(hw, ICE_PTP_NOP); ++ + /* Issue the sync to activate the time adjustment */ + ice_ptp_exec_tmr_cmd(hw); + +@@ -2372,6 +2412,9 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) + if (err) + return err; + ++ /* Do not perform any action on the main timer */ ++ ice_ptp_src_cmd(hw, ICE_PTP_NOP); ++ + ice_ptp_exec_tmr_cmd(hw); + + err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); +@@ -2847,6 +2890,8 @@ static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) + case ADJ_TIME_AT_TIME: + cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; + break; ++ case ICE_PTP_NOP: ++ return 0; + } + + /* Read, modify, write */ +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +index 3b68cb91bd819..096685237ca61 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +@@ -9,7 +9,8 @@ enum ice_ptp_tmr_cmd { + INIT_INCVAL, + ADJ_TIME, + ADJ_TIME_AT_TIME, +- READ_TIME ++ READ_TIME, ++ ICE_PTP_NOP, + }; + + enum ice_ptp_serdes { +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index ba5e1d1320f67..c7da6cfc00a33 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -4812,6 +4812,10 @@ void igb_configure_rx_ring(struct igb_adapter *adapter, + static void igb_set_rx_buffer_len(struct igb_adapter *adapter, + struct igb_ring *rx_ring) + { ++#if (PAGE_SIZE < 8192) ++ struct e1000_hw *hw = &adapter->hw; ++#endif ++ + /* set build_skb and buffer size flags */ + clear_ring_build_skb_enabled(rx_ring); + clear_ring_uses_large_buffer(rx_ring); +@@ -4822,10 +4826,9 @@ static void igb_set_rx_buffer_len(struct igb_adapter *adapter, + set_ring_build_skb_enabled(rx_ring); + + #if (PAGE_SIZE < 8192) +- if (adapter->max_frame_size <= IGB_MAX_FRAME_BUILD_SKB) +- return; +- +- set_ring_uses_large_buffer(rx_ring); ++ if (adapter->max_frame_size > IGB_MAX_FRAME_BUILD_SKB || ++ rd32(E1000_RCTL) & E1000_RCTL_SBP) ++ set_ring_uses_large_buffer(rx_ring); + #endif + } + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c +index b4fcb20c3f4fd..af21e2030cff2 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c +@@ -355,8 +355,8 @@ int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause, + + void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable) + { ++ u64 cfg, pfc_class_mask_cfg; + rpm_t *rpm = rpmd; +- u64 cfg; + + /* ALL pause frames received are completely ignored */ + cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); +@@ -380,9 +380,11 @@ void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable) + rpm_write(rpm, 0, RPMX_CMR_CHAN_MSK_OR, ~0ULL); + + /* Disable all PFC classes */ +- cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL); ++ pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL : ++ RPMX_CMRX_PRT_CBFC_CTL; ++ cfg = rpm_read(rpm, lmac_id, pfc_class_mask_cfg); + cfg = FIELD_SET(RPM_PFC_CLASS_MASK, 0, cfg); +- rpm_write(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL, cfg); ++ rpm_write(rpm, lmac_id, pfc_class_mask_cfg, cfg); + } + + int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat) +@@ -605,8 +607,11 @@ int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 p + if (!is_lmac_valid(rpm, lmac_id)) + return -ENODEV; + ++ pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL : ++ RPMX_CMRX_PRT_CBFC_CTL; ++ + cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); +- class_en = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL); ++ class_en = rpm_read(rpm, lmac_id, pfc_class_mask_cfg); + pfc_en |= FIELD_GET(RPM_PFC_CLASS_MASK, class_en); + + if (rx_pause) { +@@ -635,10 +640,6 @@ int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 p + cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; + + rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); +- +- pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL : +- RPMX_CMRX_PRT_CBFC_CTL; +- + rpm_write(rpm, lmac_id, pfc_class_mask_cfg, class_en); + + return 0; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +index 49c1dbe5ec788..43f6d1b50d2ad 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +@@ -1691,6 +1691,42 @@ exit: + return true; + } + ++static void nix_reset_tx_schedule(struct rvu *rvu, int blkaddr, ++ int lvl, int schq) ++{ ++ u64 tlx_parent = 0, tlx_schedule = 0; ++ ++ switch (lvl) { ++ case NIX_TXSCH_LVL_TL2: ++ tlx_parent = NIX_AF_TL2X_PARENT(schq); ++ tlx_schedule = NIX_AF_TL2X_SCHEDULE(schq); ++ break; ++ case NIX_TXSCH_LVL_TL3: ++ tlx_parent = NIX_AF_TL3X_PARENT(schq); ++ tlx_schedule = NIX_AF_TL3X_SCHEDULE(schq); ++ break; ++ case NIX_TXSCH_LVL_TL4: ++ tlx_parent = NIX_AF_TL4X_PARENT(schq); ++ tlx_schedule = NIX_AF_TL4X_SCHEDULE(schq); ++ break; ++ case NIX_TXSCH_LVL_MDQ: ++ /* no need to reset SMQ_CFG as HW clears this CSR ++ * on SMQ flush ++ */ ++ tlx_parent = NIX_AF_MDQX_PARENT(schq); ++ tlx_schedule = NIX_AF_MDQX_SCHEDULE(schq); ++ break; ++ default: ++ return; ++ } ++ ++ if (tlx_parent) ++ rvu_write64(rvu, blkaddr, tlx_parent, 0x0); ++ ++ if (tlx_schedule) ++ rvu_write64(rvu, blkaddr, tlx_schedule, 0x0); ++} ++ + /* Disable shaping of pkts by a scheduler queue + * at a given scheduler level. + */ +@@ -2040,6 +2076,7 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, + pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); + nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); + nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); ++ nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); + } + + for (idx = 0; idx < req->schq[lvl]; idx++) { +@@ -2049,6 +2086,7 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, + pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); + nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); + nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); ++ nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); + } + } + +@@ -2144,6 +2182,7 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) + continue; + nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); + nix_clear_tx_xoff(rvu, blkaddr, lvl, schq); ++ nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); + } + } + nix_clear_tx_xoff(rvu, blkaddr, NIX_TXSCH_LVL_TL1, +@@ -2182,6 +2221,7 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) + for (schq = 0; schq < txsch->schq.max; schq++) { + if (TXSCH_MAP_FUNC(txsch->pfvf_map[schq]) != pcifunc) + continue; ++ nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); + rvu_free_rsrc(&txsch->schq, schq); + txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); + } +@@ -2241,6 +2281,9 @@ static int nix_txschq_free_one(struct rvu *rvu, + */ + nix_clear_tx_xoff(rvu, blkaddr, lvl, schq); + ++ nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); ++ nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); ++ + /* Flush if it is a SMQ. Onus of disabling + * TL2/3 queue links before SMQ flush is on user + */ +@@ -2250,6 +2293,8 @@ static int nix_txschq_free_one(struct rvu *rvu, + goto err; + } + ++ nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); ++ + /* Free the resource */ + rvu_free_rsrc(&txsch->schq, schq); + txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +index 8a41ad8ca04f1..011355e73696e 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +@@ -716,7 +716,8 @@ EXPORT_SYMBOL(otx2_smq_flush); + int otx2_txsch_alloc(struct otx2_nic *pfvf) + { + struct nix_txsch_alloc_req *req; +- int lvl; ++ struct nix_txsch_alloc_rsp *rsp; ++ int lvl, schq, rc; + + /* Get memory to put this msg */ + req = otx2_mbox_alloc_msg_nix_txsch_alloc(&pfvf->mbox); +@@ -726,33 +727,69 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf) + /* Request one schq per level */ + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) + req->schq[lvl] = 1; ++ rc = otx2_sync_mbox_msg(&pfvf->mbox); ++ if (rc) ++ return rc; + +- return otx2_sync_mbox_msg(&pfvf->mbox); ++ rsp = (struct nix_txsch_alloc_rsp *) ++ otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); ++ if (IS_ERR(rsp)) ++ return PTR_ERR(rsp); ++ ++ /* Setup transmit scheduler list */ ++ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) ++ for (schq = 0; schq < rsp->schq[lvl]; schq++) ++ pfvf->hw.txschq_list[lvl][schq] = ++ rsp->schq_list[lvl][schq]; ++ ++ pfvf->hw.txschq_link_cfg_lvl = rsp->link_cfg_lvl; ++ ++ return 0; + } + +-int otx2_txschq_stop(struct otx2_nic *pfvf) ++void otx2_txschq_free_one(struct otx2_nic *pfvf, u16 lvl, u16 schq) + { + struct nix_txsch_free_req *free_req; +- int lvl, schq, err; ++ int err; + + mutex_lock(&pfvf->mbox.lock); +- /* Free the transmit schedulers */ ++ + free_req = otx2_mbox_alloc_msg_nix_txsch_free(&pfvf->mbox); + if (!free_req) { + mutex_unlock(&pfvf->mbox.lock); +- return -ENOMEM; ++ netdev_err(pfvf->netdev, ++ "Failed alloc txschq free req\n"); ++ return; + } + +- free_req->flags = TXSCHQ_FREE_ALL; ++ free_req->schq_lvl = lvl; ++ free_req->schq = schq; ++ + err = otx2_sync_mbox_msg(&pfvf->mbox); ++ if (err) { ++ netdev_err(pfvf->netdev, ++ "Failed stop txschq %d at level %d\n", schq, lvl); ++ } ++ + mutex_unlock(&pfvf->mbox.lock); ++} ++EXPORT_SYMBOL(otx2_txschq_free_one); ++ ++void otx2_txschq_stop(struct otx2_nic *pfvf) ++{ ++ int lvl, schq; ++ ++ /* free non QOS TLx nodes */ ++ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) ++ otx2_txschq_free_one(pfvf, lvl, ++ pfvf->hw.txschq_list[lvl][0]); + + /* Clear the txschq list */ + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + for (schq = 0; schq < MAX_TXSCHQ_PER_FUNC; schq++) + pfvf->hw.txschq_list[lvl][schq] = 0; + } +- return err; ++ + } + + void otx2_sqb_flush(struct otx2_nic *pfvf) +@@ -1629,21 +1666,6 @@ void mbox_handler_cgx_fec_stats(struct otx2_nic *pfvf, + pfvf->hw.cgx_fec_uncorr_blks += rsp->fec_uncorr_blks; + } + +-void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf, +- struct nix_txsch_alloc_rsp *rsp) +-{ +- int lvl, schq; +- +- /* Setup transmit scheduler list */ +- for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) +- for (schq = 0; schq < rsp->schq[lvl]; schq++) +- pf->hw.txschq_list[lvl][schq] = +- rsp->schq_list[lvl][schq]; +- +- pf->hw.txschq_link_cfg_lvl = rsp->link_cfg_lvl; +-} +-EXPORT_SYMBOL(mbox_handler_nix_txsch_alloc); +- + void mbox_handler_npa_lf_alloc(struct otx2_nic *pfvf, + struct npa_lf_alloc_rsp *rsp) + { +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +index 0c8fc66ade82d..53cf964fc3e14 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +@@ -920,7 +920,8 @@ int otx2_config_nix(struct otx2_nic *pfvf); + int otx2_config_nix_queues(struct otx2_nic *pfvf); + int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool pfc_en); + int otx2_txsch_alloc(struct otx2_nic *pfvf); +-int otx2_txschq_stop(struct otx2_nic *pfvf); ++void otx2_txschq_stop(struct otx2_nic *pfvf); ++void otx2_txschq_free_one(struct otx2_nic *pfvf, u16 lvl, u16 schq); + void otx2_sqb_flush(struct otx2_nic *pfvf); + int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, + dma_addr_t *dma); +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c +index ccaf97bb1ce03..bfddbff7bcdfb 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c +@@ -70,7 +70,7 @@ static int otx2_pfc_txschq_alloc_one(struct otx2_nic *pfvf, u8 prio) + * link config level. These rest of the scheduler can be + * same as hw.txschq_list. + */ +- for (lvl = 0; lvl < pfvf->hw.txschq_link_cfg_lvl; lvl++) ++ for (lvl = 0; lvl <= pfvf->hw.txschq_link_cfg_lvl; lvl++) + req->schq[lvl] = 1; + + rc = otx2_sync_mbox_msg(&pfvf->mbox); +@@ -83,7 +83,7 @@ static int otx2_pfc_txschq_alloc_one(struct otx2_nic *pfvf, u8 prio) + return PTR_ERR(rsp); + + /* Setup transmit scheduler list */ +- for (lvl = 0; lvl < pfvf->hw.txschq_link_cfg_lvl; lvl++) { ++ for (lvl = 0; lvl <= pfvf->hw.txschq_link_cfg_lvl; lvl++) { + if (!rsp->schq[lvl]) + return -ENOSPC; + +@@ -125,19 +125,12 @@ int otx2_pfc_txschq_alloc(struct otx2_nic *pfvf) + + static int otx2_pfc_txschq_stop_one(struct otx2_nic *pfvf, u8 prio) + { +- struct nix_txsch_free_req *free_req; ++ int lvl; + +- mutex_lock(&pfvf->mbox.lock); + /* free PFC TLx nodes */ +- free_req = otx2_mbox_alloc_msg_nix_txsch_free(&pfvf->mbox); +- if (!free_req) { +- mutex_unlock(&pfvf->mbox.lock); +- return -ENOMEM; +- } +- +- free_req->flags = TXSCHQ_FREE_ALL; +- otx2_sync_mbox_msg(&pfvf->mbox); +- mutex_unlock(&pfvf->mbox.lock); ++ for (lvl = 0; lvl <= pfvf->hw.txschq_link_cfg_lvl; lvl++) ++ otx2_txschq_free_one(pfvf, lvl, ++ pfvf->pfc_schq_list[lvl][prio]); + + pfvf->pfc_alloc_status[prio] = false; + return 0; +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index 384d26bee9b23..fb951e953df34 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -791,10 +791,6 @@ static void otx2_process_pfaf_mbox_msg(struct otx2_nic *pf, + case MBOX_MSG_NIX_LF_ALLOC: + mbox_handler_nix_lf_alloc(pf, (struct nix_lf_alloc_rsp *)msg); + break; +- case MBOX_MSG_NIX_TXSCH_ALLOC: +- mbox_handler_nix_txsch_alloc(pf, +- (struct nix_txsch_alloc_rsp *)msg); +- break; + case MBOX_MSG_NIX_BP_ENABLE: + mbox_handler_nix_bp_enable(pf, (struct nix_bp_cfg_rsp *)msg); + break; +@@ -1517,8 +1513,7 @@ err_free_nix_queues: + otx2_free_cq_res(pf); + otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false); + err_free_txsch: +- if (otx2_txschq_stop(pf)) +- dev_err(pf->dev, "%s failed to stop TX schedulers\n", __func__); ++ otx2_txschq_stop(pf); + err_free_sq_ptrs: + otx2_sq_free_sqbs(pf); + err_free_rq_ptrs: +@@ -1553,15 +1548,13 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) + struct mbox *mbox = &pf->mbox; + struct otx2_cq_queue *cq; + struct msg_req *req; +- int qidx, err; ++ int qidx; + + /* Ensure all SQE are processed */ + otx2_sqb_flush(pf); + + /* Stop transmission */ +- err = otx2_txschq_stop(pf); +- if (err) +- dev_err(pf->dev, "RVUPF: Failed to stop/free TX schedulers\n"); ++ otx2_txschq_stop(pf); + + #ifdef CONFIG_DCB + if (pf->pfc_en) +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +index 53366dbfbf27c..f8f0c01f62a14 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +@@ -70,10 +70,6 @@ static void otx2vf_process_vfaf_mbox_msg(struct otx2_nic *vf, + case MBOX_MSG_NIX_LF_ALLOC: + mbox_handler_nix_lf_alloc(vf, (struct nix_lf_alloc_rsp *)msg); + break; +- case MBOX_MSG_NIX_TXSCH_ALLOC: +- mbox_handler_nix_txsch_alloc(vf, +- (struct nix_txsch_alloc_rsp *)msg); +- break; + case MBOX_MSG_NIX_BP_ENABLE: + mbox_handler_nix_bp_enable(vf, (struct nix_bp_cfg_rsp *)msg); + break; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +index 50022e7565f14..f202150a5093c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +@@ -332,16 +332,11 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev) + pci_cfg_access_lock(sdev); + } + /* PCI link toggle */ +- err = pci_read_config_word(bridge, cap + PCI_EXP_LNKCTL, ®16); +- if (err) +- return err; +- reg16 |= PCI_EXP_LNKCTL_LD; +- err = pci_write_config_word(bridge, cap + PCI_EXP_LNKCTL, reg16); ++ err = pcie_capability_set_word(bridge, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_LD); + if (err) + return err; + msleep(500); +- reg16 &= ~PCI_EXP_LNKCTL_LD; +- err = pci_write_config_word(bridge, cap + PCI_EXP_LNKCTL, reg16); ++ err = pcie_capability_clear_word(bridge, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_LD); + if (err) + return err; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +index dba4c5e2f7667..94a1635ecdd47 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +@@ -32,16 +32,13 @@ + + #include <linux/clocksource.h> + #include <linux/highmem.h> ++#include <linux/log2.h> + #include <linux/ptp_clock_kernel.h> + #include <rdma/mlx5-abi.h> + #include "lib/eq.h" + #include "en.h" + #include "clock.h" + +-enum { +- MLX5_CYCLES_SHIFT = 31 +-}; +- + enum { + MLX5_PIN_MODE_IN = 0x0, + MLX5_PIN_MODE_OUT = 0x1, +@@ -93,6 +90,31 @@ static bool mlx5_modify_mtutc_allowed(struct mlx5_core_dev *mdev) + return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify); + } + ++static u32 mlx5_ptp_shift_constant(u32 dev_freq_khz) ++{ ++ /* Optimal shift constant leads to corrections above just 1 scaled ppm. ++ * ++ * Two sets of equations are needed to derive the optimal shift ++ * constant for the cyclecounter. ++ * ++ * dev_freq_khz * 1000 / 2^shift_constant = 1 scaled_ppm ++ * ppb = scaled_ppm * 1000 / 2^16 ++ * ++ * Using the two equations together ++ * ++ * dev_freq_khz * 1000 / 1 scaled_ppm = 2^shift_constant ++ * dev_freq_khz * 2^16 / 1 ppb = 2^shift_constant ++ * dev_freq_khz = 2^(shift_constant - 16) ++ * ++ * then yields ++ * ++ * shift_constant = ilog2(dev_freq_khz) + 16 ++ */ ++ ++ return min(ilog2(dev_freq_khz) + 16, ++ ilog2((U32_MAX / NSEC_PER_MSEC) * dev_freq_khz)); ++} ++ + static bool mlx5_is_mtutc_time_adj_cap(struct mlx5_core_dev *mdev, s64 delta) + { + s64 min = MLX5_MTUTC_OPERATION_ADJUST_TIME_MIN; +@@ -910,7 +932,7 @@ static void mlx5_timecounter_init(struct mlx5_core_dev *mdev) + + dev_freq = MLX5_CAP_GEN(mdev, device_frequency_khz); + timer->cycles.read = read_internal_timer; +- timer->cycles.shift = MLX5_CYCLES_SHIFT; ++ timer->cycles.shift = mlx5_ptp_shift_constant(dev_freq); + timer->cycles.mult = clocksource_khz2mult(dev_freq, + timer->cycles.shift); + timer->nominal_c_mult = timer->cycles.mult; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 70735068cf292..0fd290d776ffe 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -405,7 +405,8 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev, + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + + return sprintf(buf, "front panel %03u\n", +- mlxsw_hwmon_attr->type_index); ++ mlxsw_hwmon_attr->type_index + 1 - ++ mlxsw_hwmon_attr->mlxsw_hwmon_dev->sensor_count); + } + + static ssize_t +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index 2c586c2308aef..4fac27c36ad85 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -48,6 +48,7 @@ + #define MLXSW_I2C_MBOX_SIZE_BITS 12 + #define MLXSW_I2C_ADDR_BUF_SIZE 4 + #define MLXSW_I2C_BLK_DEF 32 ++#define MLXSW_I2C_BLK_MAX 100 + #define MLXSW_I2C_RETRY 5 + #define MLXSW_I2C_TIMEOUT_MSECS 5000 + #define MLXSW_I2C_MAX_DATA_SIZE 256 +@@ -444,7 +445,7 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, + } else { + /* No input mailbox is case of initialization query command. */ + reg_size = MLXSW_I2C_MAX_DATA_SIZE; +- num = reg_size / mlxsw_i2c->block_size; ++ num = DIV_ROUND_UP(reg_size, mlxsw_i2c->block_size); + + if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { + dev_err(&client->dev, "Could not acquire lock"); +@@ -653,7 +654,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client) + return -EOPNOTSUPP; + } + +- mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, ++ mlxsw_i2c->block_size = min_t(u16, MLXSW_I2C_BLK_MAX, + min_t(u16, quirks->max_read_len, + quirks->max_write_len)); + } else { +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c +index 266a21a2d1246..1da2b1f82ae93 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c +@@ -59,7 +59,7 @@ static int lan966x_ptp_add_trap(struct lan966x_port *port, + int err; + + vrule = vcap_get_rule(lan966x->vcap_ctrl, rule_id); +- if (vrule) { ++ if (!IS_ERR(vrule)) { + u32 value, mask; + + /* Just modify the ingress port mask and exit */ +@@ -106,7 +106,7 @@ static int lan966x_ptp_del_trap(struct lan966x_port *port, + int err; + + vrule = vcap_get_rule(lan966x->vcap_ctrl, rule_id); +- if (!vrule) ++ if (IS_ERR(vrule)) + return -EEXIST; + + vcap_rule_get_key_u32(vrule, VCAP_KF_IF_IGR_PORT_MASK, &value, &mask); +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 31fdecb414b6f..d813613a670b6 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5241,13 +5241,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + + /* Disable ASPM L1 as that cause random device stop working + * problems as well as full system hangs for some PCIe devices users. +- * Chips from RTL8168h partially have issues with L1.2, but seem +- * to work fine with L1 and L1.1. + */ + if (rtl_aspm_is_safe(tp)) + rc = 0; +- else if (tp->mac_version >= RTL_GIGA_MAC_VER_46) +- rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2); + else + rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1); + tp->aspm_manageable = !rc; +diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c +index 0c40571133cb9..00cf6de3bb2be 100644 +--- a/drivers/net/ethernet/sfc/ptp.c ++++ b/drivers/net/ethernet/sfc/ptp.c +@@ -1485,7 +1485,9 @@ static int efx_ptp_insert_multicast_filters(struct efx_nic *efx) + goto fail; + + rc = efx_ptp_insert_eth_multicast_filter(efx); +- if (rc < 0) ++ ++ /* Not all firmware variants support this filter */ ++ if (rc < 0 && rc != -EPROTONOSUPPORT) + goto fail; + } + +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index 144ec756c796a..2d64650f4eb3c 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -1341,8 +1341,7 @@ static struct crypto_aead *macsec_alloc_tfm(char *key, int key_len, int icv_len) + struct crypto_aead *tfm; + int ret; + +- /* Pick a sync gcm(aes) cipher to ensure order is preserved. */ +- tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); ++ tfm = crypto_alloc_aead("gcm(aes)", 0, 0); + + if (IS_ERR(tfm)) + return tfm; +diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c +index 9372e5a4cadcf..5093fc82a0248 100644 +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -258,6 +258,16 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, + switch (id->base.extended_cc) { + case SFF8024_ECC_UNSPEC: + break; ++ case SFF8024_ECC_100G_25GAUI_C2M_AOC: ++ if (br_min <= 28000 && br_max >= 25000) { ++ /* 25GBASE-R, possibly with FEC */ ++ __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces); ++ /* There is currently no link mode for 25000base ++ * with unspecified range, reuse SR. ++ */ ++ phylink_set(modes, 25000baseSR_Full); ++ } ++ break; + case SFF8024_ECC_100GBASE_SR4_25GBASE_SR: + phylink_set(modes, 100000baseSR4_Full); + phylink_set(modes, 25000baseSR_Full); +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 2e7c7b0cdc549..c1bcd2ab1488e 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1423,6 +1423,7 @@ static const struct usb_device_id products[] = { + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0195, 4)}, /* Quectel EG95 */ + {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ ++ {QMI_QUIRK_SET_DTR(0x2c7c, 0x030e, 4)}, /* Quectel EM05GV2 */ + {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */ + {QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */ + {QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/ +diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c +index a7f44f6335fb8..9275a672f90cb 100644 +--- a/drivers/net/wireless/ath/ath10k/pci.c ++++ b/drivers/net/wireless/ath/ath10k/pci.c +@@ -1963,8 +1963,9 @@ static int ath10k_pci_hif_start(struct ath10k *ar) + ath10k_pci_irq_enable(ar); + ath10k_pci_rx_post(ar); + +- pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL, +- ar_pci->link_ctl); ++ pcie_capability_clear_and_set_word(ar_pci->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC, ++ ar_pci->link_ctl & PCI_EXP_LNKCTL_ASPMC); + + return 0; + } +@@ -2821,8 +2822,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar, + + pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL, + &ar_pci->link_ctl); +- pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL, +- ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); ++ pcie_capability_clear_word(ar_pci->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC); + + /* + * Bring the target up cleanly. +diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c +index f67ce62b2b48d..c5ff1bc02999e 100644 +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2408,7 +2408,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, + rx_status->freq = center_freq; + } else if (channel_num >= 1 && channel_num <= 14) { + rx_status->band = NL80211_BAND_2GHZ; +- } else if (channel_num >= 36 && channel_num <= 173) { ++ } else if (channel_num >= 36 && channel_num <= 177) { + rx_status->band = NL80211_BAND_5GHZ; + } else { + spin_lock_bh(&ar->data_lock); +diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c +index 7b33731a50ee7..6ba4cef6b1c7d 100644 +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -581,8 +581,8 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) + u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); + + /* disable L0s and L1 */ +- pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +- ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); ++ pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC); + + set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); + } +@@ -590,8 +590,10 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) + static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) + { + if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) +- pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +- ab_pci->link_ctl); ++ pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC, ++ ab_pci->link_ctl & ++ PCI_EXP_LNKCTL_ASPMC); + } + + static int ath11k_pci_power_up(struct ath11k_base *ab) +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index 58acfe8fdf8c0..faccea2d8148c 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -1634,9 +1634,9 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, + arg->peer_nss = min(sta->deflink.rx_nss, max_nss); + + memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info, +- sizeof(arg->peer_he_cap_macinfo)); ++ sizeof(he_cap->he_cap_elem.mac_cap_info)); + memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info, +- sizeof(arg->peer_he_cap_phyinfo)); ++ sizeof(he_cap->he_cap_elem.phy_cap_info)); + arg->peer_he_ops = vif->bss_conf.he_oper.params; + + /* the top most byte is used to indicate BSS color info */ +diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c +index 9f174daf324c9..e1e45eb50f3e3 100644 +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -794,8 +794,8 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci) + u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); + + /* disable L0s and L1 */ +- pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +- ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); ++ pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC); + + set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags); + } +@@ -803,8 +803,10 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci) + static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci) + { + if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags)) +- pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +- ab_pci->link_ctl); ++ pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC, ++ ab_pci->link_ctl & ++ PCI_EXP_LNKCTL_ASPMC); + } + + static void ath12k_pci_kill_tasklets(struct ath12k_base *ab) +diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c +index 7ae0bb78b2b53..1e65e35b5f3a6 100644 +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -2144,8 +2144,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar, + struct wmi_tlv *tlv; + void *ptr; + int i, ret, len; +- u32 *tmp_ptr; +- u8 extraie_len_with_pad = 0; ++ u32 *tmp_ptr, extraie_len_with_pad = 0; + struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL; + struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL; + +diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile +index a75bfa9fd1cfd..dc2b3b46781e1 100644 +--- a/drivers/net/wireless/ath/ath6kl/Makefile ++++ b/drivers/net/wireless/ath/ath6kl/Makefile +@@ -36,11 +36,6 @@ ath6kl_core-y += wmi.o + ath6kl_core-y += core.o + ath6kl_core-y += recovery.o + +-# FIXME: temporarily silence -Wdangling-pointer on non W=1+ builds +-ifndef KBUILD_EXTRA_WARN +-CFLAGS_htc_mbox.o += $(call cc-disable-warning, dangling-pointer) +-endif +- + ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o + ath6kl_core-$(CONFIG_ATH6KL_TRACING) += trace.o + +diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +index b3ed65e5c4da8..c55aab01fff5d 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +@@ -491,7 +491,7 @@ int ath9k_htc_init_debug(struct ath_hw *ah) + + priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, + priv->hw->wiphy->debugfsdir); +- if (!priv->debug.debugfs_phy) ++ if (IS_ERR(priv->debug.debugfs_phy)) + return -ENOMEM; + + ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); +diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c +index d652c647d56b5..1476b42b52a91 100644 +--- a/drivers/net/wireless/ath/ath9k/wmi.c ++++ b/drivers/net/wireless/ath/ath9k/wmi.c +@@ -242,10 +242,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + goto free_skb; + } +- spin_unlock_irqrestore(&wmi->wmi_lock, flags); + + /* WMI command response */ + ath9k_wmi_rsp_callback(wmi, skb); ++ spin_unlock_irqrestore(&wmi->wmi_lock, flags); + + free_skb: + kfree_skb(skb); +@@ -283,7 +283,8 @@ int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, + + static int ath9k_wmi_cmd_issue(struct wmi *wmi, + struct sk_buff *skb, +- enum wmi_cmd_id cmd, u16 len) ++ enum wmi_cmd_id cmd, u16 len, ++ u8 *rsp_buf, u32 rsp_len) + { + struct wmi_cmd_hdr *hdr; + unsigned long flags; +@@ -293,6 +294,11 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, + hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); + + spin_lock_irqsave(&wmi->wmi_lock, flags); ++ ++ /* record the rsp buffer and length */ ++ wmi->cmd_rsp_buf = rsp_buf; ++ wmi->cmd_rsp_len = rsp_len; ++ + wmi->last_seq_id = wmi->tx_seq_id; + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + +@@ -308,8 +314,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + struct ath_common *common = ath9k_hw_common(ah); + u16 headroom = sizeof(struct htc_frame_hdr) + + sizeof(struct wmi_cmd_hdr); ++ unsigned long time_left, flags; + struct sk_buff *skb; +- unsigned long time_left; + int ret = 0; + + if (ah->ah_flags & AH_UNPLUGGED) +@@ -333,11 +339,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + goto out; + } + +- /* record the rsp buffer and length */ +- wmi->cmd_rsp_buf = rsp_buf; +- wmi->cmd_rsp_len = rsp_len; +- +- ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); ++ ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len); + if (ret) + goto out; + +@@ -345,7 +347,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + if (!time_left) { + ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", + wmi_cmd_to_name(cmd_id)); ++ spin_lock_irqsave(&wmi->wmi_lock, flags); + wmi->last_seq_id = 0; ++ spin_unlock_irqrestore(&wmi->wmi_lock, flags); + mutex_unlock(&wmi->op_mutex); + return -ETIMEDOUT; + } +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +index 792adaf880b44..bece26741d3a3 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -398,7 +398,12 @@ struct brcmf_scan_params_le { + * fixed parameter portion is assumed, otherwise + * ssid in the fixed portion is ignored + */ +- __le16 channel_list[1]; /* list of chanspecs */ ++ union { ++ __le16 padding; /* Reserve space for at least 1 entry for abort ++ * which uses an on stack brcmf_scan_params_le ++ */ ++ DECLARE_FLEX_ARRAY(__le16, channel_list); /* chanspecs */ ++ }; + }; + + struct brcmf_scan_params_v2_le { +diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c +index 52b18f4a774b7..0cdd6c50c1c08 100644 +--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c ++++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c +@@ -253,8 +253,11 @@ mwifiex_histogram_read(struct file *file, char __user *ubuf, + if (!p) + return -ENOMEM; + +- if (!priv || !priv->hist_data) +- return -EFAULT; ++ if (!priv || !priv->hist_data) { ++ ret = -EFAULT; ++ goto free_and_exit; ++ } ++ + phist_data = priv->hist_data; + + p += sprintf(p, "\n" +@@ -309,6 +312,8 @@ mwifiex_histogram_read(struct file *file, char __user *ubuf, + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + ++free_and_exit: ++ free_page(page); + return ret; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a698a16a8f38..6697132ecc977 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -189,6 +189,8 @@ static int mwifiex_pcie_probe_of(struct device *dev) + } + + static void mwifiex_pcie_work(struct work_struct *work); ++static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter); ++static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter); + + static int + mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, +@@ -792,14 +794,15 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) + if (!skb) { + mwifiex_dbg(adapter, ERROR, + "Unable to allocate skb for RX ring.\n"); +- kfree(card->rxbd_ring_vbase); + return -ENOMEM; + } + + if (mwifiex_map_pci_memory(adapter, skb, + MWIFIEX_RX_DATA_BUF_SIZE, +- DMA_FROM_DEVICE)) +- return -1; ++ DMA_FROM_DEVICE)) { ++ kfree_skb(skb); ++ return -ENOMEM; ++ } + + buf_pa = MWIFIEX_SKB_DMA_ADDR(skb); + +@@ -849,7 +852,6 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) + if (!skb) { + mwifiex_dbg(adapter, ERROR, + "Unable to allocate skb for EVENT buf.\n"); +- kfree(card->evtbd_ring_vbase); + return -ENOMEM; + } + skb_put(skb, MAX_EVENT_SIZE); +@@ -857,8 +859,7 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) + if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, + DMA_FROM_DEVICE)) { + kfree_skb(skb); +- kfree(card->evtbd_ring_vbase); +- return -1; ++ return -ENOMEM; + } + + buf_pa = MWIFIEX_SKB_DMA_ADDR(skb); +@@ -1058,6 +1059,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) + */ + static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) + { ++ int ret; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + +@@ -1096,7 +1098,10 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) + (u32)((u64)card->rxbd_ring_pbase >> 32), + card->rxbd_ring_size); + +- return mwifiex_init_rxq_ring(adapter); ++ ret = mwifiex_init_rxq_ring(adapter); ++ if (ret) ++ mwifiex_pcie_delete_rxbd_ring(adapter); ++ return ret; + } + + /* +@@ -1127,6 +1132,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) + */ + static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) + { ++ int ret; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + +@@ -1161,7 +1167,10 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) + (u32)((u64)card->evtbd_ring_pbase >> 32), + card->evtbd_ring_size); + +- return mwifiex_pcie_init_evt_ring(adapter); ++ ret = mwifiex_pcie_init_evt_ring(adapter); ++ if (ret) ++ mwifiex_pcie_delete_evtbd_ring(adapter); ++ return ret; + } + + /* +diff --git a/drivers/net/wireless/marvell/mwifiex/sta_rx.c b/drivers/net/wireless/marvell/mwifiex/sta_rx.c +index 13659b02ba882..65420ad674167 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sta_rx.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_rx.c +@@ -86,6 +86,15 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, + rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length); + rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off; + ++ if (sizeof(*rx_pkt_hdr) + rx_pkt_off > skb->len) { ++ mwifiex_dbg(priv->adapter, ERROR, ++ "wrong rx packet offset: len=%d, rx_pkt_off=%d\n", ++ skb->len, rx_pkt_off); ++ priv->stats.rx_dropped++; ++ dev_kfree_skb_any(skb); ++ return -1; ++ } ++ + if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header, + sizeof(bridge_tunnel_header))) || + (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, +@@ -194,7 +203,8 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, + + rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset; + +- if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) { ++ if ((rx_pkt_offset + rx_pkt_length) > skb->len || ++ sizeof(rx_pkt_hdr->eth803_hdr) + rx_pkt_offset > skb->len) { + mwifiex_dbg(adapter, ERROR, + "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n", + skb->len, rx_pkt_offset, rx_pkt_length); +diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +index e495f7eaea033..b8b9a0fcb19cd 100644 +--- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c ++++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +@@ -103,6 +103,16 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, + return; + } + ++ if (sizeof(*rx_pkt_hdr) + ++ le16_to_cpu(uap_rx_pd->rx_pkt_offset) > skb->len) { ++ mwifiex_dbg(adapter, ERROR, ++ "wrong rx packet offset: len=%d,rx_pkt_offset=%d\n", ++ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset)); ++ priv->stats.rx_dropped++; ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ + if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header, + sizeof(bridge_tunnel_header))) || + (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, +@@ -243,7 +253,15 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv, + + if (is_multicast_ether_addr(ra)) { + skb_uap = skb_copy(skb, GFP_ATOMIC); +- mwifiex_uap_queue_bridged_pkt(priv, skb_uap); ++ if (likely(skb_uap)) { ++ mwifiex_uap_queue_bridged_pkt(priv, skb_uap); ++ } else { ++ mwifiex_dbg(adapter, ERROR, ++ "failed to copy skb for uAP\n"); ++ priv->stats.rx_dropped++; ++ dev_kfree_skb_any(skb); ++ return -1; ++ } + } else { + if (mwifiex_get_sta_entry(priv, ra)) { + /* Requeue Intra-BSS packet */ +@@ -367,6 +385,16 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, + rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type); + rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); + ++ if (le16_to_cpu(uap_rx_pd->rx_pkt_offset) + ++ sizeof(rx_pkt_hdr->eth803_hdr) > skb->len) { ++ mwifiex_dbg(adapter, ERROR, ++ "wrong rx packet for struct ethhdr: len=%d, offset=%d\n", ++ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset)); ++ priv->stats.rx_dropped++; ++ dev_kfree_skb_any(skb); ++ return 0; ++ } ++ + ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source); + + if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) + +diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c +index 94c2d219835da..745b1d925b217 100644 +--- a/drivers/net/wireless/marvell/mwifiex/util.c ++++ b/drivers/net/wireless/marvell/mwifiex/util.c +@@ -393,11 +393,15 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, + } + + rx_pd = (struct rxpd *)skb->data; ++ pkt_len = le16_to_cpu(rx_pd->rx_pkt_length); ++ if (pkt_len < sizeof(struct ieee80211_hdr) + sizeof(pkt_len)) { ++ mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length"); ++ return -1; ++ } + + skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset)); + skb_pull(skb, sizeof(pkt_len)); +- +- pkt_len = le16_to_cpu(rx_pd->rx_pkt_length); ++ pkt_len -= sizeof(pkt_len); + + ieee_hdr = (void *)skb->data; + if (ieee80211_is_mgmt(ieee_hdr->frame_control)) { +@@ -410,7 +414,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, + skb->data + sizeof(struct ieee80211_hdr), + pkt_len - sizeof(struct ieee80211_hdr)); + +- pkt_len -= ETH_ALEN + sizeof(pkt_len); ++ pkt_len -= ETH_ALEN; + rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); + + cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index 6b07b8fafec2f..0e9f4197213a3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -277,7 +277,7 @@ struct mt76_sta_stats { + u64 tx_mcs[16]; /* mcs idx */ + u64 tx_bytes; + /* WED TX */ +- u32 tx_packets; ++ u32 tx_packets; /* unit: MSDU */ + u32 tx_retries; + u32 tx_failed; + /* WED RX */ +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +index be4d63db5f64a..e415ac5e321f1 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +@@ -522,9 +522,9 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS + + mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); + +- /* counting non-offloading skbs */ +- wcid->stats.tx_bytes += skb->len; +- wcid->stats.tx_packets++; ++ /* mt7915 WA only counts WED path */ ++ if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed)) ++ wcid->stats.tx_packets++; + } + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | +@@ -609,12 +609,11 @@ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid, + txs = le32_to_cpu(txs_data[0]); + + /* PPDU based reporting */ +- if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) { ++ if (mtk_wed_device_active(&dev->mmio.wed) && ++ FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) { + stats->tx_bytes += + le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) - + le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE); +- stats->tx_packets += +- le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_CNT); + stats->tx_failed += + le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT); + stats->tx_retries += +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +index ca1ce97a6d2fd..7a52b68491b6e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +@@ -998,6 +998,7 @@ enum { + MCU_EXT_EVENT_ASSERT_DUMP = 0x23, + MCU_EXT_EVENT_RDD_REPORT = 0x3a, + MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, ++ MCU_EXT_EVENT_WA_TX_STAT = 0x74, + MCU_EXT_EVENT_BCC_NOTIFY = 0x75, + MCU_EXT_EVENT_MURU_CTRL = 0x9f, + }; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +index ac2049f49bb38..9defd2b3c2f8d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -414,7 +414,6 @@ mt7915_init_wiphy(struct mt7915_phy *phy) + if (!dev->dbdc_support) + vht_cap->cap |= + IEEE80211_VHT_CAP_SHORT_GI_160 | +- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + FIELD_PREP(IEEE80211_VHT_CAP_EXT_NSS_BW_MASK, 1); + } else { + vht_cap->cap |= +@@ -499,6 +498,12 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) + set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) | + FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3); + mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); ++ ++ /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than ++ * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. ++ */ ++ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) ++ mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H); + } + + static void +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index 1b361199c0616..42a983e40ade9 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -269,6 +269,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, + vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; + + mt7915_init_bitrate_mask(vif); ++ memset(&mvif->cap, -1, sizeof(mvif->cap)); + + mt7915_mcu_add_bss_info(phy, vif, true); + mt7915_mcu_add_sta(dev, vif, NULL, true); +@@ -470,7 +471,8 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) + ieee80211_wake_queues(hw); + } + +- if (changed & IEEE80211_CONF_CHANGE_POWER) { ++ if (changed & (IEEE80211_CONF_CHANGE_POWER | ++ IEEE80211_CONF_CHANGE_CHANNEL)) { + ret = mt7915_mcu_set_txpower_sku(phy); + if (ret) + return ret; +@@ -599,6 +601,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + { + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_dev *dev = mt7915_hw_dev(hw); ++ int set_bss_info = -1, set_sta = -1; + + mutex_lock(&dev->mt76.mutex); + +@@ -607,15 +610,18 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + * and then peer references bss_info_rfch to set bandwidth cap. + */ + if (changed & BSS_CHANGED_BSSID && +- vif->type == NL80211_IFTYPE_STATION) { +- bool join = !is_zero_ether_addr(info->bssid); +- +- mt7915_mcu_add_bss_info(phy, vif, join); +- mt7915_mcu_add_sta(dev, vif, NULL, join); +- } +- ++ vif->type == NL80211_IFTYPE_STATION) ++ set_bss_info = set_sta = !is_zero_ether_addr(info->bssid); + if (changed & BSS_CHANGED_ASSOC) +- mt7915_mcu_add_bss_info(phy, vif, vif->cfg.assoc); ++ set_bss_info = vif->cfg.assoc; ++ if (changed & BSS_CHANGED_BEACON_ENABLED && ++ vif->type != NL80211_IFTYPE_AP) ++ set_bss_info = set_sta = info->enable_beacon; ++ ++ if (set_bss_info == 1) ++ mt7915_mcu_add_bss_info(phy, vif, true); ++ if (set_sta == 1) ++ mt7915_mcu_add_sta(dev, vif, NULL, true); + + if (changed & BSS_CHANGED_ERP_CTS_PROT) + mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); +@@ -629,11 +635,6 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + } + } + +- if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { +- mt7915_mcu_add_bss_info(phy, vif, true); +- mt7915_mcu_add_sta(dev, vif, NULL, true); +- } +- + /* ensure that enable txcmd_mode after bss_info */ + if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) + mt7915_mcu_set_tx(dev, vif); +@@ -650,6 +651,62 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + BSS_CHANGED_FILS_DISCOVERY)) + mt7915_mcu_add_beacon(hw, vif, info->enable_beacon, changed); + ++ if (set_bss_info == 0) ++ mt7915_mcu_add_bss_info(phy, vif, false); ++ if (set_sta == 0) ++ mt7915_mcu_add_sta(dev, vif, NULL, false); ++ ++ mutex_unlock(&dev->mt76.mutex); ++} ++ ++static void ++mt7915_vif_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif) ++{ ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; ++ struct mt7915_vif_cap *vc = &mvif->cap; ++ ++ vc->ht_ldpc = vif->bss_conf.ht_ldpc; ++ vc->vht_ldpc = vif->bss_conf.vht_ldpc; ++ vc->vht_su_ebfer = vif->bss_conf.vht_su_beamformer; ++ vc->vht_su_ebfee = vif->bss_conf.vht_su_beamformee; ++ vc->vht_mu_ebfer = vif->bss_conf.vht_mu_beamformer; ++ vc->vht_mu_ebfee = vif->bss_conf.vht_mu_beamformee; ++ vc->he_ldpc = vif->bss_conf.he_ldpc; ++ vc->he_su_ebfer = vif->bss_conf.he_su_beamformer; ++ vc->he_su_ebfee = vif->bss_conf.he_su_beamformee; ++ vc->he_mu_ebfer = vif->bss_conf.he_mu_beamformer; ++} ++ ++static int ++mt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *link_conf) ++{ ++ struct mt7915_phy *phy = mt7915_hw_phy(hw); ++ struct mt7915_dev *dev = mt7915_hw_dev(hw); ++ int err; ++ ++ mutex_lock(&dev->mt76.mutex); ++ ++ mt7915_vif_check_caps(phy, vif); ++ ++ err = mt7915_mcu_add_bss_info(phy, vif, true); ++ if (err) ++ goto out; ++ err = mt7915_mcu_add_sta(dev, vif, NULL, true); ++out: ++ mutex_unlock(&dev->mt76.mutex); ++ ++ return err; ++} ++ ++static void ++mt7915_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *link_conf) ++{ ++ struct mt7915_dev *dev = mt7915_hw_dev(hw); ++ ++ mutex_lock(&dev->mt76.mutex); ++ mt7915_mcu_add_sta(dev, vif, NULL, false); + mutex_unlock(&dev->mt76.mutex); + } + +@@ -1042,8 +1099,10 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, + sinfo->tx_bytes = msta->wcid.stats.tx_bytes; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); + +- sinfo->tx_packets = msta->wcid.stats.tx_packets; +- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); ++ if (!mt7915_mcu_wed_wa_tx_stats(phy->dev, msta->wcid.idx)) { ++ sinfo->tx_packets = msta->wcid.stats.tx_packets; ++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); ++ } + + sinfo->tx_failed = msta->wcid.stats.tx_failed; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); +@@ -1526,6 +1585,8 @@ const struct ieee80211_ops mt7915_ops = { + .conf_tx = mt7915_conf_tx, + .configure_filter = mt7915_configure_filter, + .bss_info_changed = mt7915_bss_info_changed, ++ .start_ap = mt7915_start_ap, ++ .stop_ap = mt7915_stop_ap, + .sta_add = mt7915_sta_add, + .sta_remove = mt7915_sta_remove, + .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index 9fcb22fa1f97e..1a8611c6b684d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -164,7 +164,9 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, + } + + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; +- if (seq != rxd->seq) ++ if (seq != rxd->seq && ++ !(rxd->eid == MCU_CMD_EXT_CID && ++ rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT)) + return -EAGAIN; + + if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { +@@ -274,7 +276,7 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) + + r = (struct mt7915_mcu_rdd_report *)skb->data; + +- if (r->band_idx > MT_BAND1) ++ if (r->band_idx > MT_RX_SEL2) + return; + + if ((r->band_idx && !dev->phy.mt76->band_idx) && +@@ -395,12 +397,14 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) + struct mt76_connac2_mcu_rxd *rxd; + + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; +- if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || +- rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || +- rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || +- rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || +- rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY || +- !rxd->seq) ++ if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || ++ rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || ++ rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || ++ rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || ++ rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY || ++ !rxd->seq) && ++ !(rxd->eid == MCU_CMD_EXT_CID && ++ rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT)) + mt7915_mcu_rx_unsolicited_event(dev, skb); + else + mt76_mcu_rx_event(&dev->mt76, skb); +@@ -706,6 +710,7 @@ static void + mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + struct ieee80211_vif *vif) + { ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; + struct ieee80211_he_mcs_nss_supp mcs_map; + struct sta_rec_he *he; +@@ -739,7 +744,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) + cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; + +- if (vif->bss_conf.he_ldpc && ++ if (mvif->cap.he_ldpc && + (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) + cap |= STA_REC_HE_CAP_LDPC; +@@ -848,6 +853,7 @@ static void + mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta, struct ieee80211_vif *vif) + { ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; + struct sta_rec_muru *muru; + struct tlv *tlv; +@@ -860,9 +866,9 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + + muru = (struct sta_rec_muru *)tlv; + +- muru->cfg.mimo_dl_en = vif->bss_conf.he_mu_beamformer || +- vif->bss_conf.vht_mu_beamformer || +- vif->bss_conf.vht_mu_beamformee; ++ muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer || ++ mvif->cap.vht_mu_ebfer || ++ mvif->cap.vht_mu_ebfee; + if (!is_mt7915(&dev->mt76)) + muru->cfg.mimo_ul_en = true; + muru->cfg.ofdma_dl_en = true; +@@ -995,8 +1001,8 @@ mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr); + if (sta) + mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv, +- wtbl_hdr, vif->bss_conf.ht_ldpc, +- vif->bss_conf.vht_ldpc); ++ wtbl_hdr, mvif->cap.ht_ldpc, ++ mvif->cap.vht_ldpc); + + return 0; + } +@@ -1005,6 +1011,7 @@ static inline bool + mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool bfee) + { ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int tx_ant = hweight8(phy->mt76->chainmask) - 1; + + if (vif->type != NL80211_IFTYPE_STATION && +@@ -1018,10 +1025,10 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; + + if (bfee) +- return vif->bss_conf.he_su_beamformee && ++ return mvif->cap.he_su_ebfee && + HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); + else +- return vif->bss_conf.he_su_beamformer && ++ return mvif->cap.he_su_ebfer && + HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); + } + +@@ -1029,10 +1036,10 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, + u32 cap = sta->deflink.vht_cap.cap; + + if (bfee) +- return vif->bss_conf.vht_su_beamformee && ++ return mvif->cap.vht_su_ebfee && + (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); + else +- return vif->bss_conf.vht_su_beamformer && ++ return mvif->cap.vht_su_ebfer && + (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); + } + +@@ -1527,7 +1534,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, + cap |= STA_CAP_TX_STBC; + if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) + cap |= STA_CAP_RX_STBC; +- if (vif->bss_conf.ht_ldpc && ++ if (mvif->cap.ht_ldpc && + (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) + cap |= STA_CAP_LDPC; + +@@ -1553,7 +1560,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, + cap |= STA_CAP_VHT_TX_STBC; + if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) + cap |= STA_CAP_VHT_RX_STBC; +- if (vif->bss_conf.vht_ldpc && ++ if (mvif->cap.vht_ldpc && + (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) + cap |= STA_CAP_VHT_LDPC; + +@@ -2993,7 +3000,7 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) + } + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), +- req, sizeof(req), true, &skb); ++ req, len * sizeof(req[0]), true, &skb); + if (ret) + return ret; + +@@ -3733,6 +3740,62 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, + &req, sizeof(req), true); + } + ++int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx) ++{ ++ struct { ++ __le32 cmd; ++ __le32 num; ++ __le32 __rsv; ++ __le16 wlan_idx; ++ } req = { ++ .cmd = cpu_to_le32(0x15), ++ .num = cpu_to_le32(1), ++ .wlan_idx = cpu_to_le16(wlan_idx), ++ }; ++ struct mt7915_mcu_wa_tx_stat { ++ __le16 wlan_idx; ++ u8 __rsv[2]; ++ ++ /* tx_bytes is deprecated since WA byte counter uses u32, ++ * which easily leads to overflow. ++ */ ++ __le32 tx_bytes; ++ __le32 tx_packets; ++ } *res; ++ struct mt76_wcid *wcid; ++ struct sk_buff *skb; ++ int ret; ++ ++ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY), ++ &req, sizeof(req), true, &skb); ++ if (ret) ++ return ret; ++ ++ if (!is_mt7915(&dev->mt76)) ++ skb_pull(skb, 4); ++ ++ res = (struct mt7915_mcu_wa_tx_stat *)skb->data; ++ ++ if (le16_to_cpu(res->wlan_idx) != wlan_idx) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ rcu_read_lock(); ++ ++ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); ++ if (wcid) ++ wcid->stats.tx_packets += le32_to_cpu(res->tx_packets); ++ else ++ ret = -EINVAL; ++ ++ rcu_read_unlock(); ++out: ++ dev_kfree_skb(skb); ++ ++ return ret; ++} ++ + int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set) + { + struct { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +index 45f3558bf31c1..2fa059af23ded 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +@@ -545,8 +545,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) + static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) + { + struct mt7915_dev *dev; +- struct mt7915_phy *phy; +- int ret; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + +@@ -554,43 +552,19 @@ static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) + dev->mt76.token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->mt76.token_lock); + +- ret = wait_event_timeout(dev->mt76.tx_wait, +- !dev->mt76.wed_token_count, HZ); +- if (!ret) +- return -EAGAIN; +- +- phy = &dev->phy; +- mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H); +- +- phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; +- if (phy) +- mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx), +- MT_AGG_ACR_PPDU_TXS2H); +- +- return 0; ++ return !wait_event_timeout(dev->mt76.tx_wait, ++ !dev->mt76.wed_token_count, HZ); + } + + static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) + { + struct mt7915_dev *dev; +- struct mt7915_phy *phy; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + + spin_lock_bh(&dev->mt76.token_lock); + dev->mt76.token_size = MT7915_TOKEN_SIZE; + spin_unlock_bh(&dev->mt76.token_lock); +- +- /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than +- * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. +- */ +- phy = &dev->phy; +- mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H); +- +- phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; +- if (phy) +- mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx), +- MT_AGG_ACR_PPDU_TXS2H); + } + + static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +index b3ead35307406..0f76733c9c1ac 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +@@ -147,9 +147,23 @@ struct mt7915_sta { + } twt; + }; + ++struct mt7915_vif_cap { ++ bool ht_ldpc:1; ++ bool vht_ldpc:1; ++ bool he_ldpc:1; ++ bool vht_su_ebfer:1; ++ bool vht_su_ebfee:1; ++ bool vht_mu_ebfer:1; ++ bool vht_mu_ebfee:1; ++ bool he_su_ebfer:1; ++ bool he_su_ebfee:1; ++ bool he_mu_ebfer:1; ++}; ++ + struct mt7915_vif { + struct mt76_vif mt76; /* must be first */ + ++ struct mt7915_vif_cap cap; + struct mt7915_sta sta; + struct mt7915_phy *phy; + +@@ -539,6 +553,7 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct rate_info *rate); + int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy, + struct cfg80211_chan_def *chandef); ++int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wcid); + int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set); + int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); + int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c +index bf1da9fddfaba..f41975e37d06a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c +@@ -113,7 +113,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) + wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; + wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; + wiphy->max_sched_scan_reqs = 1; +- wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ++ wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | ++ WIPHY_FLAG_SPLIT_SCAN_6GHZ; + wiphy->reg_notifier = mt7921_regd_notifier; + + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +index 534143465d9b3..fbedaacffbba5 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +@@ -293,7 +293,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) + /* event from WA */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], + MT_RXQ_ID(MT_RXQ_MCU_WA), +- MT7996_RX_MCU_RING_SIZE, ++ MT7996_RX_MCU_RING_SIZE_WA, + MT_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MCU_WA)); + if (ret) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 9b0f6053e0fa6..25c5deb15d213 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -836,14 +836,19 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) + skb_pull(skb, hdr_gap); + if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) { + pad_start = ieee80211_get_hdrlen_from_skb(skb); +- } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR) && +- get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) { ++ } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { + /* When header translation failure is indicated, + * the hardware will insert an extra 2-byte field + * containing the data length after the protocol +- * type field. ++ * type field. This happens either when the LLC-SNAP ++ * pattern did not match, or if a VLAN header was ++ * detected. + */ +- pad_start = 16; ++ pad_start = 12; ++ if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) ++ pad_start += 4; ++ else ++ pad_start = 0; + } + + if (pad_start) { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 88e2f9d0e5130..62a02b03d83ba 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -339,7 +339,11 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) + if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys)) + return; + +- mphy = dev->mt76.phys[r->band_idx]; ++ if (dev->rdd2_phy && r->band_idx == MT_RX_SEL2) ++ mphy = dev->rdd2_phy->mt76; ++ else ++ mphy = dev->mt76.phys[r->band_idx]; ++ + if (!mphy) + return; + +@@ -712,6 +716,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, + struct cfg80211_chan_def *chandef = &phy->chandef; + struct mt76_connac_bss_basic_tlv *bss; + u32 type = CONNECTION_INFRA_AP; ++ u16 sta_wlan_idx = wlan_idx; + struct tlv *tlv; + int idx; + +@@ -731,7 +736,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, + struct mt76_wcid *wcid; + + wcid = (struct mt76_wcid *)sta->drv_priv; +- wlan_idx = wcid->idx; ++ sta_wlan_idx = wcid->idx; + } + rcu_read_unlock(); + } +@@ -751,7 +756,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, + bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + bss->dtim_period = vif->bss_conf.dtim_period; + bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); +- bss->sta_idx = cpu_to_le16(wlan_idx); ++ bss->sta_idx = cpu_to_le16(sta_wlan_idx); + bss->conn_type = cpu_to_le32(type); + bss->omac_idx = mvif->omac_idx; + bss->band_idx = mvif->band_idx; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +index 4d7dcb95a620a..b8bcad717d89f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +@@ -26,6 +26,7 @@ + + #define MT7996_RX_RING_SIZE 1536 + #define MT7996_RX_MCU_RING_SIZE 512 ++#define MT7996_RX_MCU_RING_SIZE_WA 1024 + + #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin" + #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin" +diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c +index 0accc71a91c9a..4644dace9bb34 100644 +--- a/drivers/net/wireless/mediatek/mt76/testmode.c ++++ b/drivers/net/wireless/mediatek/mt76/testmode.c +@@ -8,6 +8,7 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { + [MT76_TM_ATTR_RESET] = { .type = NLA_FLAG }, + [MT76_TM_ATTR_STATE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 }, ++ [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 }, + [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 }, +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index 72b3ec715e47a..e9b9728458a9b 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -121,6 +121,7 @@ int + mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, + struct sk_buff *skb) + { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); + int pid; +@@ -134,8 +135,14 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, + return MT_PACKET_ID_NO_ACK; + + if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | +- IEEE80211_TX_CTL_RATE_CTRL_PROBE))) ++ IEEE80211_TX_CTL_RATE_CTRL_PROBE))) { ++ if (mtk_wed_device_active(&dev->mmio.wed) && ++ ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) || ++ ieee80211_is_data(hdr->frame_control))) ++ return MT_PACKET_ID_WED; ++ + return MT_PACKET_ID_NO_SKB; ++ } + + spin_lock_bh(&dev->status_lock); + +diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c +index 858494ddfb12e..9bb09fdf931ab 100644 +--- a/drivers/net/wireless/realtek/rtw89/debug.c ++++ b/drivers/net/wireless/realtek/rtw89/debug.c +@@ -3165,12 +3165,14 @@ static ssize_t rtw89_debug_priv_btc_manual_set(struct file *filp, + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw89_btc *btc = &rtwdev->btc; + bool btc_manual; ++ int ret; + +- if (kstrtobool_from_user(user_buf, count, &btc_manual)) +- goto out; ++ ret = kstrtobool_from_user(user_buf, count, &btc_manual); ++ if (ret) ++ return ret; + + btc->ctrl.manual = btc_manual; +-out: ++ + return count; + } + +diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c +index b9b675bf9d050..60b201b24332f 100644 +--- a/drivers/net/wireless/realtek/rtw89/fw.c ++++ b/drivers/net/wireless/realtek/rtw89/fw.c +@@ -305,31 +305,17 @@ rtw89_early_fw_feature_recognize(struct device *device, + struct rtw89_fw_info *early_fw, + int *used_fw_format) + { +- union rtw89_compat_fw_hdr buf = {}; + const struct firmware *firmware; +- bool full_req = false; + char fw_name[64]; + int fw_format; + u32 ver_code; + int ret; + +- /* If SECURITY_LOADPIN_ENFORCE is enabled, reading partial files will +- * be denied (-EPERM). Then, we don't get right firmware things as +- * expected. So, in this case, we have to request full firmware here. +- */ +- if (IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE)) +- full_req = true; +- + for (fw_format = chip->fw_format_max; fw_format >= 0; fw_format--) { + rtw89_fw_get_filename(fw_name, sizeof(fw_name), + chip->fw_basename, fw_format); + +- if (full_req) +- ret = request_firmware(&firmware, fw_name, device); +- else +- ret = request_partial_firmware_into_buf(&firmware, fw_name, +- device, &buf, sizeof(buf), +- 0); ++ ret = request_firmware(&firmware, fw_name, device); + if (!ret) { + dev_info(device, "loaded firmware %s\n", fw_name); + *used_fw_format = fw_format; +@@ -342,10 +328,7 @@ rtw89_early_fw_feature_recognize(struct device *device, + return NULL; + } + +- if (full_req) +- ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data); +- else +- ver_code = rtw89_compat_fw_hdr_ver_code(&buf); ++ ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data); + + if (!ver_code) + goto out; +@@ -353,11 +336,7 @@ rtw89_early_fw_feature_recognize(struct device *device, + rtw89_fw_iterate_feature_cfg(early_fw, chip, ver_code); + + out: +- if (full_req) +- return firmware; +- +- release_firmware(firmware); +- return NULL; ++ return firmware; + } + + int rtw89_fw_recognize(struct rtw89_dev *rtwdev) +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +index 722ae34b09c1f..b6fccb1cb7a5c 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +@@ -846,7 +846,7 @@ static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + case ID_NBTXK: + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x011); +- iqk_cmd = 0x308 | (1 << (4 + path)); ++ iqk_cmd = 0x408 | (1 << (4 + path)); + break; + case ID_NBRXK: + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); +@@ -1078,7 +1078,7 @@ static bool _iqk_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 + { + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail; +- u8 gp = 0x3; ++ u8 gp = 0x2; + + switch (iqk_info->iqk_band[path]) { + case RTW89_BAND_2G: +diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c +index 2abd2235bbcab..9532108d2dce1 100644 +--- a/drivers/ntb/ntb_transport.c ++++ b/drivers/ntb/ntb_transport.c +@@ -909,7 +909,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, + return 0; + } + +-static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp) ++static void ntb_qp_link_context_reset(struct ntb_transport_qp *qp) + { + qp->link_is_up = false; + qp->active = false; +@@ -932,6 +932,13 @@ static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp) + qp->tx_async = 0; + } + ++static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp) ++{ ++ ntb_qp_link_context_reset(qp); ++ if (qp->remote_rx_info) ++ qp->remote_rx_info->entry = qp->rx_max_entry - 1; ++} ++ + static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) + { + struct ntb_transport_ctx *nt = qp->transport; +@@ -1174,7 +1181,7 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, + qp->ndev = nt->ndev; + qp->client_ready = false; + qp->event_handler = NULL; +- ntb_qp_link_down_reset(qp); ++ ntb_qp_link_context_reset(qp); + + if (mw_num < qp_count % mw_count) + num_qps_mw = qp_count / mw_count + 1; +@@ -2276,9 +2283,13 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, + struct ntb_queue_entry *entry; + int rc; + +- if (!qp || !qp->link_is_up || !len) ++ if (!qp || !len) + return -EINVAL; + ++ /* If the qp link is down already, just ignore. */ ++ if (!qp->link_is_up) ++ return 0; ++ + entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); + if (!entry) { + qp->tx_err_no_buf++; +@@ -2418,7 +2429,7 @@ unsigned int ntb_transport_tx_free_entry(struct ntb_transport_qp *qp) + unsigned int head = qp->tx_index; + unsigned int tail = qp->remote_rx_info->entry; + +- return tail > head ? tail - head : qp->tx_max_entry + tail - head; ++ return tail >= head ? tail - head : qp->tx_max_entry + tail - head; + } + EXPORT_SYMBOL_GPL(ntb_transport_tx_free_entry); + +diff --git a/drivers/nvdimm/nd_perf.c b/drivers/nvdimm/nd_perf.c +index 433bbb68ae641..2b6dc80d8fb5b 100644 +--- a/drivers/nvdimm/nd_perf.c ++++ b/drivers/nvdimm/nd_perf.c +@@ -308,8 +308,8 @@ int register_nvdimm_pmu(struct nvdimm_pmu *nd_pmu, struct platform_device *pdev) + + rc = perf_pmu_register(&nd_pmu->pmu, nd_pmu->pmu.name, -1); + if (rc) { +- kfree(nd_pmu->pmu.attr_groups); + nvdimm_pmu_free_hotplug_memory(nd_pmu); ++ kfree(nd_pmu->pmu.attr_groups); + return rc; + } + +@@ -324,6 +324,7 @@ void unregister_nvdimm_pmu(struct nvdimm_pmu *nd_pmu) + { + perf_pmu_unregister(&nd_pmu->pmu); + nvdimm_pmu_free_hotplug_memory(nd_pmu); ++ kfree(nd_pmu->pmu.attr_groups); + kfree(nd_pmu); + } + EXPORT_SYMBOL_GPL(unregister_nvdimm_pmu); +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index c6a648fd8744a..1f8c667c6f1ee 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -105,7 +105,8 @@ int async_pmem_flush(struct nd_region *nd_region, struct bio *bio) + * parent bio. Otherwise directly call nd_region flush. + */ + if (bio && bio->bi_iter.bi_sector != -1) { +- struct bio *child = bio_alloc(bio->bi_bdev, 0, REQ_PREFLUSH, ++ struct bio *child = bio_alloc(bio->bi_bdev, 0, ++ REQ_OP_WRITE | REQ_PREFLUSH, + GFP_ATOMIC); + + if (!child) +diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c +index 7feb643f13707..28b479afd506f 100644 +--- a/drivers/of/overlay.c ++++ b/drivers/of/overlay.c +@@ -752,8 +752,6 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs) + if (!of_node_is_root(ovcs->overlay_root)) + pr_debug("%s() ovcs->overlay_root is not root\n", __func__); + +- of_changeset_init(&ovcs->cset); +- + cnt = 0; + + /* fragment nodes */ +@@ -1013,6 +1011,7 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, + + INIT_LIST_HEAD(&ovcs->ovcs_list); + list_add_tail(&ovcs->ovcs_list, &ovcs_list); ++ of_changeset_init(&ovcs->cset); + + /* + * Must create permanent copy of FDT because of_fdt_unflatten_tree() +diff --git a/drivers/of/property.c b/drivers/of/property.c +index ddc75cd50825e..cf8dacf3e3b84 100644 +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -1266,6 +1266,7 @@ DEFINE_SIMPLE_PROP(pwms, "pwms", "#pwm-cells") + DEFINE_SIMPLE_PROP(resets, "resets", "#reset-cells") + DEFINE_SIMPLE_PROP(leds, "leds", NULL) + DEFINE_SIMPLE_PROP(backlight, "backlight", NULL) ++DEFINE_SIMPLE_PROP(panel, "panel", NULL) + DEFINE_SUFFIX_PROP(regulators, "-supply", NULL) + DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells") + +@@ -1354,6 +1355,7 @@ static const struct supplier_bindings of_supplier_bindings[] = { + { .parse_prop = parse_resets, }, + { .parse_prop = parse_leds, }, + { .parse_prop = parse_backlight, }, ++ { .parse_prop = parse_panel, }, + { .parse_prop = parse_gpio_compat, }, + { .parse_prop = parse_interrupts, }, + { .parse_prop = parse_regulators, }, +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index 4fe02e9f7dcdd..03a1de841d3b7 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -77,7 +77,7 @@ static void __init of_unittest_find_node_by_name(void) + + np = of_find_node_by_path("/testcase-data"); + name = kasprintf(GFP_KERNEL, "%pOF", np); +- unittest(np && !strcmp("/testcase-data", name), ++ unittest(np && name && !strcmp("/testcase-data", name), + "find /testcase-data failed\n"); + of_node_put(np); + kfree(name); +@@ -88,14 +88,14 @@ static void __init of_unittest_find_node_by_name(void) + + np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); + name = kasprintf(GFP_KERNEL, "%pOF", np); +- unittest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", name), ++ unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name), + "find /testcase-data/phandle-tests/consumer-a failed\n"); + of_node_put(np); + kfree(name); + + np = of_find_node_by_path("testcase-alias"); + name = kasprintf(GFP_KERNEL, "%pOF", np); +- unittest(np && !strcmp("/testcase-data", name), ++ unittest(np && name && !strcmp("/testcase-data", name), + "find testcase-alias failed\n"); + of_node_put(np); + kfree(name); +@@ -106,7 +106,7 @@ static void __init of_unittest_find_node_by_name(void) + + np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a"); + name = kasprintf(GFP_KERNEL, "%pOF", np); +- unittest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", name), ++ unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name), + "find testcase-alias/phandle-tests/consumer-a failed\n"); + of_node_put(np); + kfree(name); +@@ -1533,6 +1533,8 @@ static void attach_node_and_children(struct device_node *np) + const char *full_name; + + full_name = kasprintf(GFP_KERNEL, "%pOF", np); ++ if (!full_name) ++ return; + + if (!strcmp(full_name, "/__local_fixups__") || + !strcmp(full_name, "/__fixups__")) { +@@ -2208,7 +2210,7 @@ static int __init of_unittest_apply_revert_overlay_check(int overlay_nr, + of_unittest_untrack_overlay(save_ovcs_id); + + /* unittest device must be again in before state */ +- if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) { ++ if (of_unittest_device_exists(unittest_nr, ovtype) != before) { + unittest(0, "%s with device @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr), + unittest_path(unittest_nr, ovtype), +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index b5973fefdfd83..75b43c6c7031c 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -2382,7 +2382,7 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev, + + virt_dev = dev_pm_domain_attach_by_name(dev, *name); + if (IS_ERR_OR_NULL(virt_dev)) { +- ret = PTR_ERR(virt_dev) ? : -ENODEV; ++ ret = virt_dev ? PTR_ERR(virt_dev) : -ENODEV; + dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret); + goto err; + } +diff --git a/drivers/pci/access.c b/drivers/pci/access.c +index 3c230ca3de584..0b2e90d2f04f2 100644 +--- a/drivers/pci/access.c ++++ b/drivers/pci/access.c +@@ -497,8 +497,8 @@ int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val) + } + EXPORT_SYMBOL(pcie_capability_write_dword); + +-int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, +- u16 clear, u16 set) ++int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos, ++ u16 clear, u16 set) + { + int ret; + u16 val; +@@ -512,7 +512,21 @@ int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, + + return ret; + } +-EXPORT_SYMBOL(pcie_capability_clear_and_set_word); ++EXPORT_SYMBOL(pcie_capability_clear_and_set_word_unlocked); ++ ++int pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos, ++ u16 clear, u16 set) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&dev->pcie_cap_lock, flags); ++ ret = pcie_capability_clear_and_set_word_unlocked(dev, pos, clear, set); ++ spin_unlock_irqrestore(&dev->pcie_cap_lock, flags); ++ ++ return ret; ++} ++EXPORT_SYMBOL(pcie_capability_clear_and_set_word_locked); + + int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, + u32 clear, u32 set) +diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c +index 19b32839ea261..043b356d7d72d 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c ++++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c +@@ -415,7 +415,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) + /* Gate Master AXI clock to MHI bus during L1SS */ + val = readl_relaxed(pcie_ep->parf + PARF_MHI_CLOCK_RESET_CTRL); + val &= ~PARF_MSTR_AXI_CLK_EN; +- val = readl_relaxed(pcie_ep->parf + PARF_MHI_CLOCK_RESET_CTRL); ++ writel_relaxed(val, pcie_ep->parf + PARF_MHI_CLOCK_RESET_CTRL); + + dw_pcie_ep_init_notify(&pcie_ep->pci.ep); + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index e6eec85480ca9..15c8077f503f0 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -883,11 +883,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp) + pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, + PCI_CAP_ID_EXP); + +- val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL); +- val_16 &= ~PCI_EXP_DEVCTL_PAYLOAD; +- val_16 |= PCI_EXP_DEVCTL_PAYLOAD_256B; +- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL, val_16); +- + val = dw_pcie_readl_dbi(pci, PCI_IO_BASE); + val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8); + dw_pcie_writel_dbi(pci, PCI_IO_BASE, val); +@@ -1876,11 +1871,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, + PCI_CAP_ID_EXP); + +- val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL); +- val_16 &= ~PCI_EXP_DEVCTL_PAYLOAD; +- val_16 |= PCI_EXP_DEVCTL_PAYLOAD_256B; +- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL, val_16); +- + /* Clear Slot Clock Configuration bit if SRNS configuration */ + if (pcie->enable_srns) { + val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + +diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c +index 2d93d0c4f10db..bed3cefdaf198 100644 +--- a/drivers/pci/controller/pci-hyperv.c ++++ b/drivers/pci/controller/pci-hyperv.c +@@ -3983,6 +3983,9 @@ static int hv_pci_restore_msi_msg(struct pci_dev *pdev, void *arg) + struct msi_desc *entry; + int ret = 0; + ++ if (!pdev->msi_enabled && !pdev->msix_enabled) ++ return 0; ++ + msi_lock_descs(&pdev->dev); + msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) { + irq_data = irq_get_irq_data(entry->irq); +diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c +index 66f37e403a09c..2340dab6cd5bd 100644 +--- a/drivers/pci/controller/pcie-apple.c ++++ b/drivers/pci/controller/pcie-apple.c +@@ -783,6 +783,10 @@ static int apple_pcie_init(struct pci_config_window *cfg) + cfg->priv = pcie; + INIT_LIST_HEAD(&pcie->ports); + ++ ret = apple_msi_init(pcie); ++ if (ret) ++ return ret; ++ + for_each_child_of_node(dev->of_node, of_port) { + ret = apple_pcie_setup_port(pcie, of_port); + if (ret) { +@@ -792,7 +796,7 @@ static int apple_pcie_init(struct pci_config_window *cfg) + } + } + +- return apple_msi_init(pcie); ++ return 0; + } + + static int apple_pcie_probe(struct platform_device *pdev) +diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c +index 5e710e4854646..dd5245904c874 100644 +--- a/drivers/pci/controller/pcie-microchip-host.c ++++ b/drivers/pci/controller/pcie-microchip-host.c +@@ -167,12 +167,12 @@ + #define EVENT_PCIE_DLUP_EXIT 2 + #define EVENT_SEC_TX_RAM_SEC_ERR 3 + #define EVENT_SEC_RX_RAM_SEC_ERR 4 +-#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 5 +-#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 6 ++#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 5 ++#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 6 + #define EVENT_DED_TX_RAM_DED_ERR 7 + #define EVENT_DED_RX_RAM_DED_ERR 8 +-#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 9 +-#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 10 ++#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 9 ++#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 10 + #define EVENT_LOCAL_DMA_END_ENGINE_0 11 + #define EVENT_LOCAL_DMA_END_ENGINE_1 12 + #define EVENT_LOCAL_DMA_ERROR_ENGINE_0 13 +diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h +index fe0333778fd93..6111de35f84ca 100644 +--- a/drivers/pci/controller/pcie-rockchip.h ++++ b/drivers/pci/controller/pcie-rockchip.h +@@ -158,7 +158,9 @@ + #define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274) + #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20) + +-#define PCIE_ADDR_MASK 0xffffff00 ++#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3 ++#define MIN_AXI_ADDR_BITS_PASSED 8 ++#define PCIE_ADDR_MASK GENMASK_ULL(63, MIN_AXI_ADDR_BITS_PASSED) + #define PCIE_CORE_AXI_CONF_BASE 0xc00000 + #define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0) + #define PCIE_CORE_OB_REGION_ADDR0_NUM_BITS 0x3f +@@ -185,8 +187,6 @@ + #define AXI_WRAPPER_TYPE1_CFG 0xb + #define AXI_WRAPPER_NOR_MSG 0xc + +-#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3 +-#define MIN_AXI_ADDR_BITS_PASSED 8 + #define PCIE_RC_SEND_PME_OFF 0x11960 + #define ROCKCHIP_VENDOR_ID 0x1d87 + #define PCIE_LINK_IS_L2(x) \ +diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c +index 1b97a5ab71a96..e3aab5edaf706 100644 +--- a/drivers/pci/doe.c ++++ b/drivers/pci/doe.c +@@ -293,8 +293,8 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas + static void signal_task_complete(struct pci_doe_task *task, int rv) + { + task->rv = rv; +- task->complete(task); + destroy_work_on_stack(&task->work); ++ task->complete(task); + } + + static void signal_task_abort(struct pci_doe_task *task, int rv) +diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c +index f8c70115b6917..5deb45d79f9de 100644 +--- a/drivers/pci/hotplug/pciehp_hpc.c ++++ b/drivers/pci/hotplug/pciehp_hpc.c +@@ -332,17 +332,11 @@ int pciehp_check_link_status(struct controller *ctrl) + static int __pciehp_link_set(struct controller *ctrl, bool enable) + { + struct pci_dev *pdev = ctrl_dev(ctrl); +- u16 lnk_ctrl; + +- pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl); ++ pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_LD, ++ enable ? 0 : PCI_EXP_LNKCTL_LD); + +- if (enable) +- lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; +- else +- lnk_ctrl |= PCI_EXP_LNKCTL_LD; +- +- pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl); +- ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); + return 0; + } + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index c779eb4d7fb84..499c7ffa4e3b2 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1200,6 +1200,10 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) + * + * On success, return 0 or 1, depending on whether or not it is necessary to + * restore the device's BARs subsequently (1 is returned in that case). ++ * ++ * On failure, return a negative error code. Always return failure if @dev ++ * lacks a Power Management Capability, even if the platform was able to ++ * put the device in D0 via non-PCI means. + */ + int pci_power_up(struct pci_dev *dev) + { +@@ -1216,9 +1220,6 @@ int pci_power_up(struct pci_dev *dev) + else + dev->current_state = state; + +- if (state == PCI_D0) +- return 0; +- + return -EIO; + } + +@@ -1276,8 +1277,12 @@ static int pci_set_full_power_state(struct pci_dev *dev) + int ret; + + ret = pci_power_up(dev); +- if (ret < 0) ++ if (ret < 0) { ++ if (dev->current_state == PCI_D0) ++ return 0; ++ + return ret; ++ } + + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + dev->current_state = pmcsr & PCI_PM_CTRL_STATE_MASK; +diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c +index 998e26de2ad76..75e51b965c0b7 100644 +--- a/drivers/pci/pcie/aspm.c ++++ b/drivers/pci/pcie/aspm.c +@@ -250,7 +250,7 @@ static int pcie_retrain_link(struct pcie_link_state *link) + static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) + { + int same_clock = 1; +- u16 reg16, parent_reg, child_reg[8]; ++ u16 reg16, ccc, parent_old_ccc, child_old_ccc[8]; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; + /* +@@ -272,6 +272,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) + + /* Port might be already in common clock mode */ + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); ++ parent_old_ccc = reg16 & PCI_EXP_LNKCTL_CCC; + if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) { + bool consistent = true; + +@@ -288,34 +289,29 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) + pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n"); + } + ++ ccc = same_clock ? PCI_EXP_LNKCTL_CCC : 0; + /* Configure downstream component, all functions */ + list_for_each_entry(child, &linkbus->devices, bus_list) { + pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16); +- child_reg[PCI_FUNC(child->devfn)] = reg16; +- if (same_clock) +- reg16 |= PCI_EXP_LNKCTL_CCC; +- else +- reg16 &= ~PCI_EXP_LNKCTL_CCC; +- pcie_capability_write_word(child, PCI_EXP_LNKCTL, reg16); ++ child_old_ccc[PCI_FUNC(child->devfn)] = reg16 & PCI_EXP_LNKCTL_CCC; ++ pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_CCC, ccc); + } + + /* Configure upstream component */ +- pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); +- parent_reg = reg16; +- if (same_clock) +- reg16 |= PCI_EXP_LNKCTL_CCC; +- else +- reg16 &= ~PCI_EXP_LNKCTL_CCC; +- pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); ++ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_CCC, ccc); + + if (pcie_retrain_link(link)) { + + /* Training failed. Restore common clock configurations */ + pci_err(parent, "ASPM: Could not configure common clock\n"); + list_for_each_entry(child, &linkbus->devices, bus_list) +- pcie_capability_write_word(child, PCI_EXP_LNKCTL, +- child_reg[PCI_FUNC(child->devfn)]); +- pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); ++ pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_CCC, ++ child_old_ccc[PCI_FUNC(child->devfn)]); ++ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_CCC, parent_old_ccc); + } + } + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 00ed20ac0dd61..a7af7ece98f07 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -999,6 +999,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + res = window->res; + if (!res->flags && !res->start && !res->end) { + release_resource(res); ++ resource_list_destroy_entry(window); + continue; + } + +@@ -2320,6 +2321,7 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus) + .end = -1, + }; + ++ spin_lock_init(&dev->pcie_cap_lock); + #ifdef CONFIG_PCI_MSI + raw_spin_lock_init(&dev->msi_lock); + #endif +diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c +index 5222ba1e79d0e..c684aab407f86 100644 +--- a/drivers/perf/fsl_imx8_ddr_perf.c ++++ b/drivers/perf/fsl_imx8_ddr_perf.c +@@ -101,6 +101,7 @@ struct ddr_pmu { + const struct fsl_ddr_devtype_data *devtype_data; + int irq; + int id; ++ int active_counter; + }; + + static ssize_t ddr_perf_identifier_show(struct device *dev, +@@ -495,6 +496,10 @@ static void ddr_perf_event_start(struct perf_event *event, int flags) + + ddr_perf_counter_enable(pmu, event->attr.config, counter, true); + ++ if (!pmu->active_counter++) ++ ddr_perf_counter_enable(pmu, EVENT_CYCLES_ID, ++ EVENT_CYCLES_COUNTER, true); ++ + hwc->state = 0; + } + +@@ -548,6 +553,10 @@ static void ddr_perf_event_stop(struct perf_event *event, int flags) + ddr_perf_counter_enable(pmu, event->attr.config, counter, false); + ddr_perf_event_update(event); + ++ if (!--pmu->active_counter) ++ ddr_perf_counter_enable(pmu, EVENT_CYCLES_ID, ++ EVENT_CYCLES_COUNTER, false); ++ + hwc->state |= PERF_HES_STOPPED; + } + +@@ -565,25 +574,10 @@ static void ddr_perf_event_del(struct perf_event *event, int flags) + + static void ddr_perf_pmu_enable(struct pmu *pmu) + { +- struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu); +- +- /* enable cycle counter if cycle is not active event list */ +- if (ddr_pmu->events[EVENT_CYCLES_COUNTER] == NULL) +- ddr_perf_counter_enable(ddr_pmu, +- EVENT_CYCLES_ID, +- EVENT_CYCLES_COUNTER, +- true); + } + + static void ddr_perf_pmu_disable(struct pmu *pmu) + { +- struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu); +- +- if (ddr_pmu->events[EVENT_CYCLES_COUNTER] == NULL) +- ddr_perf_counter_enable(ddr_pmu, +- EVENT_CYCLES_ID, +- EVENT_CYCLES_COUNTER, +- false); + } + + static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base, +diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +index 6170f8fd118e2..d0319bee01c0f 100644 +--- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c ++++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +@@ -214,8 +214,7 @@ static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev) + if (!hsphy->phy_initialized) + return 0; + +- qcom_snps_hsphy_suspend(hsphy); +- return 0; ++ return qcom_snps_hsphy_suspend(hsphy); + } + + static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev) +@@ -225,8 +224,7 @@ static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev) + if (!hsphy->phy_initialized) + return 0; + +- qcom_snps_hsphy_resume(hsphy); +- return 0; ++ return qcom_snps_hsphy_resume(hsphy); + } + + static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode, +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 1e1563f5fffc4..fbdc23953b52e 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -745,10 +745,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + } + +- inno->pixclock = vco; +- dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); ++ inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; + +- return vco; ++ dev_dbg(inno->dev, "%s rate %lu vco %llu\n", ++ __func__, inno->pixclock, vco); ++ ++ return inno->pixclock; + } + + static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, +@@ -790,8 +792,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + RK3328_PRE_PLL_POWER_DOWN); + + /* Configure pre-pll */ +- inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, +- RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); ++ inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, ++ RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); + inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); + + val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; +@@ -1021,9 +1023,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + + inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); + if (cfg->postdiv == 1) { +- inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); ++ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | ++ RK3328_POST_PLL_POWER_DOWN); + } else { + v = (cfg->postdiv / 2) - 1; + v &= RK3328_POST_PLL_POST_DIV_MASK; +@@ -1031,7 +1034,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); + inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | +- RK3328_POST_PLL_REFCLK_SEL_TMDS); ++ RK3328_POST_PLL_REFCLK_SEL_TMDS | ++ RK3328_POST_PLL_POWER_DOWN); + } + + for (v = 0; v < 14; v++) +diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c +index 18abc57800111..0fd2c0c451f95 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c +@@ -457,37 +457,15 @@ static const unsigned int mt7981_pull_type[] = { + MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/ + MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/ + MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PUPD_R1R0_TYPE,/*63*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/ +- MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/ +- MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/ +- MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/ +- MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/ +- MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/ +- MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/ +- MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/ +- MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/ +- MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/ +- MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/ +- MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/ +- MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/ +- MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/ +- MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/ +- MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/ +- MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/ +- MTK_PULL_PU_PD_TYPE,/*100*/ ++ MTK_PULL_PU_PD_TYPE,/*40*/ MTK_PULL_PU_PD_TYPE,/*41*/ ++ MTK_PULL_PU_PD_TYPE,/*42*/ MTK_PULL_PU_PD_TYPE,/*43*/ ++ MTK_PULL_PU_PD_TYPE,/*44*/ MTK_PULL_PU_PD_TYPE,/*45*/ ++ MTK_PULL_PU_PD_TYPE,/*46*/ MTK_PULL_PU_PD_TYPE,/*47*/ ++ MTK_PULL_PU_PD_TYPE,/*48*/ MTK_PULL_PU_PD_TYPE,/*49*/ ++ MTK_PULL_PU_PD_TYPE,/*50*/ MTK_PULL_PU_PD_TYPE,/*51*/ ++ MTK_PULL_PU_PD_TYPE,/*52*/ MTK_PULL_PU_PD_TYPE,/*53*/ ++ MTK_PULL_PU_PD_TYPE,/*54*/ MTK_PULL_PU_PD_TYPE,/*55*/ ++ MTK_PULL_PU_PD_TYPE,/*56*/ + }; + + static const struct mtk_pin_reg_calc mt7981_reg_cals[] = { +@@ -1014,6 +992,10 @@ static struct mtk_pin_soc mt7981_data = { + .ies_present = false, + .base_names = mt7981_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names), ++ .bias_disable_set = mtk_pinconf_bias_disable_set, ++ .bias_disable_get = mtk_pinconf_bias_disable_get, ++ .bias_set = mtk_pinconf_bias_set, ++ .bias_get = mtk_pinconf_bias_get, + .pull_type = mt7981_pull_type, + .bias_set_combo = mtk_pinconf_bias_set_combo, + .bias_get_combo = mtk_pinconf_bias_get_combo, +diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/drivers/pinctrl/mediatek/pinctrl-mt7986.c +index aa0ccd67f4f4e..acaac9b38aa8a 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c +@@ -922,6 +922,10 @@ static struct mtk_pin_soc mt7986a_data = { + .ies_present = false, + .base_names = mt7986_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names), ++ .bias_disable_set = mtk_pinconf_bias_disable_set, ++ .bias_disable_get = mtk_pinconf_bias_disable_get, ++ .bias_set = mtk_pinconf_bias_set, ++ .bias_get = mtk_pinconf_bias_get, + .pull_type = mt7986_pull_type, + .bias_set_combo = mtk_pinconf_bias_set_combo, + .bias_get_combo = mtk_pinconf_bias_get_combo, +@@ -944,6 +948,10 @@ static struct mtk_pin_soc mt7986b_data = { + .ies_present = false, + .base_names = mt7986_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names), ++ .bias_disable_set = mtk_pinconf_bias_disable_set, ++ .bias_disable_get = mtk_pinconf_bias_disable_get, ++ .bias_set = mtk_pinconf_bias_set, ++ .bias_get = mtk_pinconf_bias_get, + .pull_type = mt7986_pull_type, + .bias_set_combo = mtk_pinconf_bias_set_combo, + .bias_get_combo = mtk_pinconf_bias_get_combo, +diff --git a/drivers/pinctrl/pinctrl-mcp23s08_spi.c b/drivers/pinctrl/pinctrl-mcp23s08_spi.c +index 9ae10318f6f35..ea059b9c5542e 100644 +--- a/drivers/pinctrl/pinctrl-mcp23s08_spi.c ++++ b/drivers/pinctrl/pinctrl-mcp23s08_spi.c +@@ -91,18 +91,28 @@ static int mcp23s08_spi_regmap_init(struct mcp23s08 *mcp, struct device *dev, + mcp->reg_shift = 0; + mcp->chip.ngpio = 8; + mcp->chip.label = devm_kasprintf(dev, GFP_KERNEL, "mcp23s08.%d", addr); ++ if (!mcp->chip.label) ++ return -ENOMEM; + + config = &mcp23x08_regmap; + name = devm_kasprintf(dev, GFP_KERNEL, "%d", addr); ++ if (!name) ++ return -ENOMEM; ++ + break; + + case MCP_TYPE_S17: + mcp->reg_shift = 1; + mcp->chip.ngpio = 16; + mcp->chip.label = devm_kasprintf(dev, GFP_KERNEL, "mcp23s17.%d", addr); ++ if (!mcp->chip.label) ++ return -ENOMEM; + + config = &mcp23x17_regmap; + name = devm_kasprintf(dev, GFP_KERNEL, "%d", addr); ++ if (!name) ++ return -ENOMEM; ++ + break; + + case MCP_TYPE_S18: +diff --git a/drivers/platform/chrome/chromeos_acpi.c b/drivers/platform/chrome/chromeos_acpi.c +index 50d8a4d4352d6..1312aaaa8750b 100644 +--- a/drivers/platform/chrome/chromeos_acpi.c ++++ b/drivers/platform/chrome/chromeos_acpi.c +@@ -90,7 +90,36 @@ static int chromeos_acpi_handle_package(struct device *dev, union acpi_object *o + case ACPI_TYPE_STRING: + return sysfs_emit(buf, "%s\n", element->string.pointer); + case ACPI_TYPE_BUFFER: +- return sysfs_emit(buf, "%s\n", element->buffer.pointer); ++ { ++ int i, r, at, room_left; ++ const int byte_per_line = 16; ++ ++ at = 0; ++ room_left = PAGE_SIZE - 1; ++ for (i = 0; i < element->buffer.length && room_left; i += byte_per_line) { ++ r = hex_dump_to_buffer(element->buffer.pointer + i, ++ element->buffer.length - i, ++ byte_per_line, 1, buf + at, room_left, ++ false); ++ if (r > room_left) ++ goto truncating; ++ at += r; ++ room_left -= r; ++ ++ r = sysfs_emit_at(buf, at, "\n"); ++ if (!r) ++ goto truncating; ++ at += r; ++ room_left -= r; ++ } ++ ++ buf[at] = 0; ++ return at; ++truncating: ++ dev_info_once(dev, "truncating sysfs content for %s\n", name); ++ sysfs_emit_at(buf, PAGE_SIZE - 4, "..\n"); ++ return PAGE_SIZE - 1; ++ } + default: + dev_err(dev, "element type %d not supported\n", element->type); + return -EINVAL; +diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c +index a79318e90a139..b600b77d91ef2 100644 +--- a/drivers/platform/mellanox/mlxbf-tmfifo.c ++++ b/drivers/platform/mellanox/mlxbf-tmfifo.c +@@ -887,6 +887,7 @@ static bool mlxbf_tmfifo_virtio_notify(struct virtqueue *vq) + tm_vdev = fifo->vdev[VIRTIO_ID_CONSOLE]; + mlxbf_tmfifo_console_output(tm_vdev, vring); + spin_unlock_irqrestore(&fifo->spin_lock[0], flags); ++ set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events); + } else if (test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, + &fifo->pend_events)) { + return true; +diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c +index a022325161273..6fa33a05c5a75 100644 +--- a/drivers/platform/x86/amd/pmf/core.c ++++ b/drivers/platform/x86/amd/pmf/core.c +@@ -322,7 +322,8 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev) + + static void amd_pmf_deinit_features(struct amd_pmf_dev *dev) + { +- if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { ++ if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR) || ++ is_apmf_func_supported(dev, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { + power_supply_unreg_notifier(&dev->pwr_src_notifier); + amd_pmf_deinit_sps(dev); + } +diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c +index fd448844de206..b2cf62937227c 100644 +--- a/drivers/platform/x86/amd/pmf/sps.c ++++ b/drivers/platform/x86/amd/pmf/sps.c +@@ -121,7 +121,8 @@ int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) + + int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) + { +- u8 mode, flag = 0; ++ u8 flag = 0; ++ int mode; + int src; + + mode = amd_pmf_get_pprof_modes(dev); +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 1038dfdcdd325..8bef66a2f0ce7 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -738,13 +738,23 @@ static ssize_t kbd_rgb_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + { +- u32 cmd, mode, r, g, b, speed; ++ u32 cmd, mode, r, g, b, speed; + int err; + + if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6) + return -EINVAL; + +- cmd = !!cmd; ++ /* B3 is set and B4 is save to BIOS */ ++ switch (cmd) { ++ case 0: ++ cmd = 0xb3; ++ break; ++ case 1: ++ cmd = 0xb4; ++ break; ++ default: ++ return -EINVAL; ++ } + + /* These are the known usable modes across all TUF/ROG */ + if (mode >= 12 || mode == 9) +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +index 0285b47d99d13..1dd5aa37ecc8b 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +@@ -396,6 +396,7 @@ static int init_bios_attributes(int attr_type, const char *guid) + struct kobject *attr_name_kobj; //individual attribute names + union acpi_object *obj = NULL; + union acpi_object *elements; ++ struct kobject *duplicate; + struct kset *tmp_set; + int min_elements; + +@@ -454,9 +455,11 @@ static int init_bios_attributes(int attr_type, const char *guid) + else + tmp_set = wmi_priv.main_dir_kset; + +- if (kset_find_obj(tmp_set, elements[ATTR_NAME].string.pointer)) { +- pr_debug("duplicate attribute name found - %s\n", +- elements[ATTR_NAME].string.pointer); ++ duplicate = kset_find_obj(tmp_set, elements[ATTR_NAME].string.pointer); ++ if (duplicate) { ++ pr_debug("Duplicate attribute name found - %s\n", ++ elements[ATTR_NAME].string.pointer); ++ kobject_put(duplicate); + goto nextobj; + } + +diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c +index 70e5c4c0574d5..0ef1c46b617b6 100644 +--- a/drivers/platform/x86/huawei-wmi.c ++++ b/drivers/platform/x86/huawei-wmi.c +@@ -85,6 +85,8 @@ static const struct key_entry huawei_wmi_keymap[] = { + { KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } }, + { KE_IGNORE, 0x294, { KEY_KBDILLUMUP } }, + { KE_IGNORE, 0x295, { KEY_KBDILLUMUP } }, ++ // Ignore Ambient Light Sensoring ++ { KE_KEY, 0x2c1, { KEY_RESERVED } }, + { KE_END, 0 } + }; + +diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c +index 5632bd3c534a3..7457ca2b27a60 100644 +--- a/drivers/platform/x86/intel/hid.c ++++ b/drivers/platform/x86/intel/hid.c +@@ -150,6 +150,12 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite Dragonfly G2 Notebook PC"), ++ }, ++ }, + { } + }; + +@@ -620,7 +626,7 @@ static bool button_array_present(struct platform_device *device) + static int intel_hid_probe(struct platform_device *device) + { + acpi_handle handle = ACPI_HANDLE(&device->dev); +- unsigned long long mode; ++ unsigned long long mode, dummy; + struct intel_hid_priv *priv; + acpi_status status; + int err; +@@ -692,18 +698,15 @@ static int intel_hid_probe(struct platform_device *device) + if (err) + goto err_remove_notify; + +- if (priv->array) { +- unsigned long long dummy; ++ intel_button_array_enable(&device->dev, true); + +- intel_button_array_enable(&device->dev, true); +- +- /* Call button load method to enable HID power button */ +- if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN, +- &dummy)) { +- dev_warn(&device->dev, +- "failed to enable HID power button\n"); +- } +- } ++ /* ++ * Call button load method to enable HID power button ++ * Always do this since it activates events on some devices without ++ * a button array too. ++ */ ++ if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN, &dummy)) ++ dev_warn(&device->dev, "failed to enable HID power button\n"); + + device_init_wakeup(&device->dev, true); + /* +diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c +index e4047ee0a7546..63eca13fd882f 100644 +--- a/drivers/platform/x86/think-lmi.c ++++ b/drivers/platform/x86/think-lmi.c +@@ -719,12 +719,12 @@ static ssize_t cert_to_password_store(struct kobject *kobj, + /* Format: 'Password,Signature' */ + auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature); + if (!auth_str) { +- kfree(passwd); ++ kfree_sensitive(passwd); + return -ENOMEM; + } + ret = tlmi_simple_call(LENOVO_CERT_TO_PASSWORD_GUID, auth_str); + kfree(auth_str); +- kfree(passwd); ++ kfree_sensitive(passwd); + + return ret ?: count; + } +diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c +index 05d0e516176a5..5d7330280bd83 100644 +--- a/drivers/powercap/arm_scmi_powercap.c ++++ b/drivers/powercap/arm_scmi_powercap.c +@@ -12,6 +12,7 @@ + #include <linux/module.h> + #include <linux/powercap.h> + #include <linux/scmi_protocol.h> ++#include <linux/slab.h> + + #define to_scmi_powercap_zone(z) \ + container_of(z, struct scmi_powercap_zone, zone) +@@ -19,6 +20,8 @@ + static const struct scmi_powercap_proto_ops *powercap_ops; + + struct scmi_powercap_zone { ++ bool registered; ++ bool invalid; + unsigned int height; + struct device *dev; + struct scmi_protocol_handle *ph; +@@ -32,6 +35,7 @@ struct scmi_powercap_root { + unsigned int num_zones; + struct scmi_powercap_zone *spzones; + struct list_head *registered_zones; ++ struct list_head scmi_zones; + }; + + static struct powercap_control_type *scmi_top_pcntrl; +@@ -255,12 +259,6 @@ static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr) + } + } + +-static inline bool +-scmi_powercap_is_zone_registered(struct scmi_powercap_zone *spz) +-{ +- return !list_empty(&spz->node); +-} +- + static inline unsigned int + scmi_powercap_get_zone_height(struct scmi_powercap_zone *spz) + { +@@ -279,11 +277,46 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz) + return &spz->spzones[spz->info->parent_id]; + } + ++static int scmi_powercap_register_zone(struct scmi_powercap_root *pr, ++ struct scmi_powercap_zone *spz, ++ struct scmi_powercap_zone *parent) ++{ ++ int ret = 0; ++ struct powercap_zone *z; ++ ++ if (spz->invalid) { ++ list_del(&spz->node); ++ return -EINVAL; ++ } ++ ++ z = powercap_register_zone(&spz->zone, scmi_top_pcntrl, spz->info->name, ++ parent ? &parent->zone : NULL, ++ &zone_ops, 1, &constraint_ops); ++ if (!IS_ERR(z)) { ++ spz->height = scmi_powercap_get_zone_height(spz); ++ spz->registered = true; ++ list_move(&spz->node, &pr->registered_zones[spz->height]); ++ dev_dbg(spz->dev, "Registered node %s - parent %s - height:%d\n", ++ spz->info->name, parent ? parent->info->name : "ROOT", ++ spz->height); ++ } else { ++ list_del(&spz->node); ++ ret = PTR_ERR(z); ++ dev_err(spz->dev, ++ "Error registering node:%s - parent:%s - h:%d - ret:%d\n", ++ spz->info->name, ++ parent ? parent->info->name : "ROOT", ++ spz->height, ret); ++ } ++ ++ return ret; ++} ++ + /** +- * scmi_powercap_register_zone - Register an SCMI powercap zone recursively ++ * scmi_zones_register- Register SCMI powercap zones starting from parent zones + * ++ * @dev: A reference to the SCMI device + * @pr: A reference to the root powercap zones descriptors +- * @spz: A reference to the SCMI powercap zone to register + * + * When registering SCMI powercap zones with the powercap framework we should + * take care to always register zones starting from the root ones and to +@@ -293,10 +326,10 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz) + * zones provided by the SCMI platform firmware is built to comply with such + * requirement. + * +- * This function, given an SCMI powercap zone to register, takes care to walk +- * the SCMI powercap zones tree up to the root looking recursively for +- * unregistered parent zones before registering the provided zone; at the same +- * time each registered zone height in such a tree is accounted for and each ++ * This function, given the set of SCMI powercap zones to register, takes care ++ * to walk the SCMI powercap zones trees up to the root registering any ++ * unregistered parent zone before registering the child zones; at the same ++ * time each registered-zone height in such a tree is accounted for and each + * zone, once registered, is stored in the @registered_zones array that is + * indexed by zone height: this way will be trivial, at unregister time, to walk + * the @registered_zones array backward and unregister all the zones starting +@@ -314,57 +347,55 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz) + * + * Return: 0 on Success + */ +-static int scmi_powercap_register_zone(struct scmi_powercap_root *pr, +- struct scmi_powercap_zone *spz) ++static int scmi_zones_register(struct device *dev, ++ struct scmi_powercap_root *pr) + { + int ret = 0; +- struct scmi_powercap_zone *parent; +- +- if (!spz->info) +- return ret; ++ unsigned int sp = 0, reg_zones = 0; ++ struct scmi_powercap_zone *spz, **zones_stack; + +- parent = scmi_powercap_get_parent_zone(spz); +- if (parent && !scmi_powercap_is_zone_registered(parent)) { +- /* +- * Bail out if a parent domain was marked as unsupported: +- * only domains participating as leaves can be skipped. +- */ +- if (!parent->info) +- return -ENODEV; ++ zones_stack = kcalloc(pr->num_zones, sizeof(spz), GFP_KERNEL); ++ if (!zones_stack) ++ return -ENOMEM; + +- ret = scmi_powercap_register_zone(pr, parent); +- if (ret) +- return ret; +- } ++ spz = list_first_entry_or_null(&pr->scmi_zones, ++ struct scmi_powercap_zone, node); ++ while (spz) { ++ struct scmi_powercap_zone *parent; + +- if (!scmi_powercap_is_zone_registered(spz)) { +- struct powercap_zone *z; +- +- z = powercap_register_zone(&spz->zone, +- scmi_top_pcntrl, +- spz->info->name, +- parent ? &parent->zone : NULL, +- &zone_ops, 1, &constraint_ops); +- if (!IS_ERR(z)) { +- spz->height = scmi_powercap_get_zone_height(spz); +- list_add(&spz->node, +- &pr->registered_zones[spz->height]); +- dev_dbg(spz->dev, +- "Registered node %s - parent %s - height:%d\n", +- spz->info->name, +- parent ? parent->info->name : "ROOT", +- spz->height); +- ret = 0; ++ parent = scmi_powercap_get_parent_zone(spz); ++ if (parent && !parent->registered) { ++ zones_stack[sp++] = spz; ++ spz = parent; + } else { +- ret = PTR_ERR(z); +- dev_err(spz->dev, +- "Error registering node:%s - parent:%s - h:%d - ret:%d\n", +- spz->info->name, +- parent ? parent->info->name : "ROOT", +- spz->height, ret); ++ ret = scmi_powercap_register_zone(pr, spz, parent); ++ if (!ret) { ++ reg_zones++; ++ } else if (sp) { ++ /* Failed to register a non-leaf zone. ++ * Bail-out. ++ */ ++ dev_err(dev, ++ "Failed to register non-leaf zone - ret:%d\n", ++ ret); ++ scmi_powercap_unregister_all_zones(pr); ++ reg_zones = 0; ++ goto out; ++ } ++ /* Pick next zone to process */ ++ if (sp) ++ spz = zones_stack[--sp]; ++ else ++ spz = list_first_entry_or_null(&pr->scmi_zones, ++ struct scmi_powercap_zone, ++ node); + } + } + ++out: ++ kfree(zones_stack); ++ dev_info(dev, "Registered %d SCMI Powercap domains !\n", reg_zones); ++ + return ret; + } + +@@ -408,6 +439,8 @@ static int scmi_powercap_probe(struct scmi_device *sdev) + if (!pr->registered_zones) + return -ENOMEM; + ++ INIT_LIST_HEAD(&pr->scmi_zones); ++ + for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) { + /* + * Powercap domains are validate by the protocol layer, i.e. +@@ -422,6 +455,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev) + INIT_LIST_HEAD(&spz->node); + INIT_LIST_HEAD(&pr->registered_zones[i]); + ++ list_add_tail(&spz->node, &pr->scmi_zones); + /* + * Forcibly skip powercap domains using an abstract scale. + * Note that only leaves domains can be skipped, so this could +@@ -432,7 +466,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev) + dev_warn(dev, + "Abstract power scale not supported. Skip %s.\n", + spz->info->name); +- spz->info = NULL; ++ spz->invalid = true; + continue; + } + } +@@ -441,21 +475,12 @@ static int scmi_powercap_probe(struct scmi_device *sdev) + * Scan array of retrieved SCMI powercap domains and register them + * recursively starting from the root domains. + */ +- for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) { +- ret = scmi_powercap_register_zone(pr, spz); +- if (ret) { +- dev_err(dev, +- "Failed to register powercap zone %s - ret:%d\n", +- spz->info->name, ret); +- scmi_powercap_unregister_all_zones(pr); +- return ret; +- } +- } ++ ret = scmi_zones_register(dev, pr); ++ if (ret) ++ return ret; + + dev_set_drvdata(dev, pr); + +- dev_info(dev, "Registered %d SCMI Powercap domains !\n", pr->num_zones); +- + return ret; + } + +diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c +index 1beb40a1d3df2..e4015db99899d 100644 +--- a/drivers/rpmsg/qcom_glink_native.c ++++ b/drivers/rpmsg/qcom_glink_native.c +@@ -221,6 +221,10 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, + + channel->glink = glink; + channel->name = kstrdup(name, GFP_KERNEL); ++ if (!channel->name) { ++ kfree(channel); ++ return ERR_PTR(-ENOMEM); ++ } + + init_completion(&channel->open_req); + init_completion(&channel->open_ack); +diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c +index 9fbfce735d565..50c48a48fcae3 100644 +--- a/drivers/s390/block/dasd.c ++++ b/drivers/s390/block/dasd.c +@@ -2938,41 +2938,32 @@ static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data) + * Requeue a request back to the block request queue + * only works for block requests + */ +-static int _dasd_requeue_request(struct dasd_ccw_req *cqr) ++static void _dasd_requeue_request(struct dasd_ccw_req *cqr) + { +- struct dasd_block *block = cqr->block; + struct request *req; + +- if (!block) +- return -EINVAL; + /* + * If the request is an ERP request there is nothing to requeue. + * This will be done with the remaining original request. + */ + if (cqr->refers) +- return 0; ++ return; + spin_lock_irq(&cqr->dq->lock); + req = (struct request *) cqr->callback_data; + blk_mq_requeue_request(req, true); + spin_unlock_irq(&cqr->dq->lock); + +- return 0; ++ return; + } + +-/* +- * Go through all request on the dasd_block request queue, cancel them +- * on the respective dasd_device, and return them to the generic +- * block layer. +- */ +-static int dasd_flush_block_queue(struct dasd_block *block) ++static int _dasd_requests_to_flushqueue(struct dasd_block *block, ++ struct list_head *flush_queue) + { + struct dasd_ccw_req *cqr, *n; +- int rc, i; +- struct list_head flush_queue; + unsigned long flags; ++ int rc, i; + +- INIT_LIST_HEAD(&flush_queue); +- spin_lock_bh(&block->queue_lock); ++ spin_lock_irqsave(&block->queue_lock, flags); + rc = 0; + restart: + list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) { +@@ -2987,13 +2978,32 @@ restart: + * is returned from the dasd_device layer. + */ + cqr->callback = _dasd_wake_block_flush_cb; +- for (i = 0; cqr != NULL; cqr = cqr->refers, i++) +- list_move_tail(&cqr->blocklist, &flush_queue); ++ for (i = 0; cqr; cqr = cqr->refers, i++) ++ list_move_tail(&cqr->blocklist, flush_queue); + if (i > 1) + /* moved more than one request - need to restart */ + goto restart; + } +- spin_unlock_bh(&block->queue_lock); ++ spin_unlock_irqrestore(&block->queue_lock, flags); ++ ++ return rc; ++} ++ ++/* ++ * Go through all request on the dasd_block request queue, cancel them ++ * on the respective dasd_device, and return them to the generic ++ * block layer. ++ */ ++static int dasd_flush_block_queue(struct dasd_block *block) ++{ ++ struct dasd_ccw_req *cqr, *n; ++ struct list_head flush_queue; ++ unsigned long flags; ++ int rc; ++ ++ INIT_LIST_HEAD(&flush_queue); ++ rc = _dasd_requests_to_flushqueue(block, &flush_queue); ++ + /* Now call the callback function of flushed requests */ + restart_cb: + list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) { +@@ -3878,75 +3888,36 @@ EXPORT_SYMBOL_GPL(dasd_generic_space_avail); + */ + int dasd_generic_requeue_all_requests(struct dasd_device *device) + { ++ struct dasd_block *block = device->block; + struct list_head requeue_queue; + struct dasd_ccw_req *cqr, *n; +- struct dasd_ccw_req *refers; + int rc; + +- INIT_LIST_HEAD(&requeue_queue); +- spin_lock_irq(get_ccwdev_lock(device->cdev)); +- rc = 0; +- list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { +- /* Check status and move request to flush_queue */ +- if (cqr->status == DASD_CQR_IN_IO) { +- rc = device->discipline->term_IO(cqr); +- if (rc) { +- /* unable to terminate requeust */ +- dev_err(&device->cdev->dev, +- "Unable to terminate request %p " +- "on suspend\n", cqr); +- spin_unlock_irq(get_ccwdev_lock(device->cdev)); +- dasd_put_device(device); +- return rc; +- } +- } +- list_move_tail(&cqr->devlist, &requeue_queue); +- } +- spin_unlock_irq(get_ccwdev_lock(device->cdev)); +- +- list_for_each_entry_safe(cqr, n, &requeue_queue, devlist) { +- wait_event(dasd_flush_wq, +- (cqr->status != DASD_CQR_CLEAR_PENDING)); ++ if (!block) ++ return 0; + +- /* +- * requeue requests to blocklayer will only work +- * for block device requests +- */ +- if (_dasd_requeue_request(cqr)) +- continue; ++ INIT_LIST_HEAD(&requeue_queue); ++ rc = _dasd_requests_to_flushqueue(block, &requeue_queue); + +- /* remove requests from device and block queue */ +- list_del_init(&cqr->devlist); +- while (cqr->refers != NULL) { +- refers = cqr->refers; +- /* remove the request from the block queue */ +- list_del(&cqr->blocklist); +- /* free the finished erp request */ +- dasd_free_erp_request(cqr, cqr->memdev); +- cqr = refers; ++ /* Now call the callback function of flushed requests */ ++restart_cb: ++ list_for_each_entry_safe(cqr, n, &requeue_queue, blocklist) { ++ wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED)); ++ /* Process finished ERP request. */ ++ if (cqr->refers) { ++ spin_lock_bh(&block->queue_lock); ++ __dasd_process_erp(block->base, cqr); ++ spin_unlock_bh(&block->queue_lock); ++ /* restart list_for_xx loop since dasd_process_erp ++ * might remove multiple elements ++ */ ++ goto restart_cb; + } +- +- /* +- * _dasd_requeue_request already checked for a valid +- * blockdevice, no need to check again +- * all erp requests (cqr->refers) have a cqr->block +- * pointer copy from the original cqr +- */ ++ _dasd_requeue_request(cqr); + list_del_init(&cqr->blocklist); + cqr->block->base->discipline->free_cp( + cqr, (struct request *) cqr->callback_data); + } +- +- /* +- * if requests remain then they are internal request +- * and go back to the device queue +- */ +- if (!list_empty(&requeue_queue)) { +- /* move freeze_queue to start of the ccw_queue */ +- spin_lock_irq(get_ccwdev_lock(device->cdev)); +- list_splice_tail(&requeue_queue, &device->ccw_queue); +- spin_unlock_irq(get_ccwdev_lock(device->cdev)); +- } + dasd_schedule_device_bh(device); + return rc; + } +diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c +index f0f210627cadf..89957bb7244d2 100644 +--- a/drivers/s390/block/dasd_3990_erp.c ++++ b/drivers/s390/block/dasd_3990_erp.c +@@ -2441,7 +2441,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) + erp->block = cqr->block; + erp->magic = cqr->magic; + erp->expires = cqr->expires; +- erp->retries = 256; ++ erp->retries = device->default_retries; + erp->buildclk = get_tod_clock(); + erp->status = DASD_CQR_FILLED; + +diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c +index 620fab01b710b..c4e36650c4264 100644 +--- a/drivers/s390/block/dasd_devmap.c ++++ b/drivers/s390/block/dasd_devmap.c +@@ -1378,16 +1378,12 @@ static ssize_t dasd_vendor_show(struct device *dev, + + static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); + +-#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ +- /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 +\ +- /* vduit */ 32 + 1) +- + static ssize_t + dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) + { ++ char uid_string[DASD_UID_STRLEN]; + struct dasd_device *device; + struct dasd_uid uid; +- char uid_string[UID_STRLEN]; + char ua_string[3]; + + device = dasd_device_from_cdev(to_ccwdev(dev)); +diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c +index 113c509bf6d05..718ac726ffced 100644 +--- a/drivers/s390/block/dasd_eckd.c ++++ b/drivers/s390/block/dasd_eckd.c +@@ -1079,12 +1079,12 @@ static void dasd_eckd_get_uid_string(struct dasd_conf *conf, + + create_uid(conf, &uid); + if (strlen(uid.vduit) > 0) +- snprintf(print_uid, sizeof(*print_uid), ++ snprintf(print_uid, DASD_UID_STRLEN, + "%s.%s.%04x.%02x.%s", + uid.vendor, uid.serial, uid.ssid, + uid.real_unit_addr, uid.vduit); + else +- snprintf(print_uid, sizeof(*print_uid), ++ snprintf(print_uid, DASD_UID_STRLEN, + "%s.%s.%04x.%02x", + uid.vendor, uid.serial, uid.ssid, + uid.real_unit_addr); +@@ -1093,8 +1093,8 @@ static void dasd_eckd_get_uid_string(struct dasd_conf *conf, + static int dasd_eckd_check_cabling(struct dasd_device *device, + void *conf_data, __u8 lpm) + { ++ char print_path_uid[DASD_UID_STRLEN], print_device_uid[DASD_UID_STRLEN]; + struct dasd_eckd_private *private = device->private; +- char print_path_uid[60], print_device_uid[60]; + struct dasd_conf path_conf; + + path_conf.data = conf_data; +@@ -1293,9 +1293,9 @@ static void dasd_eckd_path_available_action(struct dasd_device *device, + __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE]; + __u8 lpm, opm, npm, ppm, epm, hpfpm, cablepm; + struct dasd_conf_data *conf_data; ++ char print_uid[DASD_UID_STRLEN]; + struct dasd_conf path_conf; + unsigned long flags; +- char print_uid[60]; + int rc, pos; + + opm = 0; +@@ -5855,8 +5855,8 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, + static int dasd_eckd_reload_device(struct dasd_device *device) + { + struct dasd_eckd_private *private = device->private; ++ char print_uid[DASD_UID_STRLEN]; + int rc, old_base; +- char print_uid[60]; + struct dasd_uid uid; + unsigned long flags; + +diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h +index 33f812f0e5150..966b915ef22cb 100644 +--- a/drivers/s390/block/dasd_int.h ++++ b/drivers/s390/block/dasd_int.h +@@ -259,6 +259,10 @@ struct dasd_uid { + char vduit[33]; + }; + ++#define DASD_UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 + \ ++ /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 + \ ++ /* vduit */ 32 + 1) ++ + /* + * PPRC Status data + */ +diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c +index c09f2e053bf86..cbf03d68283bb 100644 +--- a/drivers/s390/block/dcssblk.c ++++ b/drivers/s390/block/dcssblk.c +@@ -411,6 +411,7 @@ removeseg: + } + list_del(&dev_info->lh); + ++ dax_remove_host(dev_info->gd); + kill_dax(dev_info->dax_dev); + put_dax(dev_info->dax_dev); + del_gendisk(dev_info->gd); +@@ -706,9 +707,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char + goto out; + + out_dax_host: ++ put_device(&dev_info->dev); + dax_remove_host(dev_info->gd); + out_dax: +- put_device(&dev_info->dev); + kill_dax(dev_info->dax_dev); + put_dax(dev_info->dax_dev); + put_dev: +@@ -788,6 +789,7 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch + } + + list_del(&dev_info->lh); ++ dax_remove_host(dev_info->gd); + kill_dax(dev_info->dax_dev); + put_dax(dev_info->dax_dev); + del_gendisk(dev_info->gd); +diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c +index a8def50c149bd..2b92ec20ed68e 100644 +--- a/drivers/s390/crypto/pkey_api.c ++++ b/drivers/s390/crypto/pkey_api.c +@@ -565,6 +565,11 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + if (*keybufsize < MINEP11AESKEYBLOBSIZE) + return -EINVAL; + break; ++ case PKEY_TYPE_EP11_AES: ++ if (*keybufsize < (sizeof(struct ep11kblob_header) + ++ MINEP11AESKEYBLOBSIZE)) ++ return -EINVAL; ++ break; + default: + return -EINVAL; + } +@@ -581,9 +586,10 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; +- if (ktype == PKEY_TYPE_EP11) { ++ if (ktype == PKEY_TYPE_EP11 || ++ ktype == PKEY_TYPE_EP11_AES) { + rc = ep11_genaeskey(card, dom, ksize, kflags, +- keybuf, keybufsize); ++ keybuf, keybufsize, ktype); + } else if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_genseckey(card, dom, ksize, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); +@@ -747,7 +753,7 @@ static int pkey_verifykey2(const u8 *key, size_t keylen, + if (ktype) + *ktype = PKEY_TYPE_EP11; + if (ksize) +- *ksize = kb->head.keybitlen; ++ *ksize = kb->head.bitlen; + + rc = ep11_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX7, EP11_API_V, kb->wkvp); +@@ -1313,7 +1319,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, + apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); +- kkey = kmalloc(klen, GFP_KERNEL); ++ kkey = kzalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); + return -ENOMEM; +@@ -1941,7 +1947,7 @@ static struct attribute_group ccacipher_attr_group = { + * (i.e. off != 0 or count < key blob size) -EINVAL is returned. + * This function and the sysfs attributes using it provide EP11 key blobs + * padded to the upper limit of MAXEP11AESKEYBLOBSIZE which is currently +- * 320 bytes. ++ * 336 bytes. + */ + static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits, + bool is_xts, char *buf, loff_t off, +@@ -1969,7 +1975,8 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits, + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i] >> 16; + dom = apqns[i] & 0xFFFF; +- rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize); ++ rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize, ++ PKEY_TYPE_EP11_AES); + if (rc == 0) + break; + } +@@ -1979,7 +1986,8 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits, + if (is_xts) { + keysize = MAXEP11AESKEYBLOBSIZE; + buf += MAXEP11AESKEYBLOBSIZE; +- rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize); ++ rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize, ++ PKEY_TYPE_EP11_AES); + if (rc == 0) + return 2 * MAXEP11AESKEYBLOBSIZE; + } +diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c +index f67d19d08571b..0cd0395fa17fc 100644 +--- a/drivers/s390/crypto/zcrypt_ep11misc.c ++++ b/drivers/s390/crypto/zcrypt_ep11misc.c +@@ -113,6 +113,50 @@ static void __exit card_cache_free(void) + spin_unlock_bh(&card_list_lock); + } + ++static int ep11_kb_split(const u8 *kb, size_t kblen, u32 kbver, ++ struct ep11kblob_header **kbhdr, size_t *kbhdrsize, ++ u8 **kbpl, size_t *kbplsize) ++{ ++ struct ep11kblob_header *hdr = NULL; ++ size_t hdrsize, plsize = 0; ++ int rc = -EINVAL; ++ u8 *pl = NULL; ++ ++ if (kblen < sizeof(struct ep11kblob_header)) ++ goto out; ++ hdr = (struct ep11kblob_header *)kb; ++ ++ switch (kbver) { ++ case TOKVER_EP11_AES: ++ /* header overlays the payload */ ++ hdrsize = 0; ++ break; ++ case TOKVER_EP11_ECC_WITH_HEADER: ++ case TOKVER_EP11_AES_WITH_HEADER: ++ /* payload starts after the header */ ++ hdrsize = sizeof(struct ep11kblob_header); ++ break; ++ default: ++ goto out; ++ } ++ ++ plsize = kblen - hdrsize; ++ pl = (u8 *)kb + hdrsize; ++ ++ if (kbhdr) ++ *kbhdr = hdr; ++ if (kbhdrsize) ++ *kbhdrsize = hdrsize; ++ if (kbpl) ++ *kbpl = pl; ++ if (kbplsize) ++ *kbplsize = plsize; ++ ++ rc = 0; ++out: ++ return rc; ++} ++ + /* + * Simple check if the key blob is a valid EP11 AES key blob with header. + */ +@@ -664,8 +708,9 @@ EXPORT_SYMBOL(ep11_get_domain_info); + */ + #define KEY_ATTR_DEFAULTS 0x00200c00 + +-int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, +- u8 *keybuf, size_t *keybufsize) ++static int _ep11_genaeskey(u16 card, u16 domain, ++ u32 keybitsize, u32 keygenflags, ++ u8 *keybuf, size_t *keybufsize) + { + struct keygen_req_pl { + struct pl_head head; +@@ -701,7 +746,6 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, + struct ep11_cprb *req = NULL, *rep = NULL; + struct ep11_target_dev target; + struct ep11_urb *urb = NULL; +- struct ep11keyblob *kb; + int api, rc = -ENOMEM; + + switch (keybitsize) { +@@ -780,14 +824,9 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, + goto out; + } + +- /* copy key blob and set header values */ ++ /* copy key blob */ + memcpy(keybuf, rep_pl->data, rep_pl->data_len); + *keybufsize = rep_pl->data_len; +- kb = (struct ep11keyblob *)keybuf; +- kb->head.type = TOKTYPE_NON_CCA; +- kb->head.len = rep_pl->data_len; +- kb->head.version = TOKVER_EP11_AES; +- kb->head.keybitlen = keybitsize; + + out: + kfree(req); +@@ -795,6 +834,43 @@ out: + kfree(urb); + return rc; + } ++ ++int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, ++ u8 *keybuf, size_t *keybufsize, u32 keybufver) ++{ ++ struct ep11kblob_header *hdr; ++ size_t hdr_size, pl_size; ++ u8 *pl; ++ int rc; ++ ++ switch (keybufver) { ++ case TOKVER_EP11_AES: ++ case TOKVER_EP11_AES_WITH_HEADER: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ rc = ep11_kb_split(keybuf, *keybufsize, keybufver, ++ &hdr, &hdr_size, &pl, &pl_size); ++ if (rc) ++ return rc; ++ ++ rc = _ep11_genaeskey(card, domain, keybitsize, keygenflags, ++ pl, &pl_size); ++ if (rc) ++ return rc; ++ ++ *keybufsize = hdr_size + pl_size; ++ ++ /* update header information */ ++ hdr->type = TOKTYPE_NON_CCA; ++ hdr->len = *keybufsize; ++ hdr->version = keybufver; ++ hdr->bitlen = keybitsize; ++ ++ return 0; ++} + EXPORT_SYMBOL(ep11_genaeskey); + + static int ep11_cryptsingle(u16 card, u16 domain, +@@ -1055,7 +1131,7 @@ static int ep11_unwrapkey(u16 card, u16 domain, + kb->head.type = TOKTYPE_NON_CCA; + kb->head.len = rep_pl->data_len; + kb->head.version = TOKVER_EP11_AES; +- kb->head.keybitlen = keybitsize; ++ kb->head.bitlen = keybitsize; + + out: + kfree(req); +@@ -1201,7 +1277,6 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, + const u8 *clrkey, u8 *keybuf, size_t *keybufsize) + { + int rc; +- struct ep11keyblob *kb; + u8 encbuf[64], *kek = NULL; + size_t clrkeylen, keklen, encbuflen = sizeof(encbuf); + +@@ -1223,17 +1298,15 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, + } + + /* Step 1: generate AES 256 bit random kek key */ +- rc = ep11_genaeskey(card, domain, 256, +- 0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */ +- kek, &keklen); ++ rc = _ep11_genaeskey(card, domain, 256, ++ 0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */ ++ kek, &keklen); + if (rc) { + DEBUG_ERR( + "%s generate kek key failed, rc=%d\n", + __func__, rc); + goto out; + } +- kb = (struct ep11keyblob *)kek; +- memset(&kb->head, 0, sizeof(kb->head)); + + /* Step 2: encrypt clear key value with the kek key */ + rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen, +diff --git a/drivers/s390/crypto/zcrypt_ep11misc.h b/drivers/s390/crypto/zcrypt_ep11misc.h +index 07445041869fe..ed328c354bade 100644 +--- a/drivers/s390/crypto/zcrypt_ep11misc.h ++++ b/drivers/s390/crypto/zcrypt_ep11misc.h +@@ -29,14 +29,7 @@ struct ep11keyblob { + union { + u8 session[32]; + /* only used for PKEY_TYPE_EP11: */ +- struct { +- u8 type; /* 0x00 (TOKTYPE_NON_CCA) */ +- u8 res0; /* unused */ +- u16 len; /* total length in bytes of this blob */ +- u8 version; /* 0x03 (TOKVER_EP11_AES) */ +- u8 res1; /* unused */ +- u16 keybitlen; /* clear key bit len, 0 for unknown */ +- } head; ++ struct ep11kblob_header head; + }; + u8 wkvp[16]; /* wrapping key verification pattern */ + u64 attr; /* boolean key attributes */ +@@ -114,7 +107,7 @@ int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info); + * Generate (random) EP11 AES secure key. + */ + int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags, +- u8 *keybuf, size_t *keybufsize); ++ u8 *keybuf, size_t *keybufsize, u32 keybufver); + + /* + * Generate EP11 AES secure key with given clear key value. +diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c +index 8aeaddc93b167..8d374ae863ba2 100644 +--- a/drivers/scsi/be2iscsi/be_iscsi.c ++++ b/drivers/scsi/be2iscsi/be_iscsi.c +@@ -450,6 +450,10 @@ int beiscsi_iface_set_param(struct Scsi_Host *shost, + } + + nla_for_each_attr(attrib, data, dt_len, rm_len) { ++ /* ignore nla_type as it is never used */ ++ if (nla_len(attrib) < sizeof(*iface_param)) ++ return -EINVAL; ++ + iface_param = nla_data(attrib); + + if (iface_param->param_type != ISCSI_NET_PARAM) +diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c +index 5c8d1ba3f8f3c..19eee108db021 100644 +--- a/drivers/scsi/fcoe/fcoe_ctlr.c ++++ b/drivers/scsi/fcoe/fcoe_ctlr.c +@@ -319,16 +319,17 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip) + { + struct fcoe_fcf *sel; + struct fcoe_fcf *fcf; ++ unsigned long flags; + + mutex_lock(&fip->ctlr_mutex); +- spin_lock_bh(&fip->ctlr_lock); ++ spin_lock_irqsave(&fip->ctlr_lock, flags); + + kfree_skb(fip->flogi_req); + fip->flogi_req = NULL; + list_for_each_entry(fcf, &fip->fcfs, list) + fcf->flogi_sent = 0; + +- spin_unlock_bh(&fip->ctlr_lock); ++ spin_unlock_irqrestore(&fip->ctlr_lock, flags); + sel = fip->sel_fcf; + + if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr)) +@@ -699,6 +700,7 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, + { + struct fc_frame *fp; + struct fc_frame_header *fh; ++ unsigned long flags; + u16 old_xid; + u8 op; + u8 mac[ETH_ALEN]; +@@ -732,11 +734,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, + op = FIP_DT_FLOGI; + if (fip->mode == FIP_MODE_VN2VN) + break; +- spin_lock_bh(&fip->ctlr_lock); ++ spin_lock_irqsave(&fip->ctlr_lock, flags); + kfree_skb(fip->flogi_req); + fip->flogi_req = skb; + fip->flogi_req_send = 1; +- spin_unlock_bh(&fip->ctlr_lock); ++ spin_unlock_irqrestore(&fip->ctlr_lock, flags); + schedule_work(&fip->timer_work); + return -EINPROGRESS; + case ELS_FDISC: +@@ -1705,10 +1707,11 @@ static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip) + static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) + { + struct fcoe_fcf *fcf; ++ unsigned long flags; + int error; + + mutex_lock(&fip->ctlr_mutex); +- spin_lock_bh(&fip->ctlr_lock); ++ spin_lock_irqsave(&fip->ctlr_lock, flags); + LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n"); + fcf = fcoe_ctlr_select(fip); + if (!fcf || fcf->flogi_sent) { +@@ -1719,7 +1722,7 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) + fcoe_ctlr_solicit(fip, NULL); + error = fcoe_ctlr_flogi_send_locked(fip); + } +- spin_unlock_bh(&fip->ctlr_lock); ++ spin_unlock_irqrestore(&fip->ctlr_lock, flags); + mutex_unlock(&fip->ctlr_mutex); + return error; + } +@@ -1736,8 +1739,9 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) + static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) + { + struct fcoe_fcf *fcf; ++ unsigned long flags; + +- spin_lock_bh(&fip->ctlr_lock); ++ spin_lock_irqsave(&fip->ctlr_lock, flags); + fcf = fip->sel_fcf; + if (!fcf || !fip->flogi_req_send) + goto unlock; +@@ -1764,7 +1768,7 @@ static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) + } else /* XXX */ + LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n"); + unlock: +- spin_unlock_bh(&fip->ctlr_lock); ++ spin_unlock_irqrestore(&fip->ctlr_lock, flags); + } + + /** +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +index cd78e4c983aa8..38a91e227842c 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +@@ -2026,6 +2026,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, + u16 dma_tx_err_type = le16_to_cpu(err_record->dma_tx_err_type); + u16 sipc_rx_err_type = le16_to_cpu(err_record->sipc_rx_err_type); + u32 dma_rx_err_type = le32_to_cpu(err_record->dma_rx_err_type); ++ struct hisi_sas_complete_v2_hdr *complete_queue = ++ hisi_hba->complete_hdr[slot->cmplt_queue]; ++ struct hisi_sas_complete_v2_hdr *complete_hdr = ++ &complete_queue[slot->cmplt_queue_slot]; ++ u32 dw0 = le32_to_cpu(complete_hdr->dw0); + int error = -1; + + if (err_phase == 1) { +@@ -2310,7 +2315,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, + break; + } + } +- hisi_sas_sata_done(task, slot); ++ if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) ++ hisi_sas_sata_done(task, slot); + } + break; + default: +@@ -2443,7 +2449,8 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba, + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + { + ts->stat = SAS_SAM_STAT_GOOD; +- hisi_sas_sata_done(task, slot); ++ if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) ++ hisi_sas_sata_done(task, slot); + break; + } + default: +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +index 12d588454f5de..1794ad709183e 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +@@ -2206,6 +2206,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, + u32 trans_tx_fail_type = le32_to_cpu(record->trans_tx_fail_type); + u16 sipc_rx_err_type = le16_to_cpu(record->sipc_rx_err_type); + u32 dw3 = le32_to_cpu(complete_hdr->dw3); ++ u32 dw0 = le32_to_cpu(complete_hdr->dw0); + + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: +@@ -2215,8 +2216,8 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, + * but I/O information has been written to the host memory, we examine + * response IU. + */ +- if (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) && +- (complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)) ++ if (!(dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) && ++ (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)) + return false; + + ts->residual = trans_tx_fail_type; +@@ -2232,7 +2233,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: +- if ((complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) && ++ if ((dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) && + (sipc_rx_err_type & RX_FIS_STATUS_ERR_MSK)) { + ts->stat = SAS_PROTO_RESPONSE; + } else if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) { +@@ -2246,7 +2247,8 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + } +- hisi_sas_sata_done(task, slot); ++ if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) ++ hisi_sas_sata_done(task, slot); + break; + case SAS_PROTOCOL_SMP: + ts->stat = SAS_SAM_STAT_CHECK_CONDITION; +@@ -2373,7 +2375,8 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba, + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + ts->stat = SAS_SAM_STAT_GOOD; +- hisi_sas_sata_done(task, slot); ++ if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) ++ hisi_sas_sata_done(task, slot); + break; + default: + ts->stat = SAS_SAM_STAT_CHECK_CONDITION; +diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c +index f0bc8bbb39381..13ee3453e56a1 100644 +--- a/drivers/scsi/hosts.c ++++ b/drivers/scsi/hosts.c +@@ -536,7 +536,7 @@ EXPORT_SYMBOL(scsi_host_alloc); + static int __scsi_host_match(struct device *dev, const void *data) + { + struct Scsi_Host *p; +- const unsigned short *hostnum = data; ++ const unsigned int *hostnum = data; + + p = class_to_shost(dev); + return p->host_no == *hostnum; +@@ -553,7 +553,7 @@ static int __scsi_host_match(struct device *dev, const void *data) + * that scsi_host_get() took. The put_device() below dropped + * the reference from class_find_device(). + **/ +-struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) ++struct Scsi_Host *scsi_host_lookup(unsigned int hostnum) + { + struct device *cdev; + struct Scsi_Host *shost = NULL; +diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c +index e989f130434e4..e34a41fb3e1cb 100644 +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -109,8 +109,6 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, + } + } + +-#define LPFC_INVALID_REFTAG ((u32)-1) +- + /** + * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread + * @phba: The Hba for which this call is being executed. +@@ -978,8 +976,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, + + sgpe = scsi_prot_sglist(sc); + lba = scsi_prot_ref_tag(sc); +- if (lba == LPFC_INVALID_REFTAG) +- return 0; + + /* First check if we need to match the LBA */ + if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) { +@@ -1560,8 +1556,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, + + /* extract some info from the scsi command for pde*/ + reftag = scsi_prot_ref_tag(sc); +- if (reftag == LPFC_INVALID_REFTAG) +- goto out; + + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); +@@ -1723,8 +1717,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, + /* extract some info from the scsi command */ + blksize = scsi_prot_interval(sc); + reftag = scsi_prot_ref_tag(sc); +- if (reftag == LPFC_INVALID_REFTAG) +- goto out; + + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); +@@ -1953,8 +1945,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, + + /* extract some info from the scsi command for pde*/ + reftag = scsi_prot_ref_tag(sc); +- if (reftag == LPFC_INVALID_REFTAG) +- goto out; + + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); +@@ -2154,8 +2144,6 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, + /* extract some info from the scsi command */ + blksize = scsi_prot_interval(sc); + reftag = scsi_prot_ref_tag(sc); +- if (reftag == LPFC_INVALID_REFTAG) +- goto out; + + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); +@@ -2746,8 +2734,6 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) + + src = (struct scsi_dif_tuple *)sg_virt(sgpe); + start_ref_tag = scsi_prot_ref_tag(cmd); +- if (start_ref_tag == LPFC_INVALID_REFTAG) +- goto out; + start_app_tag = src->app_tag; + len = sgpe->length; + while (src && protsegcnt) { +@@ -3493,11 +3479,11 @@ err: + scsi_cmnd->sc_data_direction); + + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, +- "9084 Cannot setup S/G List for HBA" +- "IO segs %d/%d SGL %d SCSI %d: %d %d\n", ++ "9084 Cannot setup S/G List for HBA " ++ "IO segs %d/%d SGL %d SCSI %d: %d %d %d\n", + lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt, + phba->cfg_total_seg_cnt, phba->cfg_sg_seg_cnt, +- prot_group_type, num_sge); ++ prot_group_type, num_sge, ret); + + lpfc_cmd->seg_cnt = 0; + lpfc_cmd->prot_seg_cnt = 0; +diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c +index 53f5492579cb7..5284584e4cd2b 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_base.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_base.c +@@ -138,6 +138,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); + static void + _base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc); + ++static u32 ++_base_readl_ext_retry(const volatile void __iomem *addr); ++ + /** + * mpt3sas_base_check_cmd_timeout - Function + * to check timeout and command termination due +@@ -213,6 +216,20 @@ _base_readl_aero(const volatile void __iomem *addr) + return ret_val; + } + ++static u32 ++_base_readl_ext_retry(const volatile void __iomem *addr) ++{ ++ u32 i, ret_val; ++ ++ for (i = 0 ; i < 30 ; i++) { ++ ret_val = readl(addr); ++ if (ret_val == 0) ++ continue; ++ } ++ ++ return ret_val; ++} ++ + static inline u32 + _base_readl(const volatile void __iomem *addr) + { +@@ -940,7 +957,7 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) + + dump_stack(); + +- doorbell = ioc->base_readl(&ioc->chip->Doorbell); ++ doorbell = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + mpt3sas_print_fault_code(ioc, doorbell & + MPI2_DOORBELL_DATA_MASK); +@@ -6686,7 +6703,7 @@ mpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked) + { + u32 s, sc; + +- s = ioc->base_readl(&ioc->chip->Doorbell); ++ s = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); + sc = s & MPI2_IOC_STATE_MASK; + return cooked ? sc : s; + } +@@ -6831,7 +6848,7 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout) + __func__, count, timeout)); + return 0; + } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { +- doorbell = ioc->base_readl(&ioc->chip->Doorbell); ++ doorbell = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); + if ((doorbell & MPI2_IOC_STATE_MASK) == + MPI2_IOC_STATE_FAULT) { + mpt3sas_print_fault_code(ioc, doorbell); +@@ -6871,7 +6888,7 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout) + count = 0; + cntdn = 1000 * timeout; + do { +- doorbell_reg = ioc->base_readl(&ioc->chip->Doorbell); ++ doorbell_reg = ioc->base_readl_ext_retry(&ioc->chip->Doorbell); + if (!(doorbell_reg & MPI2_DOORBELL_USED)) { + dhsprintk(ioc, + ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", +@@ -7019,7 +7036,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, + __le32 *mfp; + + /* make sure doorbell is not in use */ +- if ((ioc->base_readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { ++ if ((ioc->base_readl_ext_retry(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { + ioc_err(ioc, "doorbell is in use (line=%d)\n", __LINE__); + return -EFAULT; + } +@@ -7068,7 +7085,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, + } + + /* read the first two 16-bits, it gives the total length of the reply */ +- reply[0] = le16_to_cpu(ioc->base_readl(&ioc->chip->Doorbell) ++ reply[0] = le16_to_cpu(ioc->base_readl_ext_retry(&ioc->chip->Doorbell) + & MPI2_DOORBELL_DATA_MASK); + writel(0, &ioc->chip->HostInterruptStatus); + if ((_base_wait_for_doorbell_int(ioc, 5))) { +@@ -7076,7 +7093,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, + __LINE__); + return -EFAULT; + } +- reply[1] = le16_to_cpu(ioc->base_readl(&ioc->chip->Doorbell) ++ reply[1] = le16_to_cpu(ioc->base_readl_ext_retry(&ioc->chip->Doorbell) + & MPI2_DOORBELL_DATA_MASK); + writel(0, &ioc->chip->HostInterruptStatus); + +@@ -7087,10 +7104,10 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, + return -EFAULT; + } + if (i >= reply_bytes/2) /* overflow case */ +- ioc->base_readl(&ioc->chip->Doorbell); ++ ioc->base_readl_ext_retry(&ioc->chip->Doorbell); + else + reply[i] = le16_to_cpu( +- ioc->base_readl(&ioc->chip->Doorbell) ++ ioc->base_readl_ext_retry(&ioc->chip->Doorbell) + & MPI2_DOORBELL_DATA_MASK); + writel(0, &ioc->chip->HostInterruptStatus); + } +@@ -7949,7 +7966,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) + goto out; + } + +- host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic); ++ host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); + drsprintk(ioc, + ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", + count, host_diagnostic)); +@@ -7969,7 +7986,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) + for (count = 0; count < (300000000 / + MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { + +- host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic); ++ host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic); + + if (host_diagnostic == 0xFFFFFFFF) { + ioc_info(ioc, +@@ -8359,10 +8376,13 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) + ioc->rdpq_array_enable_assigned = 0; + ioc->use_32bit_dma = false; + ioc->dma_mask = 64; +- if (ioc->is_aero_ioc) ++ if (ioc->is_aero_ioc) { + ioc->base_readl = &_base_readl_aero; +- else ++ ioc->base_readl_ext_retry = &_base_readl_ext_retry; ++ } else { + ioc->base_readl = &_base_readl; ++ ioc->base_readl_ext_retry = &_base_readl; ++ } + r = mpt3sas_base_map_resources(ioc); + if (r) + goto out_free_resources; +diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h +index 05364aa15ecdb..10055c7e4a9f7 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_base.h ++++ b/drivers/scsi/mpt3sas/mpt3sas_base.h +@@ -1618,6 +1618,7 @@ struct MPT3SAS_ADAPTER { + u8 diag_trigger_active; + u8 atomic_desc_capable; + BASE_READ_REG base_readl; ++ BASE_READ_REG base_readl_ext_retry; + struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; + struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event; + struct SL_WH_SCSI_TRIGGERS_T diag_trigger_scsi; +diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h +index f4d81127239eb..5ec2b817c694a 100644 +--- a/drivers/scsi/qedf/qedf_dbg.h ++++ b/drivers/scsi/qedf/qedf_dbg.h +@@ -59,6 +59,8 @@ extern uint qedf_debug; + #define QEDF_LOG_NOTICE 0x40000000 /* Notice logs */ + #define QEDF_LOG_WARN 0x80000000 /* Warning logs */ + ++#define QEDF_DEBUGFS_LOG_LEN (2 * PAGE_SIZE) ++ + /* Debug context structure */ + struct qedf_dbg_ctx { + unsigned int host_no; +diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c +index a3ed681c8ce3f..451fd236bfd05 100644 +--- a/drivers/scsi/qedf/qedf_debugfs.c ++++ b/drivers/scsi/qedf/qedf_debugfs.c +@@ -8,6 +8,7 @@ + #include <linux/uaccess.h> + #include <linux/debugfs.h> + #include <linux/module.h> ++#include <linux/vmalloc.h> + + #include "qedf.h" + #include "qedf_dbg.h" +@@ -98,7 +99,9 @@ static ssize_t + qedf_dbg_fp_int_cmd_read(struct file *filp, char __user *buffer, size_t count, + loff_t *ppos) + { ++ ssize_t ret; + size_t cnt = 0; ++ char *cbuf; + int id; + struct qedf_fastpath *fp = NULL; + struct qedf_dbg_ctx *qedf_dbg = +@@ -108,19 +111,25 @@ qedf_dbg_fp_int_cmd_read(struct file *filp, char __user *buffer, size_t count, + + QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n"); + +- cnt = sprintf(buffer, "\nFastpath I/O completions\n\n"); ++ cbuf = vmalloc(QEDF_DEBUGFS_LOG_LEN); ++ if (!cbuf) ++ return 0; ++ ++ cnt += scnprintf(cbuf + cnt, QEDF_DEBUGFS_LOG_LEN - cnt, "\nFastpath I/O completions\n\n"); + + for (id = 0; id < qedf->num_queues; id++) { + fp = &(qedf->fp_array[id]); + if (fp->sb_id == QEDF_SB_ID_NULL) + continue; +- cnt += sprintf((buffer + cnt), "#%d: %lu\n", id, +- fp->completions); ++ cnt += scnprintf(cbuf + cnt, QEDF_DEBUGFS_LOG_LEN - cnt, ++ "#%d: %lu\n", id, fp->completions); + } + +- cnt = min_t(int, count, cnt - *ppos); +- *ppos += cnt; +- return cnt; ++ ret = simple_read_from_buffer(buffer, count, ppos, cbuf, cnt); ++ ++ vfree(cbuf); ++ ++ return ret; + } + + static ssize_t +@@ -138,15 +147,14 @@ qedf_dbg_debug_cmd_read(struct file *filp, char __user *buffer, size_t count, + loff_t *ppos) + { + int cnt; ++ char cbuf[32]; + struct qedf_dbg_ctx *qedf_dbg = + (struct qedf_dbg_ctx *)filp->private_data; + + QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "debug mask=0x%x\n", qedf_debug); +- cnt = sprintf(buffer, "debug mask = 0x%x\n", qedf_debug); ++ cnt = scnprintf(cbuf, sizeof(cbuf), "debug mask = 0x%x\n", qedf_debug); + +- cnt = min_t(int, count, cnt - *ppos); +- *ppos += cnt; +- return cnt; ++ return simple_read_from_buffer(buffer, count, ppos, cbuf, cnt); + } + + static ssize_t +@@ -185,18 +193,17 @@ qedf_dbg_stop_io_on_error_cmd_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) + { + int cnt; ++ char cbuf[7]; + struct qedf_dbg_ctx *qedf_dbg = + (struct qedf_dbg_ctx *)filp->private_data; + struct qedf_ctx *qedf = container_of(qedf_dbg, + struct qedf_ctx, dbg_ctx); + + QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n"); +- cnt = sprintf(buffer, "%s\n", ++ cnt = scnprintf(cbuf, sizeof(cbuf), "%s\n", + qedf->stop_io_on_error ? "true" : "false"); + +- cnt = min_t(int, count, cnt - *ppos); +- *ppos += cnt; +- return cnt; ++ return simple_read_from_buffer(buffer, count, ppos, cbuf, cnt); + } + + static ssize_t +diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c +index ef62dbbc1868e..1106d26113888 100644 +--- a/drivers/scsi/qedi/qedi_main.c ++++ b/drivers/scsi/qedi/qedi_main.c +@@ -1977,8 +1977,9 @@ static int qedi_cpu_offline(unsigned int cpu) + struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); + struct qedi_work *work, *tmp; + struct task_struct *thread; ++ unsigned long flags; + +- spin_lock_bh(&p->p_work_lock); ++ spin_lock_irqsave(&p->p_work_lock, flags); + thread = p->iothread; + p->iothread = NULL; + +@@ -1989,7 +1990,7 @@ static int qedi_cpu_offline(unsigned int cpu) + kfree(work); + } + +- spin_unlock_bh(&p->p_work_lock); ++ spin_unlock_irqrestore(&p->p_work_lock, flags); + if (thread) + kthread_stop(thread); + return 0; +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index e6b857d7b3dd4..00cf7b81cfc0f 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -5549,7 +5549,7 @@ static void qla_get_login_template(scsi_qla_host_t *vha) + __be32 *q; + + memset(ha->init_cb, 0, ha->init_cb_size); +- sz = min_t(int, sizeof(struct fc_els_csp), ha->init_cb_size); ++ sz = min_t(int, sizeof(struct fc_els_flogi), ha->init_cb_size); + rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma, + ha->init_cb, sz); + if (rval != QLA_SUCCESS) { +diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c +index ee6d784c095c9..b6959470ddc04 100644 +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -968,6 +968,11 @@ static int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len) + memset(&chap_rec, 0, sizeof(chap_rec)); + + nla_for_each_attr(attr, data, len, rem) { ++ if (nla_len(attr) < sizeof(*param_info)) { ++ rc = -EINVAL; ++ goto exit_set_chap; ++ } ++ + param_info = nla_data(attr); + + switch (param_info->param) { +@@ -2750,6 +2755,11 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) + } + + nla_for_each_attr(attr, data, len, rem) { ++ if (nla_len(attr) < sizeof(*iface_param)) { ++ rval = -EINVAL; ++ goto exit_init_fw_cb; ++ } ++ + iface_param = nla_data(attr); + + if (iface_param->param_type == ISCSI_NET_PARAM) { +@@ -8104,6 +8114,11 @@ qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess, + + memset((void *)&chap_tbl, 0, sizeof(chap_tbl)); + nla_for_each_attr(attr, data, len, rem) { ++ if (nla_len(attr) < sizeof(*fnode_param)) { ++ rc = -EINVAL; ++ goto exit_set_param; ++ } ++ + fnode_param = nla_data(attr); + + switch (fnode_param->param) { +diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c +index b9b97300e3b3c..49dbcd67579aa 100644 +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -3013,14 +3013,15 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev + } + + static int +-iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) ++iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) + { + char *data = (char*)ev + sizeof(*ev); + struct iscsi_cls_conn *conn; + struct iscsi_cls_session *session; + int err = 0, value = 0, state; + +- if (ev->u.set_param.len > PAGE_SIZE) ++ if (ev->u.set_param.len > rlen || ++ ev->u.set_param.len > PAGE_SIZE) + return -EINVAL; + + session = iscsi_session_lookup(ev->u.set_param.sid); +@@ -3028,6 +3029,10 @@ iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) + if (!conn || !session) + return -EINVAL; + ++ /* data will be regarded as NULL-ended string, do length check */ ++ if (strlen(data) > ev->u.set_param.len) ++ return -EINVAL; ++ + switch (ev->u.set_param.param) { + case ISCSI_PARAM_SESS_RECOVERY_TMO: + sscanf(data, "%d", &value); +@@ -3117,7 +3122,7 @@ put_ep: + + static int + iscsi_if_transport_ep(struct iscsi_transport *transport, +- struct iscsi_uevent *ev, int msg_type) ++ struct iscsi_uevent *ev, int msg_type, u32 rlen) + { + struct iscsi_endpoint *ep; + int rc = 0; +@@ -3125,7 +3130,10 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, + switch (msg_type) { + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: +- rc = iscsi_if_ep_connect(transport, ev, msg_type); ++ if (rlen < sizeof(struct sockaddr)) ++ rc = -EINVAL; ++ else ++ rc = iscsi_if_ep_connect(transport, ev, msg_type); + break; + case ISCSI_UEVENT_TRANSPORT_EP_POLL: + if (!transport->ep_poll) +@@ -3149,12 +3157,15 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, + + static int + iscsi_tgt_dscvr(struct iscsi_transport *transport, +- struct iscsi_uevent *ev) ++ struct iscsi_uevent *ev, u32 rlen) + { + struct Scsi_Host *shost; + struct sockaddr *dst_addr; + int err; + ++ if (rlen < sizeof(*dst_addr)) ++ return -EINVAL; ++ + if (!transport->tgt_dscvr) + return -EINVAL; + +@@ -3175,7 +3186,7 @@ iscsi_tgt_dscvr(struct iscsi_transport *transport, + + static int + iscsi_set_host_param(struct iscsi_transport *transport, +- struct iscsi_uevent *ev) ++ struct iscsi_uevent *ev, u32 rlen) + { + char *data = (char*)ev + sizeof(*ev); + struct Scsi_Host *shost; +@@ -3184,7 +3195,8 @@ iscsi_set_host_param(struct iscsi_transport *transport, + if (!transport->set_host_param) + return -ENOSYS; + +- if (ev->u.set_host_param.len > PAGE_SIZE) ++ if (ev->u.set_host_param.len > rlen || ++ ev->u.set_host_param.len > PAGE_SIZE) + return -EINVAL; + + shost = scsi_host_lookup(ev->u.set_host_param.host_no); +@@ -3194,6 +3206,10 @@ iscsi_set_host_param(struct iscsi_transport *transport, + return -ENODEV; + } + ++ /* see similar check in iscsi_if_set_param() */ ++ if (strlen(data) > ev->u.set_host_param.len) ++ return -EINVAL; ++ + err = transport->set_host_param(shost, ev->u.set_host_param.param, + data, ev->u.set_host_param.len); + scsi_host_put(shost); +@@ -3201,12 +3217,15 @@ iscsi_set_host_param(struct iscsi_transport *transport, + } + + static int +-iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) ++iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) + { + struct Scsi_Host *shost; + struct iscsi_path *params; + int err; + ++ if (rlen < sizeof(*params)) ++ return -EINVAL; ++ + if (!transport->set_path) + return -ENOSYS; + +@@ -3266,12 +3285,15 @@ iscsi_set_iface_params(struct iscsi_transport *transport, + } + + static int +-iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev) ++iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) + { + struct Scsi_Host *shost; + struct sockaddr *dst_addr; + int err; + ++ if (rlen < sizeof(*dst_addr)) ++ return -EINVAL; ++ + if (!transport->send_ping) + return -ENOSYS; + +@@ -3769,13 +3791,12 @@ exit_host_stats: + } + + static int iscsi_if_transport_conn(struct iscsi_transport *transport, +- struct nlmsghdr *nlh) ++ struct nlmsghdr *nlh, u32 pdu_len) + { + struct iscsi_uevent *ev = nlmsg_data(nlh); + struct iscsi_cls_session *session; + struct iscsi_cls_conn *conn = NULL; + struct iscsi_endpoint *ep; +- uint32_t pdu_len; + int err = 0; + + switch (nlh->nlmsg_type) { +@@ -3860,8 +3881,6 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport, + + break; + case ISCSI_UEVENT_SEND_PDU: +- pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); +- + if ((ev->u.send_pdu.hdr_size > pdu_len) || + (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) { + err = -EINVAL; +@@ -3891,6 +3910,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct iscsi_endpoint *ep = NULL; ++ u32 rlen; + + if (!netlink_capable(skb, CAP_SYS_ADMIN)) + return -EPERM; +@@ -3910,6 +3930,13 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + + portid = NETLINK_CB(skb).portid; + ++ /* ++ * Even though the remaining payload may not be regarded as nlattr, ++ * (like address or something else), calculate the remaining length ++ * here to ease following length checks. ++ */ ++ rlen = nlmsg_attrlen(nlh, sizeof(*ev)); ++ + switch (nlh->nlmsg_type) { + case ISCSI_UEVENT_CREATE_SESSION: + err = iscsi_if_create_session(priv, ep, ev, +@@ -3966,7 +3993,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + err = -EINVAL; + break; + case ISCSI_UEVENT_SET_PARAM: +- err = iscsi_if_set_param(transport, ev); ++ err = iscsi_if_set_param(transport, ev, rlen); + break; + case ISCSI_UEVENT_CREATE_CONN: + case ISCSI_UEVENT_DESTROY_CONN: +@@ -3974,7 +4001,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + case ISCSI_UEVENT_START_CONN: + case ISCSI_UEVENT_BIND_CONN: + case ISCSI_UEVENT_SEND_PDU: +- err = iscsi_if_transport_conn(transport, nlh); ++ err = iscsi_if_transport_conn(transport, nlh, rlen); + break; + case ISCSI_UEVENT_GET_STATS: + err = iscsi_if_get_stats(transport, nlh); +@@ -3983,23 +4010,22 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + case ISCSI_UEVENT_TRANSPORT_EP_POLL: + case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: +- err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); ++ err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type, rlen); + break; + case ISCSI_UEVENT_TGT_DSCVR: +- err = iscsi_tgt_dscvr(transport, ev); ++ err = iscsi_tgt_dscvr(transport, ev, rlen); + break; + case ISCSI_UEVENT_SET_HOST_PARAM: +- err = iscsi_set_host_param(transport, ev); ++ err = iscsi_set_host_param(transport, ev, rlen); + break; + case ISCSI_UEVENT_PATH_UPDATE: +- err = iscsi_set_path(transport, ev); ++ err = iscsi_set_path(transport, ev, rlen); + break; + case ISCSI_UEVENT_SET_IFACE_PARAMS: +- err = iscsi_set_iface_params(transport, ev, +- nlmsg_attrlen(nlh, sizeof(*ev))); ++ err = iscsi_set_iface_params(transport, ev, rlen); + break; + case ISCSI_UEVENT_PING: +- err = iscsi_send_ping(transport, ev); ++ err = iscsi_send_ping(transport, ev, rlen); + break; + case ISCSI_UEVENT_GET_CHAP: + err = iscsi_get_chap(transport, nlh); +@@ -4008,13 +4034,10 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + err = iscsi_delete_chap(transport, ev); + break; + case ISCSI_UEVENT_SET_FLASHNODE_PARAMS: +- err = iscsi_set_flashnode_param(transport, ev, +- nlmsg_attrlen(nlh, +- sizeof(*ev))); ++ err = iscsi_set_flashnode_param(transport, ev, rlen); + break; + case ISCSI_UEVENT_NEW_FLASHNODE: +- err = iscsi_new_flashnode(transport, ev, +- nlmsg_attrlen(nlh, sizeof(*ev))); ++ err = iscsi_new_flashnode(transport, ev, rlen); + break; + case ISCSI_UEVENT_DEL_FLASHNODE: + err = iscsi_del_flashnode(transport, ev); +@@ -4029,8 +4052,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + err = iscsi_logout_flashnode_sid(transport, ev); + break; + case ISCSI_UEVENT_SET_CHAP: +- err = iscsi_set_chap(transport, ev, +- nlmsg_attrlen(nlh, sizeof(*ev))); ++ err = iscsi_set_chap(transport, ev, rlen); + break; + case ISCSI_UEVENT_GET_HOST_STATS: + err = iscsi_get_host_stats(transport, nlh); +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 199fe98720350..ef7c1748242ac 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -76,8 +76,12 @@ struct ocmem { + #define OCMEM_REG_GFX_MPU_START 0x00001004 + #define OCMEM_REG_GFX_MPU_END 0x00001008 + +-#define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_PREP(0x0000000f, (val)) +-#define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_PREP(0x00003f00, (val)) ++#define OCMEM_HW_VERSION_MAJOR(val) FIELD_GET(GENMASK(31, 28), val) ++#define OCMEM_HW_VERSION_MINOR(val) FIELD_GET(GENMASK(27, 16), val) ++#define OCMEM_HW_VERSION_STEP(val) FIELD_GET(GENMASK(15, 0), val) ++ ++#define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_GET(0x0000000f, (val)) ++#define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_GET(0x00003f00, (val)) + + #define OCMEM_HW_PROFILE_LAST_REGN_HALFSIZE 0x00010000 + #define OCMEM_HW_PROFILE_INTERLEAVING 0x00020000 +@@ -355,6 +359,12 @@ static int ocmem_dev_probe(struct platform_device *pdev) + } + } + ++ reg = ocmem_read(ocmem, OCMEM_REG_HW_VERSION); ++ dev_dbg(dev, "OCMEM hardware version: %lu.%lu.%lu\n", ++ OCMEM_HW_VERSION_MAJOR(reg), ++ OCMEM_HW_VERSION_MINOR(reg), ++ OCMEM_HW_VERSION_STEP(reg)); ++ + reg = ocmem_read(ocmem, OCMEM_REG_HW_PROFILE); + ocmem->num_ports = OCMEM_HW_PROFILE_NUM_PORTS(reg); + ocmem->num_macros = OCMEM_HW_PROFILE_NUM_MACROS(reg); +diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c +index 6be7ea93c78cf..1e08bb3b1679a 100644 +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -723,7 +723,7 @@ EXPORT_SYMBOL(qcom_smem_get_free_space); + + static bool addr_in_range(void __iomem *base, size_t size, void *addr) + { +- return base && (addr >= base && addr < base + size); ++ return base && ((void __iomem *)addr >= base && (void __iomem *)addr < base + size); + } + + /** +diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c +index 99aeef28a4774..5cecca1bef026 100644 +--- a/drivers/spi/spi-mpc512x-psc.c ++++ b/drivers/spi/spi-mpc512x-psc.c +@@ -53,7 +53,7 @@ struct mpc512x_psc_spi { + int type; + void __iomem *psc; + struct mpc512x_psc_fifo __iomem *fifo; +- unsigned int irq; ++ int irq; + u8 bits_per_word; + u32 mclk_rate; + +diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c +index 4286310628a2b..0c5507473f972 100644 +--- a/drivers/spi/spi-tegra20-sflash.c ++++ b/drivers/spi/spi-tegra20-sflash.c +@@ -455,7 +455,11 @@ static int tegra_sflash_probe(struct platform_device *pdev) + goto exit_free_master; + } + +- tsd->irq = platform_get_irq(pdev, 0); ++ ret = platform_get_irq(pdev, 0); ++ if (ret < 0) ++ goto exit_free_master; ++ tsd->irq = ret; ++ + ret = request_irq(tsd->irq, tegra_sflash_isr, 0, + dev_name(&pdev->dev), tsd); + if (ret < 0) { +diff --git a/drivers/staging/fbtft/fb_ili9341.c b/drivers/staging/fbtft/fb_ili9341.c +index 9ccd0823c3ab3..47e72b87d76d9 100644 +--- a/drivers/staging/fbtft/fb_ili9341.c ++++ b/drivers/staging/fbtft/fb_ili9341.c +@@ -145,7 +145,7 @@ static struct fbtft_display display = { + }, + }; + +-FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display); ++FBTFT_REGISTER_SPI_DRIVER(DRVNAME, "ilitek", "ili9341", &display); + + MODULE_ALIAS("spi:" DRVNAME); + MODULE_ALIAS("platform:" DRVNAME); +diff --git a/drivers/staging/media/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c +index 9767159aeb9b2..abf5c72607b64 100644 +--- a/drivers/staging/media/av7110/sp8870.c ++++ b/drivers/staging/media/av7110/sp8870.c +@@ -606,4 +606,4 @@ MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver"); + MODULE_AUTHOR("Juergen Peitz"); + MODULE_LICENSE("GPL"); + +-EXPORT_SYMBOL(sp8870_attach); ++EXPORT_SYMBOL_GPL(sp8870_attach); +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 134e2b9fa7d9a..84a41792cb4b8 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -120,7 +120,7 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + .max_width = 4096, + .step_width = 16, + .min_height = 48, +- .max_height = 2304, ++ .max_height = 2560, + .step_height = 16, + }, + .ctrls = &rkvdec_h264_ctrls, +diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c +index d8005e9ec992b..1f780c4a1c890 100644 +--- a/drivers/thermal/imx8mm_thermal.c ++++ b/drivers/thermal/imx8mm_thermal.c +@@ -179,10 +179,8 @@ static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev, + int ret; + + ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0); +- if (ret) { +- dev_warn(dev, "Failed to read OCOTP nvmem cell (%d).\n", ret); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to read OCOTP nvmem cell\n"); + + writel(FIELD_PREP(TASR_BUF_VREF_MASK, + FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) | +diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c +index d0a3f95b7884b..d4f160e8c7dbc 100644 +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -63,7 +63,12 @@ + #define LVTS_HW_FILTER 0x2 + #define LVTS_TSSEL_CONF 0x13121110 + #define LVTS_CALSCALE_CONF 0x300 +-#define LVTS_MONINT_CONF 0x9FBF7BDE ++#define LVTS_MONINT_CONF 0x8300318C ++ ++#define LVTS_MONINT_OFFSET_SENSOR0 0xC ++#define LVTS_MONINT_OFFSET_SENSOR1 0x180 ++#define LVTS_MONINT_OFFSET_SENSOR2 0x3000 ++#define LVTS_MONINT_OFFSET_SENSOR3 0x3000000 + + #define LVTS_INT_SENSOR0 0x0009001F + #define LVTS_INT_SENSOR1 0x001203E0 +@@ -81,6 +86,8 @@ + + #define LVTS_HW_SHUTDOWN_MT8195 105000 + ++#define LVTS_MINIMUM_THRESHOLD 20000 ++ + static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT; + static int coeff_b = LVTS_COEFF_B; + +@@ -108,6 +115,8 @@ struct lvts_sensor { + void __iomem *base; + int id; + int dt_id; ++ int low_thresh; ++ int high_thresh; + }; + + struct lvts_ctrl { +@@ -117,6 +126,8 @@ struct lvts_ctrl { + int num_lvts_sensor; + int mode; + void __iomem *base; ++ int low_thresh; ++ int high_thresh; + }; + + struct lvts_domain { +@@ -288,32 +299,84 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) + return 0; + } + ++static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl) ++{ ++ u32 masks[] = { ++ LVTS_MONINT_OFFSET_SENSOR0, ++ LVTS_MONINT_OFFSET_SENSOR1, ++ LVTS_MONINT_OFFSET_SENSOR2, ++ LVTS_MONINT_OFFSET_SENSOR3, ++ }; ++ u32 value = 0; ++ int i; ++ ++ value = readl(LVTS_MONINT(lvts_ctrl->base)); ++ ++ for (i = 0; i < ARRAY_SIZE(masks); i++) { ++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh ++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) ++ value |= masks[i]; ++ else ++ value &= ~masks[i]; ++ } ++ ++ writel(value, LVTS_MONINT(lvts_ctrl->base)); ++} ++ ++static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high) ++{ ++ int i; ++ ++ if (high > lvts_ctrl->high_thresh) ++ return true; ++ ++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) ++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh ++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) ++ return false; ++ ++ return true; ++} ++ + static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) + { + struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); ++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]); + void __iomem *base = lvts_sensor->base; +- u32 raw_low = lvts_temp_to_raw(low); ++ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD); + u32 raw_high = lvts_temp_to_raw(high); ++ bool should_update_thresh; ++ ++ lvts_sensor->low_thresh = low; ++ lvts_sensor->high_thresh = high; ++ ++ should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high); ++ if (should_update_thresh) { ++ lvts_ctrl->high_thresh = high; ++ lvts_ctrl->low_thresh = low; ++ } ++ lvts_update_irq_mask(lvts_ctrl); ++ ++ if (!should_update_thresh) ++ return 0; + + /* +- * Hot to normal temperature threshold ++ * Low offset temperature threshold + * +- * LVTS_H2NTHRE ++ * LVTS_OFFSETL + * + * Bits: + * + * 14-0 : Raw temperature for threshold + */ +- if (low != -INT_MAX) { +- pr_debug("%s: Setting low limit temperature interrupt: %d\n", +- thermal_zone_device_type(tz), low); +- writel(raw_low, LVTS_H2NTHRE(base)); +- } ++ pr_debug("%s: Setting low limit temperature interrupt: %d\n", ++ thermal_zone_device_type(tz), low); ++ writel(raw_low, LVTS_OFFSETL(base)); + + /* +- * Hot temperature threshold ++ * High offset temperature threshold + * +- * LVTS_HTHRE ++ * LVTS_OFFSETH + * + * Bits: + * +@@ -321,7 +384,7 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) + */ + pr_debug("%s: Setting high limit temperature interrupt: %d\n", + thermal_zone_device_type(tz), high); +- writel(raw_high, LVTS_HTHRE(base)); ++ writel(raw_high, LVTS_OFFSETH(base)); + + return 0; + } +@@ -449,7 +512,7 @@ static irqreturn_t lvts_irq_handler(int irq, void *data) + + for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { + +- aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl); ++ aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]); + if (aux != IRQ_HANDLED) + continue; + +@@ -519,6 +582,9 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, + */ + lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ? + imm_regs[i] : msr_regs[i]; ++ ++ lvts_sensor[i].low_thresh = INT_MIN; ++ lvts_sensor[i].high_thresh = INT_MIN; + }; + + lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor; +@@ -686,6 +752,9 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td, + */ + lvts_ctrl[i].hw_tshut_raw_temp = + lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp); ++ ++ lvts_ctrl[i].low_thresh = INT_MIN; ++ lvts_ctrl[i].high_thresh = INT_MIN; + } + + /* +@@ -894,24 +963,6 @@ static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl) + LVTS_HW_FILTER << 3 | LVTS_HW_FILTER; + writel(value, LVTS_MSRCTL0(lvts_ctrl->base)); + +- /* +- * LVTS_MSRCTL1 : Measurement control +- * +- * Bits: +- * +- * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 +- * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 +- * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 +- * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 +- * +- * That configuration will ignore the filtering and the delays +- * introduced below in MONCTL1 and MONCTL2 +- */ +- if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { +- value = BIT(9) | BIT(6) | BIT(5) | BIT(4); +- writel(value, LVTS_MSRCTL1(lvts_ctrl->base)); +- } +- + /* + * LVTS_MONCTL1 : Period unit and group interval configuration + * +@@ -977,6 +1028,15 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) + struct thermal_zone_device *tz; + u32 sensor_map = 0; + int i; ++ /* ++ * Bitmaps to enable each sensor on immediate and filtered modes, as ++ * described in MSRCTL1 and MONCTL0 registers below, respectively. ++ */ ++ u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) }; ++ u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) }; ++ ++ u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ? ++ sensor_imm_bitmap : sensor_filt_bitmap; + + for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) { + +@@ -1012,20 +1072,38 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) + * map, so we can enable the temperature monitoring in + * the hardware thermal controller. + */ +- sensor_map |= BIT(i); ++ sensor_map |= sensor_bitmap[i]; + } + + /* +- * Bits: +- * 9: Single point access flow +- * 0-3: Enable sensing point 0-3 +- * + * The initialization of the thermal zones give us + * which sensor point to enable. If any thermal zone + * was not described in the device tree, it won't be + * enabled here in the sensor map. + */ +- writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); ++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { ++ /* ++ * LVTS_MSRCTL1 : Measurement control ++ * ++ * Bits: ++ * ++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 ++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 ++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 ++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 ++ * ++ * That configuration will ignore the filtering and the delays ++ * introduced in MONCTL1 and MONCTL2 ++ */ ++ writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base)); ++ } else { ++ /* ++ * Bits: ++ * 9: Single point access flow ++ * 0-3: Enable sensing point 0-3 ++ */ ++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); ++ } + + return 0; + } +diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c +index 842f678c1c3e1..cc2b5e81c6205 100644 +--- a/drivers/thermal/thermal_core.c ++++ b/drivers/thermal/thermal_core.c +@@ -1203,7 +1203,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp); + struct thermal_zone_device * + thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *trips, int num_trips, int mask, + void *devdata, struct thermal_zone_device_ops *ops, +- struct thermal_zone_params *tzp, int passive_delay, ++ const struct thermal_zone_params *tzp, int passive_delay, + int polling_delay) + { + struct thermal_zone_device *tz; +@@ -1371,7 +1371,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_device_register_with_trips); + + struct thermal_zone_device *thermal_zone_device_register(const char *type, int ntrips, int mask, + void *devdata, struct thermal_zone_device_ops *ops, +- struct thermal_zone_params *tzp, int passive_delay, ++ const struct thermal_zone_params *tzp, int passive_delay, + int polling_delay) + { + return thermal_zone_device_register_with_trips(type, NULL, ntrips, mask, +diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c +index bc07ae1c284cf..22272f9c5934a 100644 +--- a/drivers/thermal/thermal_of.c ++++ b/drivers/thermal/thermal_of.c +@@ -292,13 +292,13 @@ static int __thermal_of_unbind(struct device_node *map_np, int index, int trip_i + ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells", + index, &cooling_spec); + +- of_node_put(cooling_spec.np); +- + if (ret < 0) { + pr_err("Invalid cooling-device entry\n"); + return ret; + } + ++ of_node_put(cooling_spec.np); ++ + if (cooling_spec.args_count < 2) { + pr_err("wrong reference to cooling device, missing limits\n"); + return -EINVAL; +@@ -325,13 +325,13 @@ static int __thermal_of_bind(struct device_node *map_np, int index, int trip_id, + ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells", + index, &cooling_spec); + +- of_node_put(cooling_spec.np); +- + if (ret < 0) { + pr_err("Invalid cooling-device entry\n"); + return ret; + } + ++ of_node_put(cooling_spec.np); ++ + if (cooling_spec.args_count < 2) { + pr_err("wrong reference to cooling device, missing limits\n"); + return -EINVAL; +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index 24ebdb0b63a8e..ae632a9d4f3ae 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -592,7 +592,6 @@ static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport) + { + struct qcom_geni_serial_port *port = to_dev_port(uport); + bool done; +- u32 m_irq_en; + + if (!qcom_geni_serial_main_active(uport)) + return; +@@ -604,12 +603,10 @@ static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport) + port->tx_remaining = 0; + } + +- m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); +- writel(m_irq_en, uport->membase + SE_GENI_M_IRQ_EN); + geni_se_cancel_m_cmd(&port->se); + +- done = qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS, +- S_CMD_CANCEL_EN, true); ++ done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, ++ M_CMD_CANCEL_EN, true); + if (!done) { + geni_se_abort_m_cmd(&port->se); + done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index 54c760b46da13..8845301c16058 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -236,7 +236,8 @@ + + /* IOControl register bits (Only 750/760) */ + #define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */ +-#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */ ++#define SC16IS7XX_IOCONTROL_MODEM_A_BIT (1 << 1) /* Enable GPIO[7:4] as modem A pins */ ++#define SC16IS7XX_IOCONTROL_MODEM_B_BIT (1 << 2) /* Enable GPIO[3:0] as modem B pins */ + #define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */ + + /* EFCR register bits */ +@@ -301,12 +302,12 @@ + /* Misc definitions */ + #define SC16IS7XX_FIFO_SIZE (64) + #define SC16IS7XX_REG_SHIFT 2 ++#define SC16IS7XX_GPIOS_PER_BANK 4 + + struct sc16is7xx_devtype { + char name[10]; + int nr_gpio; + int nr_uart; +- int has_mctrl; + }; + + #define SC16IS7XX_RECONF_MD (1 << 0) +@@ -336,7 +337,9 @@ struct sc16is7xx_port { + struct clk *clk; + #ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; ++ unsigned long gpio_valid_mask; + #endif ++ u8 mctrl_mask; + unsigned char buf[SC16IS7XX_FIFO_SIZE]; + struct kthread_worker kworker; + struct task_struct *kworker_task; +@@ -447,35 +450,30 @@ static const struct sc16is7xx_devtype sc16is74x_devtype = { + .name = "SC16IS74X", + .nr_gpio = 0, + .nr_uart = 1, +- .has_mctrl = 0, + }; + + static const struct sc16is7xx_devtype sc16is750_devtype = { + .name = "SC16IS750", +- .nr_gpio = 4, ++ .nr_gpio = 8, + .nr_uart = 1, +- .has_mctrl = 1, + }; + + static const struct sc16is7xx_devtype sc16is752_devtype = { + .name = "SC16IS752", +- .nr_gpio = 0, ++ .nr_gpio = 8, + .nr_uart = 2, +- .has_mctrl = 1, + }; + + static const struct sc16is7xx_devtype sc16is760_devtype = { + .name = "SC16IS760", +- .nr_gpio = 4, ++ .nr_gpio = 8, + .nr_uart = 1, +- .has_mctrl = 1, + }; + + static const struct sc16is7xx_devtype sc16is762_devtype = { + .name = "SC16IS762", +- .nr_gpio = 0, ++ .nr_gpio = 8, + .nr_uart = 2, +- .has_mctrl = 1, + }; + + static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) +@@ -1357,8 +1355,98 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, + + return 0; + } ++ ++static int sc16is7xx_gpio_init_valid_mask(struct gpio_chip *chip, ++ unsigned long *valid_mask, ++ unsigned int ngpios) ++{ ++ struct sc16is7xx_port *s = gpiochip_get_data(chip); ++ ++ *valid_mask = s->gpio_valid_mask; ++ ++ return 0; ++} ++ ++static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s) ++{ ++ struct device *dev = s->p[0].port.dev; ++ ++ if (!s->devtype->nr_gpio) ++ return 0; ++ ++ switch (s->mctrl_mask) { ++ case 0: ++ s->gpio_valid_mask = GENMASK(7, 0); ++ break; ++ case SC16IS7XX_IOCONTROL_MODEM_A_BIT: ++ s->gpio_valid_mask = GENMASK(3, 0); ++ break; ++ case SC16IS7XX_IOCONTROL_MODEM_B_BIT: ++ s->gpio_valid_mask = GENMASK(7, 4); ++ break; ++ default: ++ break; ++ } ++ ++ if (s->gpio_valid_mask == 0) ++ return 0; ++ ++ s->gpio.owner = THIS_MODULE; ++ s->gpio.parent = dev; ++ s->gpio.label = dev_name(dev); ++ s->gpio.init_valid_mask = sc16is7xx_gpio_init_valid_mask; ++ s->gpio.direction_input = sc16is7xx_gpio_direction_input; ++ s->gpio.get = sc16is7xx_gpio_get; ++ s->gpio.direction_output = sc16is7xx_gpio_direction_output; ++ s->gpio.set = sc16is7xx_gpio_set; ++ s->gpio.base = -1; ++ s->gpio.ngpio = s->devtype->nr_gpio; ++ s->gpio.can_sleep = 1; ++ ++ return gpiochip_add_data(&s->gpio, s); ++} + #endif + ++/* ++ * Configure ports designated to operate as modem control lines. ++ */ ++static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s) ++{ ++ int i; ++ int ret; ++ int count; ++ u32 mctrl_port[2]; ++ struct device *dev = s->p[0].port.dev; ++ ++ count = device_property_count_u32(dev, "nxp,modem-control-line-ports"); ++ if (count < 0 || count > ARRAY_SIZE(mctrl_port)) ++ return 0; ++ ++ ret = device_property_read_u32_array(dev, "nxp,modem-control-line-ports", ++ mctrl_port, count); ++ if (ret) ++ return ret; ++ ++ s->mctrl_mask = 0; ++ ++ for (i = 0; i < count; i++) { ++ /* Use GPIO lines as modem control lines */ ++ if (mctrl_port[i] == 0) ++ s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_A_BIT; ++ else if (mctrl_port[i] == 1) ++ s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_B_BIT; ++ } ++ ++ if (s->mctrl_mask) ++ regmap_update_bits( ++ s->regmap, ++ SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, ++ SC16IS7XX_IOCONTROL_MODEM_A_BIT | ++ SC16IS7XX_IOCONTROL_MODEM_B_BIT, s->mctrl_mask); ++ ++ return 0; ++} ++ + static const struct serial_rs485 sc16is7xx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, +@@ -1471,12 +1559,6 @@ static int sc16is7xx_probe(struct device *dev, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + +- /* Use GPIO lines as modem status registers */ +- if (devtype->has_mctrl) +- sc16is7xx_port_write(&s->p[i].port, +- SC16IS7XX_IOCONTROL_REG, +- SC16IS7XX_IOCONTROL_MODEM_BIT); +- + /* Initialize kthread work structs */ + kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc); + kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc); +@@ -1514,23 +1596,14 @@ static int sc16is7xx_probe(struct device *dev, + s->p[u].irda_mode = true; + } + ++ ret = sc16is7xx_setup_mctrl_ports(s); ++ if (ret) ++ goto out_ports; ++ + #ifdef CONFIG_GPIOLIB +- if (devtype->nr_gpio) { +- /* Setup GPIO cotroller */ +- s->gpio.owner = THIS_MODULE; +- s->gpio.parent = dev; +- s->gpio.label = dev_name(dev); +- s->gpio.direction_input = sc16is7xx_gpio_direction_input; +- s->gpio.get = sc16is7xx_gpio_get; +- s->gpio.direction_output = sc16is7xx_gpio_direction_output; +- s->gpio.set = sc16is7xx_gpio_set; +- s->gpio.base = -1; +- s->gpio.ngpio = devtype->nr_gpio; +- s->gpio.can_sleep = 1; +- ret = gpiochip_add_data(&s->gpio, s); +- if (ret) +- goto out_thread; +- } ++ ret = sc16is7xx_setup_gpio_chip(s); ++ if (ret) ++ goto out_ports; + #endif + + /* +@@ -1553,10 +1626,8 @@ static int sc16is7xx_probe(struct device *dev, + return 0; + + #ifdef CONFIG_GPIOLIB +- if (devtype->nr_gpio) ++ if (s->gpio_valid_mask) + gpiochip_remove(&s->gpio); +- +-out_thread: + #endif + + out_ports: +@@ -1579,7 +1650,7 @@ static void sc16is7xx_remove(struct device *dev) + int i; + + #ifdef CONFIG_GPIOLIB +- if (s->devtype->nr_gpio) ++ if (s->gpio_valid_mask) + gpiochip_remove(&s->gpio); + #endif + +diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c +index 1cf08b33456c9..37e1e05bc87e6 100644 +--- a/drivers/tty/serial/serial-tegra.c ++++ b/drivers/tty/serial/serial-tegra.c +@@ -998,7 +998,11 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) + tup->ier_shadow = 0; + tup->current_baud = 0; + +- clk_prepare_enable(tup->uart_clk); ++ ret = clk_prepare_enable(tup->uart_clk); ++ if (ret) { ++ dev_err(tup->uport.dev, "could not enable clk\n"); ++ return ret; ++ } + + /* Reset the UART controller to clear all previous status.*/ + reset_control_assert(tup->rst); +diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c +index b58f51296ace2..99da964e8bd44 100644 +--- a/drivers/tty/serial/sprd_serial.c ++++ b/drivers/tty/serial/sprd_serial.c +@@ -364,7 +364,7 @@ static void sprd_rx_free_buf(struct sprd_uart_port *sp) + if (sp->rx_dma.virt) + dma_free_coherent(sp->port.dev, SPRD_UART_RX_SIZE, + sp->rx_dma.virt, sp->rx_dma.phys_addr); +- ++ sp->rx_dma.virt = NULL; + } + + static int sprd_rx_dma_config(struct uart_port *port, u32 burst) +@@ -1106,7 +1106,7 @@ static bool sprd_uart_is_console(struct uart_port *uport) + static int sprd_clk_init(struct uart_port *uport) + { + struct clk *clk_uart, *clk_parent; +- struct sprd_uart_port *u = sprd_port[uport->line]; ++ struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port); + + clk_uart = devm_clk_get(uport->dev, "uart"); + if (IS_ERR(clk_uart)) { +@@ -1149,22 +1149,22 @@ static int sprd_probe(struct platform_device *pdev) + { + struct resource *res; + struct uart_port *up; ++ struct sprd_uart_port *sport; + int irq; + int index; + int ret; + + index = of_alias_get_id(pdev->dev.of_node, "serial"); +- if (index < 0 || index >= ARRAY_SIZE(sprd_port)) { ++ if (index < 0 || index >= UART_NR_MAX) { + dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index); + return -EINVAL; + } + +- sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]), +- GFP_KERNEL); +- if (!sprd_port[index]) ++ sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); ++ if (!sport) + return -ENOMEM; + +- up = &sprd_port[index]->port; ++ up = &sport->port; + up->dev = &pdev->dev; + up->line = index; + up->type = PORT_SPRD; +@@ -1195,7 +1195,7 @@ static int sprd_probe(struct platform_device *pdev) + * Allocate one dma buffer to prepare for receive transfer, in case + * memory allocation failure at runtime. + */ +- ret = sprd_rx_alloc_buf(sprd_port[index]); ++ ret = sprd_rx_alloc_buf(sport); + if (ret) + return ret; + +@@ -1203,17 +1203,27 @@ static int sprd_probe(struct platform_device *pdev) + ret = uart_register_driver(&sprd_uart_driver); + if (ret < 0) { + pr_err("Failed to register SPRD-UART driver\n"); +- return ret; ++ goto free_rx_buf; + } + } ++ + sprd_ports_num++; ++ sprd_port[index] = sport; + + ret = uart_add_one_port(&sprd_uart_driver, up); + if (ret) +- sprd_remove(pdev); ++ goto clean_port; + + platform_set_drvdata(pdev, up); + ++ return 0; ++ ++clean_port: ++ sprd_port[index] = NULL; ++ if (--sprd_ports_num == 0) ++ uart_unregister_driver(&sprd_uart_driver); ++free_rx_buf: ++ sprd_rx_free_buf(sport); + return ret; + } + +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index 6d8ef80d9cbc4..b9177182e5a7b 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -5255,9 +5255,17 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, + int result = 0; + int scsi_status; + enum utp_ocs ocs; ++ u8 upiu_flags; ++ u32 resid; + +- scsi_set_resid(lrbp->cmd, +- be32_to_cpu(lrbp->ucd_rsp_ptr->sr.residual_transfer_count)); ++ upiu_flags = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_0) >> 16; ++ resid = be32_to_cpu(lrbp->ucd_rsp_ptr->sr.residual_transfer_count); ++ /* ++ * Test !overflow instead of underflow to support UFS devices that do ++ * not set either flag. ++ */ ++ if (resid && !(upiu_flags & UPIU_RSP_FLAG_OVERFLOW)) ++ scsi_set_resid(lrbp->cmd, resid); + + /* overall command status of utrd */ + ocs = ufshcd_get_tr_ocs(lrbp, cqe); +diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c +index 8300baedafd20..6af0a31ff1475 100644 +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -983,6 +983,7 @@ static int register_root_hub(struct usb_hcd *hcd) + { + struct device *parent_dev = hcd->self.controller; + struct usb_device *usb_dev = hcd->self.root_hub; ++ struct usb_device_descriptor *descr; + const int devnum = 1; + int retval; + +@@ -994,13 +995,16 @@ static int register_root_hub(struct usb_hcd *hcd) + mutex_lock(&usb_bus_idr_lock); + + usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); +- retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); +- if (retval != sizeof usb_dev->descriptor) { ++ descr = usb_get_device_descriptor(usb_dev); ++ if (IS_ERR(descr)) { ++ retval = PTR_ERR(descr); + mutex_unlock(&usb_bus_idr_lock); + dev_dbg (parent_dev, "can't read %s device descriptor %d\n", + dev_name(&usb_dev->dev), retval); +- return (retval < 0) ? retval : -EMSGSIZE; ++ return retval; + } ++ usb_dev->descriptor = *descr; ++ kfree(descr); + + if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) { + retval = usb_get_bos_descriptor(usb_dev); +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 97a0f8faea6e5..8a576326b3593 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2656,12 +2656,17 @@ int usb_authorize_device(struct usb_device *usb_dev) + } + + if (usb_dev->wusb) { +- result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); +- if (result < 0) { ++ struct usb_device_descriptor *descr; ++ ++ descr = usb_get_device_descriptor(usb_dev); ++ if (IS_ERR(descr)) { ++ result = PTR_ERR(descr); + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } ++ usb_dev->descriptor = *descr; ++ kfree(descr); + } + + usb_dev->authorized = 1; +@@ -4703,6 +4708,67 @@ static int hub_enable_device(struct usb_device *udev) + return hcd->driver->enable_device(hcd, udev); + } + ++/* ++ * Get the bMaxPacketSize0 value during initialization by reading the ++ * device's device descriptor. Since we don't already know this value, ++ * the transfer is unsafe and it ignores I/O errors, only testing for ++ * reasonable received values. ++ * ++ * For "old scheme" initialization, size will be 8 so we read just the ++ * start of the device descriptor, which should work okay regardless of ++ * the actual bMaxPacketSize0 value. For "new scheme" initialization, ++ * size will be 64 (and buf will point to a sufficiently large buffer), ++ * which might not be kosher according to the USB spec but it's what ++ * Windows does and what many devices expect. ++ * ++ * Returns: bMaxPacketSize0 or a negative error code. ++ */ ++static int get_bMaxPacketSize0(struct usb_device *udev, ++ struct usb_device_descriptor *buf, int size, bool first_time) ++{ ++ int i, rc; ++ ++ /* ++ * Retry on all errors; some devices are flakey. ++ * 255 is for WUSB devices, we actually need to use ++ * 512 (WUSB1.0[4.8.1]). ++ */ ++ for (i = 0; i < GET_MAXPACKET0_TRIES; ++i) { ++ /* Start with invalid values in case the transfer fails */ ++ buf->bDescriptorType = buf->bMaxPacketSize0 = 0; ++ rc = usb_control_msg(udev, usb_rcvaddr0pipe(), ++ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, ++ USB_DT_DEVICE << 8, 0, ++ buf, size, ++ initial_descriptor_timeout); ++ switch (buf->bMaxPacketSize0) { ++ case 8: case 16: case 32: case 64: case 9: ++ if (buf->bDescriptorType == USB_DT_DEVICE) { ++ rc = buf->bMaxPacketSize0; ++ break; ++ } ++ fallthrough; ++ default: ++ if (rc >= 0) ++ rc = -EPROTO; ++ break; ++ } ++ ++ /* ++ * Some devices time out if they are powered on ++ * when already connected. They need a second ++ * reset, so return early. But only on the first ++ * attempt, lest we get into a time-out/reset loop. ++ */ ++ if (rc > 0 || (rc == -ETIMEDOUT && first_time && ++ udev->speed > USB_SPEED_FULL)) ++ break; ++ } ++ return rc; ++} ++ ++#define GET_DESCRIPTOR_BUFSIZE 64 ++ + /* Reset device, (re)assign address, get device descriptor. + * Device connection must be stable, no more debouncing needed. + * Returns device in USB_STATE_ADDRESS, except on error. +@@ -4712,10 +4778,17 @@ static int hub_enable_device(struct usb_device *udev) + * the port lock. For a newly detected device that is not accessible + * through any global pointers, it's not necessary to lock the device, + * but it is still necessary to lock the port. ++ * ++ * For a newly detected device, @dev_descr must be NULL. The device ++ * descriptor retrieved from the device will then be stored in ++ * @udev->descriptor. For an already existing device, @dev_descr ++ * must be non-NULL. The device descriptor will be stored there, ++ * not in @udev->descriptor, because descriptors for registered ++ * devices are meant to be immutable. + */ + static int + hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, +- int retry_counter) ++ int retry_counter, struct usb_device_descriptor *dev_descr) + { + struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); +@@ -4727,6 +4800,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + int devnum = udev->devnum; + const char *driver_name; + bool do_new_scheme; ++ const bool initial = !dev_descr; ++ int maxp0; ++ struct usb_device_descriptor *buf, *descr; ++ ++ buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); ++ if (!buf) ++ return -ENOMEM; + + /* root hub ports have a slightly longer reset period + * (from USB 2.0 spec, section 7.1.7.5) +@@ -4759,32 +4839,34 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + } + oldspeed = udev->speed; + +- /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... +- * it's fixed size except for full speed devices. +- * For Wireless USB devices, ep0 max packet is always 512 (tho +- * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. +- */ +- switch (udev->speed) { +- case USB_SPEED_SUPER_PLUS: +- case USB_SPEED_SUPER: +- case USB_SPEED_WIRELESS: /* fixed at 512 */ +- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); +- break; +- case USB_SPEED_HIGH: /* fixed at 64 */ +- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); +- break; +- case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ +- /* to determine the ep0 maxpacket size, try to read +- * the device descriptor to get bMaxPacketSize0 and +- * then correct our initial guess. ++ if (initial) { ++ /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... ++ * it's fixed size except for full speed devices. ++ * For Wireless USB devices, ep0 max packet is always 512 (tho ++ * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. + */ +- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); +- break; +- case USB_SPEED_LOW: /* fixed at 8 */ +- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8); +- break; +- default: +- goto fail; ++ switch (udev->speed) { ++ case USB_SPEED_SUPER_PLUS: ++ case USB_SPEED_SUPER: ++ case USB_SPEED_WIRELESS: /* fixed at 512 */ ++ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); ++ break; ++ case USB_SPEED_HIGH: /* fixed at 64 */ ++ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); ++ break; ++ case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ ++ /* to determine the ep0 maxpacket size, try to read ++ * the device descriptor to get bMaxPacketSize0 and ++ * then correct our initial guess. ++ */ ++ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); ++ break; ++ case USB_SPEED_LOW: /* fixed at 8 */ ++ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8); ++ break; ++ default: ++ goto fail; ++ } + } + + if (udev->speed == USB_SPEED_WIRELESS) +@@ -4807,22 +4889,24 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + if (udev->speed < USB_SPEED_SUPER) + dev_info(&udev->dev, + "%s %s USB device number %d using %s\n", +- (udev->config) ? "reset" : "new", speed, ++ (initial ? "new" : "reset"), speed, + devnum, driver_name); + +- /* Set up TT records, if needed */ +- if (hdev->tt) { +- udev->tt = hdev->tt; +- udev->ttport = hdev->ttport; +- } else if (udev->speed != USB_SPEED_HIGH +- && hdev->speed == USB_SPEED_HIGH) { +- if (!hub->tt.hub) { +- dev_err(&udev->dev, "parent hub has no TT\n"); +- retval = -EINVAL; +- goto fail; ++ if (initial) { ++ /* Set up TT records, if needed */ ++ if (hdev->tt) { ++ udev->tt = hdev->tt; ++ udev->ttport = hdev->ttport; ++ } else if (udev->speed != USB_SPEED_HIGH ++ && hdev->speed == USB_SPEED_HIGH) { ++ if (!hub->tt.hub) { ++ dev_err(&udev->dev, "parent hub has no TT\n"); ++ retval = -EINVAL; ++ goto fail; ++ } ++ udev->tt = &hub->tt; ++ udev->ttport = port1; + } +- udev->tt = &hub->tt; +- udev->ttport = port1; + } + + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? +@@ -4846,9 +4930,6 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + } + + if (do_new_scheme) { +- struct usb_device_descriptor *buf; +- int r = 0; +- + retval = hub_enable_device(udev); + if (retval < 0) { + dev_err(&udev->dev, +@@ -4857,52 +4938,14 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + goto fail; + } + +-#define GET_DESCRIPTOR_BUFSIZE 64 +- buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); +- if (!buf) { +- retval = -ENOMEM; +- continue; +- } +- +- /* Retry on all errors; some devices are flakey. +- * 255 is for WUSB devices, we actually need to use +- * 512 (WUSB1.0[4.8.1]). +- */ +- for (operations = 0; operations < GET_MAXPACKET0_TRIES; +- ++operations) { +- buf->bMaxPacketSize0 = 0; +- r = usb_control_msg(udev, usb_rcvaddr0pipe(), +- USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, +- USB_DT_DEVICE << 8, 0, +- buf, GET_DESCRIPTOR_BUFSIZE, +- initial_descriptor_timeout); +- switch (buf->bMaxPacketSize0) { +- case 8: case 16: case 32: case 64: case 255: +- if (buf->bDescriptorType == +- USB_DT_DEVICE) { +- r = 0; +- break; +- } +- fallthrough; +- default: +- if (r == 0) +- r = -EPROTO; +- break; +- } +- /* +- * Some devices time out if they are powered on +- * when already connected. They need a second +- * reset. But only on the first attempt, +- * lest we get into a time out/reset loop +- */ +- if (r == 0 || (r == -ETIMEDOUT && +- retries == 0 && +- udev->speed > USB_SPEED_FULL)) +- break; ++ maxp0 = get_bMaxPacketSize0(udev, buf, ++ GET_DESCRIPTOR_BUFSIZE, retries == 0); ++ if (maxp0 > 0 && !initial && ++ maxp0 != udev->descriptor.bMaxPacketSize0) { ++ dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n"); ++ retval = -ENODEV; ++ goto fail; + } +- udev->descriptor.bMaxPacketSize0 = +- buf->bMaxPacketSize0; +- kfree(buf); + + retval = hub_port_reset(hub, port1, udev, delay, false); + if (retval < 0) /* error or disconnect */ +@@ -4913,14 +4956,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + retval = -ENODEV; + goto fail; + } +- if (r) { +- if (r != -ENODEV) ++ if (maxp0 < 0) { ++ if (maxp0 != -ENODEV) + dev_err(&udev->dev, "device descriptor read/64, error %d\n", +- r); +- retval = -EMSGSIZE; ++ maxp0); ++ retval = maxp0; + continue; + } +-#undef GET_DESCRIPTOR_BUFSIZE + } + + /* +@@ -4966,18 +5008,22 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + break; + } + +- retval = usb_get_device_descriptor(udev, 8); +- if (retval < 8) { ++ /* !do_new_scheme || wusb */ ++ maxp0 = get_bMaxPacketSize0(udev, buf, 8, retries == 0); ++ if (maxp0 < 0) { ++ retval = maxp0; + if (retval != -ENODEV) + dev_err(&udev->dev, + "device descriptor read/8, error %d\n", + retval); +- if (retval >= 0) +- retval = -EMSGSIZE; + } else { + u32 delay; + +- retval = 0; ++ if (!initial && maxp0 != udev->descriptor.bMaxPacketSize0) { ++ dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n"); ++ retval = -ENODEV; ++ goto fail; ++ } + + delay = udev->parent->hub_delay; + udev->hub_delay = min_t(u32, delay, +@@ -4996,48 +5042,61 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + goto fail; + + /* +- * Some superspeed devices have finished the link training process +- * and attached to a superspeed hub port, but the device descriptor +- * got from those devices show they aren't superspeed devices. Warm +- * reset the port attached by the devices can fix them. ++ * Check the ep0 maxpacket guess and correct it if necessary. ++ * maxp0 is the value stored in the device descriptor; ++ * i is the value it encodes (logarithmic for SuperSpeed or greater). + */ +- if ((udev->speed >= USB_SPEED_SUPER) && +- (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) { +- dev_err(&udev->dev, "got a wrong device descriptor, " +- "warm reset device\n"); +- hub_port_reset(hub, port1, udev, +- HUB_BH_RESET_TIME, true); +- retval = -EINVAL; +- goto fail; +- } +- +- if (udev->descriptor.bMaxPacketSize0 == 0xff || +- udev->speed >= USB_SPEED_SUPER) +- i = 512; +- else +- i = udev->descriptor.bMaxPacketSize0; +- if (usb_endpoint_maxp(&udev->ep0.desc) != i) { +- if (udev->speed == USB_SPEED_LOW || +- !(i == 8 || i == 16 || i == 32 || i == 64)) { +- dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i); +- retval = -EMSGSIZE; +- goto fail; +- } ++ i = maxp0; ++ if (udev->speed >= USB_SPEED_SUPER) { ++ if (maxp0 <= 16) ++ i = 1 << maxp0; ++ else ++ i = 0; /* Invalid */ ++ } ++ if (usb_endpoint_maxp(&udev->ep0.desc) == i) { ++ ; /* Initial ep0 maxpacket guess is right */ ++ } else if ((udev->speed == USB_SPEED_FULL || ++ udev->speed == USB_SPEED_HIGH) && ++ (i == 8 || i == 16 || i == 32 || i == 64)) { ++ /* Initial guess is wrong; use the descriptor's value */ + if (udev->speed == USB_SPEED_FULL) + dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i); + else + dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i); + udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); + usb_ep0_reinit(udev); ++ } else { ++ /* Initial guess is wrong and descriptor's value is invalid */ ++ dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", maxp0); ++ retval = -EMSGSIZE; ++ goto fail; + } + +- retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); +- if (retval < (signed)sizeof(udev->descriptor)) { ++ descr = usb_get_device_descriptor(udev); ++ if (IS_ERR(descr)) { ++ retval = PTR_ERR(descr); + if (retval != -ENODEV) + dev_err(&udev->dev, "device descriptor read/all, error %d\n", + retval); +- if (retval >= 0) +- retval = -ENOMSG; ++ goto fail; ++ } ++ if (initial) ++ udev->descriptor = *descr; ++ else ++ *dev_descr = *descr; ++ kfree(descr); ++ ++ /* ++ * Some superspeed devices have finished the link training process ++ * and attached to a superspeed hub port, but the device descriptor ++ * got from those devices show they aren't superspeed devices. Warm ++ * reset the port attached by the devices can fix them. ++ */ ++ if ((udev->speed >= USB_SPEED_SUPER) && ++ (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) { ++ dev_err(&udev->dev, "got a wrong device descriptor, warm reset device\n"); ++ hub_port_reset(hub, port1, udev, HUB_BH_RESET_TIME, true); ++ retval = -EINVAL; + goto fail; + } + +@@ -5063,6 +5122,7 @@ fail: + hub_port_disable(hub, port1, 0); + update_devnum(udev, devnum); /* for disconnect processing */ + } ++ kfree(buf); + return retval; + } + +@@ -5143,7 +5203,7 @@ hub_power_remaining(struct usb_hub *hub) + + + static int descriptors_changed(struct usb_device *udev, +- struct usb_device_descriptor *old_device_descriptor, ++ struct usb_device_descriptor *new_device_descriptor, + struct usb_host_bos *old_bos) + { + int changed = 0; +@@ -5154,8 +5214,8 @@ static int descriptors_changed(struct usb_device *udev, + int length; + char *buf; + +- if (memcmp(&udev->descriptor, old_device_descriptor, +- sizeof(*old_device_descriptor)) != 0) ++ if (memcmp(&udev->descriptor, new_device_descriptor, ++ sizeof(*new_device_descriptor)) != 0) + return 1; + + if ((old_bos && !udev->bos) || (!old_bos && udev->bos)) +@@ -5333,7 +5393,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, + } + + /* reset (non-USB 3.0 devices) and get descriptor */ +- status = hub_port_init(hub, udev, port1, i); ++ status = hub_port_init(hub, udev, port1, i, NULL); + if (status < 0) + goto loop; + +@@ -5480,9 +5540,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, + { + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; +- struct usb_device_descriptor descriptor; ++ struct usb_device_descriptor *descr; + int status = -ENODEV; +- int retval; + + dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, + portchange, portspeed(hub, portstatus)); +@@ -5509,23 +5568,20 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, + * changed device descriptors before resuscitating the + * device. + */ +- descriptor = udev->descriptor; +- retval = usb_get_device_descriptor(udev, +- sizeof(udev->descriptor)); +- if (retval < 0) { ++ descr = usb_get_device_descriptor(udev); ++ if (IS_ERR(descr)) { + dev_dbg(&udev->dev, +- "can't read device descriptor %d\n", +- retval); ++ "can't read device descriptor %ld\n", ++ PTR_ERR(descr)); + } else { +- if (descriptors_changed(udev, &descriptor, ++ if (descriptors_changed(udev, descr, + udev->bos)) { + dev_dbg(&udev->dev, + "device descriptor has changed\n"); +- /* for disconnect() calls */ +- udev->descriptor = descriptor; + } else { + status = 0; /* Nothing to do */ + } ++ kfree(descr); + } + #ifdef CONFIG_PM + } else if (udev->state == USB_STATE_SUSPENDED && +@@ -5967,7 +6023,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) + struct usb_device *parent_hdev = udev->parent; + struct usb_hub *parent_hub; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); +- struct usb_device_descriptor descriptor = udev->descriptor; ++ struct usb_device_descriptor descriptor; + struct usb_host_bos *bos; + int i, j, ret = 0; + int port1 = udev->portnum; +@@ -6003,7 +6059,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) + /* ep0 maxpacket size may change; let the HCD know about it. + * Other endpoints will be handled by re-enumeration. */ + usb_ep0_reinit(udev); +- ret = hub_port_init(parent_hub, udev, port1, i); ++ ret = hub_port_init(parent_hub, udev, port1, i, &descriptor); + if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV) + break; + } +@@ -6015,7 +6071,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) + /* Device might have changed firmware (DFU or similar) */ + if (descriptors_changed(udev, &descriptor, bos)) { + dev_info(&udev->dev, "device firmware changed\n"); +- udev->descriptor = descriptor; /* for disconnect() calls */ + goto re_enumerate; + } + +diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c +index b5811620f1de1..1da8e7ff39830 100644 +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -1040,40 +1040,35 @@ char *usb_cache_string(struct usb_device *udev, int index) + EXPORT_SYMBOL_GPL(usb_cache_string); + + /* +- * usb_get_device_descriptor - (re)reads the device descriptor (usbcore) +- * @dev: the device whose device descriptor is being updated +- * @size: how much of the descriptor to read ++ * usb_get_device_descriptor - read the device descriptor ++ * @udev: the device whose device descriptor should be read + * + * Context: task context, might sleep. + * +- * Updates the copy of the device descriptor stored in the device structure, +- * which dedicates space for this purpose. +- * + * Not exported, only for use by the core. If drivers really want to read + * the device descriptor directly, they can call usb_get_descriptor() with + * type = USB_DT_DEVICE and index = 0. + * +- * This call is synchronous, and may not be used in an interrupt context. +- * +- * Return: The number of bytes received on success, or else the status code +- * returned by the underlying usb_control_msg() call. ++ * Returns: a pointer to a dynamically allocated usb_device_descriptor ++ * structure (which the caller must deallocate), or an ERR_PTR value. + */ +-int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) ++struct usb_device_descriptor *usb_get_device_descriptor(struct usb_device *udev) + { + struct usb_device_descriptor *desc; + int ret; + +- if (size > sizeof(*desc)) +- return -EINVAL; + desc = kmalloc(sizeof(*desc), GFP_NOIO); + if (!desc) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); ++ ++ ret = usb_get_descriptor(udev, USB_DT_DEVICE, 0, desc, sizeof(*desc)); ++ if (ret == sizeof(*desc)) ++ return desc; + +- ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); + if (ret >= 0) +- memcpy(&dev->descriptor, desc, size); ++ ret = -EMSGSIZE; + kfree(desc); +- return ret; ++ return ERR_PTR(ret); + } + + /* +diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h +index ffe3f6818e9cf..4a16d559d3bff 100644 +--- a/drivers/usb/core/usb.h ++++ b/drivers/usb/core/usb.h +@@ -43,8 +43,8 @@ extern bool usb_endpoint_is_ignored(struct usb_device *udev, + struct usb_endpoint_descriptor *epd); + extern int usb_remove_device(struct usb_device *udev); + +-extern int usb_get_device_descriptor(struct usb_device *dev, +- unsigned int size); ++extern struct usb_device_descriptor *usb_get_device_descriptor( ++ struct usb_device *udev); + extern int usb_set_isoch_delay(struct usb_device *dev); + extern int usb_get_bos_descriptor(struct usb_device *dev); + extern void usb_release_bos_descriptor(struct usb_device *dev); +diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c +index 3a30feb47073f..e927d82f0890d 100644 +--- a/drivers/usb/gadget/function/f_mass_storage.c ++++ b/drivers/usb/gadget/function/f_mass_storage.c +@@ -927,7 +927,7 @@ static void invalidate_sub(struct fsg_lun *curlun) + { + struct file *filp = curlun->filp; + struct inode *inode = file_inode(filp); +- unsigned long rc; ++ unsigned long __maybe_unused rc; + + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); +diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c +index d5bc2892184ca..5ec47757167e8 100644 +--- a/drivers/usb/gadget/udc/core.c ++++ b/drivers/usb/gadget/udc/core.c +@@ -40,6 +40,7 @@ static const struct bus_type gadget_bus_type; + * @allow_connect: Indicates whether UDC is allowed to be pulled up. + * Set/cleared by gadget_(un)bind_driver() after gadget driver is bound or + * unbound. ++ * @vbus_work: work routine to handle VBUS status change notifications. + * @connect_lock: protects udc->started, gadget->connect, + * gadget->allow_connect and gadget->deactivate. The routines + * usb_gadget_connect_locked(), usb_gadget_disconnect_locked(), +diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c +index e1a2b2ea098b5..cceabb9d37e98 100644 +--- a/drivers/usb/phy/phy-mxs-usb.c ++++ b/drivers/usb/phy/phy-mxs-usb.c +@@ -388,14 +388,8 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect) + + static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy) + { +- void __iomem *base = mxs_phy->phy.io_priv; +- u32 phyctrl = readl(base + HW_USBPHY_CTRL); +- +- if (IS_ENABLED(CONFIG_USB_OTG) && +- !(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE)) +- return true; +- +- return false; ++ return IS_ENABLED(CONFIG_USB_OTG) && ++ mxs_phy->phy.last_event == USB_EVENT_ID; + } + + static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) +diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c +index fe5b9a2e61f58..e95ec7e382bb7 100644 +--- a/drivers/usb/typec/bus.c ++++ b/drivers/usb/typec/bus.c +@@ -183,12 +183,20 @@ EXPORT_SYMBOL_GPL(typec_altmode_exit); + * + * Notifies the partner of @adev about Attention command. + */ +-void typec_altmode_attention(struct typec_altmode *adev, u32 vdo) ++int typec_altmode_attention(struct typec_altmode *adev, u32 vdo) + { +- struct typec_altmode *pdev = &to_altmode(adev)->partner->adev; ++ struct altmode *partner = to_altmode(adev)->partner; ++ struct typec_altmode *pdev; ++ ++ if (!partner) ++ return -ENODEV; ++ ++ pdev = &partner->adev; + + if (pdev->ops && pdev->ops->attention) + pdev->ops->attention(pdev, vdo); ++ ++ return 0; + } + EXPORT_SYMBOL_GPL(typec_altmode_attention); + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 9c4b73d23f833..43d0519683db9 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -1877,7 +1877,8 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, + } + break; + case ADEV_ATTENTION: +- typec_altmode_attention(adev, p[1]); ++ if (typec_altmode_attention(adev, p[1])) ++ tcpm_log(port, "typec_altmode_attention no port partner altmode"); + break; + } + } +@@ -3935,6 +3936,29 @@ static enum typec_cc_status tcpm_pwr_opmode_to_rp(enum typec_pwr_opmode opmode) + } + } + ++static void tcpm_set_initial_svdm_version(struct tcpm_port *port) ++{ ++ switch (port->negotiated_rev) { ++ case PD_REV30: ++ break; ++ /* ++ * 6.4.4.2.3 Structured VDM Version ++ * 2.0 states "At this time, there is only one version (1.0) defined. ++ * This field Shall be set to zero to indicate Version 1.0." ++ * 3.0 states "This field Shall be set to 01b to indicate Version 2.0." ++ * To ensure that we follow the Power Delivery revision we are currently ++ * operating on, downgrade the SVDM version to the highest one supported ++ * by the Power Delivery revision. ++ */ ++ case PD_REV20: ++ typec_partner_set_svdm_version(port->partner, SVDM_VER_1_0); ++ break; ++ default: ++ typec_partner_set_svdm_version(port->partner, SVDM_VER_1_0); ++ break; ++ } ++} ++ + static void run_state_machine(struct tcpm_port *port) + { + int ret; +@@ -4172,10 +4196,12 @@ static void run_state_machine(struct tcpm_port *port) + * For now, this driver only supports SOP for DISCOVER_IDENTITY, thus using + * port->explicit_contract to decide whether to send the command. + */ +- if (port->explicit_contract) ++ if (port->explicit_contract) { ++ tcpm_set_initial_svdm_version(port); + mod_send_discover_delayed_work(port, 0); +- else ++ } else { + port->send_discover = false; ++ } + + /* + * 6.3.5 +@@ -4462,10 +4488,12 @@ static void run_state_machine(struct tcpm_port *port) + * For now, this driver only supports SOP for DISCOVER_IDENTITY, thus using + * port->explicit_contract. + */ +- if (port->explicit_contract) ++ if (port->explicit_contract) { ++ tcpm_set_initial_svdm_version(port); + mod_send_discover_delayed_work(port, 0); +- else ++ } else { + port->send_discover = false; ++ } + + power_supply_changed(port->psy); + break; +diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c +index f18a9301ab94e..6b79ae746ab93 100644 +--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c ++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c +@@ -2447,7 +2447,15 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) + else + ndev->rqt_size = 1; + +- ndev->cur_num_vqs = 2 * ndev->rqt_size; ++ /* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section ++ * 5.1.6.5.5 "Device operation in multiqueue mode": ++ * ++ * Multiqueue is disabled by default. ++ * The driver enables multiqueue by sending a command using class ++ * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue ++ * operation, as follows: ... ++ */ ++ ndev->cur_num_vqs = 2; + + update_cvq_info(mvdev); + return err; +diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c +index 0d2f805468e19..cd2113be632b9 100644 +--- a/drivers/vfio/vfio_iommu_type1.c ++++ b/drivers/vfio/vfio_iommu_type1.c +@@ -2729,7 +2729,7 @@ static int vfio_iommu_iova_build_caps(struct vfio_iommu *iommu, + static int vfio_iommu_migration_build_caps(struct vfio_iommu *iommu, + struct vfio_info_cap *caps) + { +- struct vfio_iommu_type1_info_cap_migration cap_mig; ++ struct vfio_iommu_type1_info_cap_migration cap_mig = {}; + + cap_mig.header.id = VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION; + cap_mig.header.version = 1; +diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c +index bb10fa4bb4f6e..fa19c3f043b12 100644 +--- a/drivers/vhost/scsi.c ++++ b/drivers/vhost/scsi.c +@@ -25,6 +25,8 @@ + #include <linux/fs.h> + #include <linux/vmalloc.h> + #include <linux/miscdevice.h> ++#include <linux/blk_types.h> ++#include <linux/bio.h> + #include <asm/unaligned.h> + #include <scsi/scsi_common.h> + #include <scsi/scsi_proto.h> +@@ -75,6 +77,9 @@ struct vhost_scsi_cmd { + u32 tvc_prot_sgl_count; + /* Saved unpacked SCSI LUN for vhost_scsi_target_queue_cmd() */ + u32 tvc_lun; ++ u32 copied_iov:1; ++ const void *saved_iter_addr; ++ struct iov_iter saved_iter; + /* Pointer to the SGL formatted memory from virtio-scsi */ + struct scatterlist *tvc_sgl; + struct scatterlist *tvc_prot_sgl; +@@ -328,8 +333,13 @@ static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd) + int i; + + if (tv_cmd->tvc_sgl_count) { +- for (i = 0; i < tv_cmd->tvc_sgl_count; i++) +- put_page(sg_page(&tv_cmd->tvc_sgl[i])); ++ for (i = 0; i < tv_cmd->tvc_sgl_count; i++) { ++ if (tv_cmd->copied_iov) ++ __free_page(sg_page(&tv_cmd->tvc_sgl[i])); ++ else ++ put_page(sg_page(&tv_cmd->tvc_sgl[i])); ++ } ++ kfree(tv_cmd->saved_iter_addr); + } + if (tv_cmd->tvc_prot_sgl_count) { + for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++) +@@ -502,6 +512,28 @@ static void vhost_scsi_evt_work(struct vhost_work *work) + mutex_unlock(&vq->mutex); + } + ++static int vhost_scsi_copy_sgl_to_iov(struct vhost_scsi_cmd *cmd) ++{ ++ struct iov_iter *iter = &cmd->saved_iter; ++ struct scatterlist *sg = cmd->tvc_sgl; ++ struct page *page; ++ size_t len; ++ int i; ++ ++ for (i = 0; i < cmd->tvc_sgl_count; i++) { ++ page = sg_page(&sg[i]); ++ len = sg[i].length; ++ ++ if (copy_page_to_iter(page, 0, len, iter) != len) { ++ pr_err("Could not copy data while handling misaligned cmd. Error %zu\n", ++ len); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + /* Fill in status and signal that we are done processing this command + * + * This is scheduled in the vhost work queue so we are called with the owner +@@ -525,15 +557,20 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) + + pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, + cmd, se_cmd->residual_count, se_cmd->scsi_status); +- + memset(&v_rsp, 0, sizeof(v_rsp)); +- v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq, se_cmd->residual_count); +- /* TODO is status_qualifier field needed? */ +- v_rsp.status = se_cmd->scsi_status; +- v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq, +- se_cmd->scsi_sense_length); +- memcpy(v_rsp.sense, cmd->tvc_sense_buf, +- se_cmd->scsi_sense_length); ++ ++ if (cmd->saved_iter_addr && vhost_scsi_copy_sgl_to_iov(cmd)) { ++ v_rsp.response = VIRTIO_SCSI_S_BAD_TARGET; ++ } else { ++ v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq, ++ se_cmd->residual_count); ++ /* TODO is status_qualifier field needed? */ ++ v_rsp.status = se_cmd->scsi_status; ++ v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq, ++ se_cmd->scsi_sense_length); ++ memcpy(v_rsp.sense, cmd->tvc_sense_buf, ++ se_cmd->scsi_sense_length); ++ } + + iov_iter_init(&iov_iter, ITER_DEST, cmd->tvc_resp_iov, + cmd->tvc_in_iovs, sizeof(v_rsp)); +@@ -615,12 +652,12 @@ static int + vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd, + struct iov_iter *iter, + struct scatterlist *sgl, +- bool write) ++ bool is_prot) + { + struct page **pages = cmd->tvc_upages; + struct scatterlist *sg = sgl; +- ssize_t bytes; +- size_t offset; ++ ssize_t bytes, mapped_bytes; ++ size_t offset, mapped_offset; + unsigned int npages = 0; + + bytes = iov_iter_get_pages2(iter, pages, LONG_MAX, +@@ -629,13 +666,53 @@ vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd, + if (bytes <= 0) + return bytes < 0 ? bytes : -EFAULT; + ++ mapped_bytes = bytes; ++ mapped_offset = offset; ++ + while (bytes) { + unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes); ++ /* ++ * The block layer requires bios/requests to be a multiple of ++ * 512 bytes, but Windows can send us vecs that are misaligned. ++ * This can result in bios and later requests with misaligned ++ * sizes if we have to break up a cmd/scatterlist into multiple ++ * bios. ++ * ++ * We currently only break up a command into multiple bios if ++ * we hit the vec/seg limit, so check if our sgl_count is ++ * greater than the max and if a vec in the cmd has a ++ * misaligned offset/size. ++ */ ++ if (!is_prot && ++ (offset & (SECTOR_SIZE - 1) || n & (SECTOR_SIZE - 1)) && ++ cmd->tvc_sgl_count > BIO_MAX_VECS) { ++ WARN_ONCE(true, ++ "vhost-scsi detected misaligned IO. Performance may be degraded."); ++ goto revert_iter_get_pages; ++ } ++ + sg_set_page(sg++, pages[npages++], n, offset); + bytes -= n; + offset = 0; + } ++ + return npages; ++ ++revert_iter_get_pages: ++ iov_iter_revert(iter, mapped_bytes); ++ ++ npages = 0; ++ while (mapped_bytes) { ++ unsigned int n = min_t(unsigned int, PAGE_SIZE - mapped_offset, ++ mapped_bytes); ++ ++ put_page(pages[npages++]); ++ ++ mapped_bytes -= n; ++ mapped_offset = 0; ++ } ++ ++ return -EINVAL; + } + + static int +@@ -659,25 +736,80 @@ vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls) + } + + static int +-vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write, +- struct iov_iter *iter, +- struct scatterlist *sg, int sg_count) ++vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, ++ struct scatterlist *sg, int sg_count) ++{ ++ size_t len = iov_iter_count(iter); ++ unsigned int nbytes = 0; ++ struct page *page; ++ int i; ++ ++ if (cmd->tvc_data_direction == DMA_FROM_DEVICE) { ++ cmd->saved_iter_addr = dup_iter(&cmd->saved_iter, iter, ++ GFP_KERNEL); ++ if (!cmd->saved_iter_addr) ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < sg_count; i++) { ++ page = alloc_page(GFP_KERNEL); ++ if (!page) { ++ i--; ++ goto err; ++ } ++ ++ nbytes = min_t(unsigned int, PAGE_SIZE, len); ++ sg_set_page(&sg[i], page, nbytes, 0); ++ ++ if (cmd->tvc_data_direction == DMA_TO_DEVICE && ++ copy_page_from_iter(page, 0, nbytes, iter) != nbytes) ++ goto err; ++ ++ len -= nbytes; ++ } ++ ++ cmd->copied_iov = 1; ++ return 0; ++ ++err: ++ pr_err("Could not read %u bytes while handling misaligned cmd\n", ++ nbytes); ++ ++ for (; i >= 0; i--) ++ __free_page(sg_page(&sg[i])); ++ kfree(cmd->saved_iter_addr); ++ return -ENOMEM; ++} ++ ++static int ++vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, ++ struct scatterlist *sg, int sg_count, bool is_prot) + { + struct scatterlist *p = sg; ++ size_t revert_bytes; + int ret; + + while (iov_iter_count(iter)) { +- ret = vhost_scsi_map_to_sgl(cmd, iter, sg, write); ++ ret = vhost_scsi_map_to_sgl(cmd, iter, sg, is_prot); + if (ret < 0) { ++ revert_bytes = 0; ++ + while (p < sg) { +- struct page *page = sg_page(p++); +- if (page) ++ struct page *page = sg_page(p); ++ ++ if (page) { + put_page(page); ++ revert_bytes += p->length; ++ } ++ p++; + } ++ ++ iov_iter_revert(iter, revert_bytes); + return ret; + } + sg += ret; + } ++ + return 0; + } + +@@ -687,7 +819,6 @@ vhost_scsi_mapal(struct vhost_scsi_cmd *cmd, + size_t data_bytes, struct iov_iter *data_iter) + { + int sgl_count, ret; +- bool write = (cmd->tvc_data_direction == DMA_FROM_DEVICE); + + if (prot_bytes) { + sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes, +@@ -700,9 +831,8 @@ vhost_scsi_mapal(struct vhost_scsi_cmd *cmd, + pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__, + cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count); + +- ret = vhost_scsi_iov_to_sgl(cmd, write, prot_iter, +- cmd->tvc_prot_sgl, +- cmd->tvc_prot_sgl_count); ++ ret = vhost_scsi_iov_to_sgl(cmd, prot_iter, cmd->tvc_prot_sgl, ++ cmd->tvc_prot_sgl_count, true); + if (ret < 0) { + cmd->tvc_prot_sgl_count = 0; + return ret; +@@ -718,8 +848,14 @@ vhost_scsi_mapal(struct vhost_scsi_cmd *cmd, + pr_debug("%s data_sg %p data_sgl_count %u\n", __func__, + cmd->tvc_sgl, cmd->tvc_sgl_count); + +- ret = vhost_scsi_iov_to_sgl(cmd, write, data_iter, +- cmd->tvc_sgl, cmd->tvc_sgl_count); ++ ret = vhost_scsi_iov_to_sgl(cmd, data_iter, cmd->tvc_sgl, ++ cmd->tvc_sgl_count, false); ++ if (ret == -EINVAL) { ++ sg_init_table(cmd->tvc_sgl, cmd->tvc_sgl_count); ++ ret = vhost_scsi_copy_iov_to_sgl(cmd, data_iter, cmd->tvc_sgl, ++ cmd->tvc_sgl_count); ++ } ++ + if (ret < 0) { + cmd->tvc_sgl_count = 0; + return ret; +diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c +index f4db6c064635b..e3410444ea235 100644 +--- a/drivers/video/backlight/bd6107.c ++++ b/drivers/video/backlight/bd6107.c +@@ -104,7 +104,7 @@ static int bd6107_backlight_check_fb(struct backlight_device *backlight, + { + struct bd6107 *bd = bl_get_data(backlight); + +- return bd->pdata->fbdev == NULL || bd->pdata->fbdev == info->dev; ++ return bd->pdata->fbdev == NULL || bd->pdata->fbdev == info->device; + } + + static const struct backlight_ops bd6107_backlight_ops = { +diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c +index 6f78d928f054a..5c5c99f7979e3 100644 +--- a/drivers/video/backlight/gpio_backlight.c ++++ b/drivers/video/backlight/gpio_backlight.c +@@ -35,7 +35,7 @@ static int gpio_backlight_check_fb(struct backlight_device *bl, + { + struct gpio_backlight *gbl = bl_get_data(bl); + +- return gbl->fbdev == NULL || gbl->fbdev == info->dev; ++ return gbl->fbdev == NULL || gbl->fbdev == info->device; + } + + static const struct backlight_ops gpio_backlight_ops = { +diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c +index 00673c8b66ac5..99ba4bc0a500d 100644 +--- a/drivers/video/backlight/lv5207lp.c ++++ b/drivers/video/backlight/lv5207lp.c +@@ -67,7 +67,7 @@ static int lv5207lp_backlight_check_fb(struct backlight_device *backlight, + { + struct lv5207lp *lv = bl_get_data(backlight); + +- return lv->pdata->fbdev == NULL || lv->pdata->fbdev == info->dev; ++ return lv->pdata->fbdev == NULL || lv->pdata->fbdev == info->device; + } + + static const struct backlight_ops lv5207lp_backlight_ops = { +diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c +index 6fa2108fd912d..e41c9fef4a3b6 100644 +--- a/drivers/video/fbdev/goldfishfb.c ++++ b/drivers/video/fbdev/goldfishfb.c +@@ -203,8 +203,8 @@ static int goldfish_fb_probe(struct platform_device *pdev) + } + + fb->irq = platform_get_irq(pdev, 0); +- if (fb->irq <= 0) { +- ret = -ENODEV; ++ if (fb->irq < 0) { ++ ret = fb->irq; + goto err_no_irq; + } + +diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c +index 835f6cc2fb664..fa5226c198cc6 100644 +--- a/drivers/virtio/virtio_mem.c ++++ b/drivers/virtio/virtio_mem.c +@@ -38,11 +38,6 @@ module_param(bbm_block_size, ulong, 0444); + MODULE_PARM_DESC(bbm_block_size, + "Big Block size in bytes. Default is 0 (auto-detection)."); + +-static bool bbm_safe_unplug = true; +-module_param(bbm_safe_unplug, bool, 0444); +-MODULE_PARM_DESC(bbm_safe_unplug, +- "Use a safe unplug mechanism in BBM, avoiding long/endless loops"); +- + /* + * virtio-mem currently supports the following modes of operation: + * +@@ -173,6 +168,13 @@ struct virtio_mem { + /* The number of subblocks per Linux memory block. */ + uint32_t sbs_per_mb; + ++ /* ++ * Some of the Linux memory blocks tracked as "partially ++ * plugged" are completely unplugged and can be offlined ++ * and removed -- which previously failed. ++ */ ++ bool have_unplugged_mb; ++ + /* Summary of all memory block states. */ + unsigned long mb_count[VIRTIO_MEM_SBM_MB_COUNT]; + +@@ -746,11 +748,15 @@ static int virtio_mem_offline_and_remove_memory(struct virtio_mem *vm, + * immediately instead of waiting. + */ + virtio_mem_retry(vm); +- } else { +- dev_dbg(&vm->vdev->dev, +- "offlining and removing memory failed: %d\n", rc); ++ return 0; + } +- return rc; ++ dev_dbg(&vm->vdev->dev, "offlining and removing memory failed: %d\n", rc); ++ /* ++ * We don't really expect this to fail, because we fake-offlined all ++ * memory already. But it could fail in corner cases. ++ */ ++ WARN_ON_ONCE(rc != -ENOMEM && rc != -EBUSY); ++ return rc == -ENOMEM ? -ENOMEM : -EBUSY; + } + + /* +@@ -766,6 +772,34 @@ static int virtio_mem_sbm_offline_and_remove_mb(struct virtio_mem *vm, + return virtio_mem_offline_and_remove_memory(vm, addr, size); + } + ++/* ++ * Try (offlining and) removing memory from Linux in case all subblocks are ++ * unplugged. Can be called on online and offline memory blocks. ++ * ++ * May modify the state of memory blocks in virtio-mem. ++ */ ++static int virtio_mem_sbm_try_remove_unplugged_mb(struct virtio_mem *vm, ++ unsigned long mb_id) ++{ ++ int rc; ++ ++ /* ++ * Once all subblocks of a memory block were unplugged, offline and ++ * remove it. ++ */ ++ if (!virtio_mem_sbm_test_sb_unplugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) ++ return 0; ++ ++ /* offline_and_remove_memory() works for online and offline memory. */ ++ mutex_unlock(&vm->hotplug_mutex); ++ rc = virtio_mem_sbm_offline_and_remove_mb(vm, mb_id); ++ mutex_lock(&vm->hotplug_mutex); ++ if (!rc) ++ virtio_mem_sbm_set_mb_state(vm, mb_id, ++ VIRTIO_MEM_SBM_MB_UNUSED); ++ return rc; ++} ++ + /* + * See virtio_mem_offline_and_remove_memory(): Try to offline and remove a + * all Linux memory blocks covered by the big block. +@@ -1155,7 +1189,8 @@ static void virtio_mem_fake_online(unsigned long pfn, unsigned long nr_pages) + * Try to allocate a range, marking pages fake-offline, effectively + * fake-offlining them. + */ +-static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages) ++static int virtio_mem_fake_offline(struct virtio_mem *vm, unsigned long pfn, ++ unsigned long nr_pages) + { + const bool is_movable = is_zone_movable_page(pfn_to_page(pfn)); + int rc, retry_count; +@@ -1168,6 +1203,14 @@ static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages) + * some guarantees. + */ + for (retry_count = 0; retry_count < 5; retry_count++) { ++ /* ++ * If the config changed, stop immediately and go back to the ++ * main loop: avoid trying to keep unplugging if the device ++ * might have decided to not remove any more memory. ++ */ ++ if (atomic_read(&vm->config_changed)) ++ return -EAGAIN; ++ + rc = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_MOVABLE, + GFP_KERNEL); + if (rc == -ENOMEM) +@@ -1917,7 +1960,7 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm, + start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + + sb_id * vm->sbm.sb_size); + +- rc = virtio_mem_fake_offline(start_pfn, nr_pages); ++ rc = virtio_mem_fake_offline(vm, start_pfn, nr_pages); + if (rc) + return rc; + +@@ -1989,20 +2032,10 @@ static int virtio_mem_sbm_unplug_any_sb_online(struct virtio_mem *vm, + } + + unplugged: +- /* +- * Once all subblocks of a memory block were unplugged, offline and +- * remove it. This will usually not fail, as no memory is in use +- * anymore - however some other notifiers might NACK the request. +- */ +- if (virtio_mem_sbm_test_sb_unplugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) { +- mutex_unlock(&vm->hotplug_mutex); +- rc = virtio_mem_sbm_offline_and_remove_mb(vm, mb_id); +- mutex_lock(&vm->hotplug_mutex); +- if (!rc) +- virtio_mem_sbm_set_mb_state(vm, mb_id, +- VIRTIO_MEM_SBM_MB_UNUSED); +- } +- ++ rc = virtio_mem_sbm_try_remove_unplugged_mb(vm, mb_id); ++ if (rc) ++ vm->sbm.have_unplugged_mb = 1; ++ /* Ignore errors, this is not critical. We'll retry later. */ + return 0; + } + +@@ -2111,38 +2144,32 @@ static int virtio_mem_bbm_offline_remove_and_unplug_bb(struct virtio_mem *vm, + VIRTIO_MEM_BBM_BB_ADDED)) + return -EINVAL; + +- if (bbm_safe_unplug) { +- /* +- * Start by fake-offlining all memory. Once we marked the device +- * block as fake-offline, all newly onlined memory will +- * automatically be kept fake-offline. Protect from concurrent +- * onlining/offlining until we have a consistent state. +- */ +- mutex_lock(&vm->hotplug_mutex); +- virtio_mem_bbm_set_bb_state(vm, bb_id, +- VIRTIO_MEM_BBM_BB_FAKE_OFFLINE); ++ /* ++ * Start by fake-offlining all memory. Once we marked the device ++ * block as fake-offline, all newly onlined memory will ++ * automatically be kept fake-offline. Protect from concurrent ++ * onlining/offlining until we have a consistent state. ++ */ ++ mutex_lock(&vm->hotplug_mutex); ++ virtio_mem_bbm_set_bb_state(vm, bb_id, VIRTIO_MEM_BBM_BB_FAKE_OFFLINE); + +- for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { +- page = pfn_to_online_page(pfn); +- if (!page) +- continue; ++ for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { ++ page = pfn_to_online_page(pfn); ++ if (!page) ++ continue; + +- rc = virtio_mem_fake_offline(pfn, PAGES_PER_SECTION); +- if (rc) { +- end_pfn = pfn; +- goto rollback_safe_unplug; +- } ++ rc = virtio_mem_fake_offline(vm, pfn, PAGES_PER_SECTION); ++ if (rc) { ++ end_pfn = pfn; ++ goto rollback; + } +- mutex_unlock(&vm->hotplug_mutex); + } ++ mutex_unlock(&vm->hotplug_mutex); + + rc = virtio_mem_bbm_offline_and_remove_bb(vm, bb_id); + if (rc) { +- if (bbm_safe_unplug) { +- mutex_lock(&vm->hotplug_mutex); +- goto rollback_safe_unplug; +- } +- return rc; ++ mutex_lock(&vm->hotplug_mutex); ++ goto rollback; + } + + rc = virtio_mem_bbm_unplug_bb(vm, bb_id); +@@ -2154,7 +2181,7 @@ static int virtio_mem_bbm_offline_remove_and_unplug_bb(struct virtio_mem *vm, + VIRTIO_MEM_BBM_BB_UNUSED); + return rc; + +-rollback_safe_unplug: ++rollback: + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + page = pfn_to_online_page(pfn); + if (!page) +@@ -2260,12 +2287,13 @@ static int virtio_mem_unplug_request(struct virtio_mem *vm, uint64_t diff) + + /* + * Try to unplug all blocks that couldn't be unplugged before, for example, +- * because the hypervisor was busy. ++ * because the hypervisor was busy. Further, offline and remove any memory ++ * blocks where we previously failed. + */ +-static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm) ++static int virtio_mem_cleanup_pending_mb(struct virtio_mem *vm) + { + unsigned long id; +- int rc; ++ int rc = 0; + + if (!vm->in_sbm) { + virtio_mem_bbm_for_each_bb(vm, id, +@@ -2287,6 +2315,27 @@ static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm) + VIRTIO_MEM_SBM_MB_UNUSED); + } + ++ if (!vm->sbm.have_unplugged_mb) ++ return 0; ++ ++ /* ++ * Let's retry (offlining and) removing completely unplugged Linux ++ * memory blocks. ++ */ ++ vm->sbm.have_unplugged_mb = false; ++ ++ mutex_lock(&vm->hotplug_mutex); ++ virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL) ++ rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id); ++ virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL) ++ rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id); ++ virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL) ++ rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id); ++ mutex_unlock(&vm->hotplug_mutex); ++ ++ if (rc) ++ vm->sbm.have_unplugged_mb = true; ++ /* Ignore errors, this is not critical. We'll retry later. */ + return 0; + } + +@@ -2368,9 +2417,9 @@ retry: + virtio_mem_refresh_config(vm); + } + +- /* Unplug any leftovers from previous runs */ ++ /* Cleanup any leftovers from previous runs */ + if (!rc) +- rc = virtio_mem_unplug_pending_mb(vm); ++ rc = virtio_mem_cleanup_pending_mb(vm); + + if (!rc && vm->requested_size != vm->plugged_size) { + if (vm->requested_size > vm->plugged_size) { +@@ -2382,6 +2431,13 @@ retry: + } + } + ++ /* ++ * Keep retrying to offline and remove completely unplugged Linux ++ * memory blocks. ++ */ ++ if (!rc && vm->in_sbm && vm->sbm.have_unplugged_mb) ++ rc = -EBUSY; ++ + switch (rc) { + case 0: + vm->retry_timer_ms = VIRTIO_MEM_RETRY_TIMER_MIN_MS; +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index c5310eaf8b468..da1150d127c24 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -1461,7 +1461,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq, + } + } + +- if (i < head) ++ if (i <= head) + vq->packed.avail_wrap_counter ^= 1; + + /* We're using some buffers from the free list. */ +diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c +index 961161da59000..06ce6d8c2e004 100644 +--- a/drivers/virtio/virtio_vdpa.c ++++ b/drivers/virtio/virtio_vdpa.c +@@ -366,11 +366,14 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + struct irq_affinity default_affd = { 0 }; + struct cpumask *masks; + struct vdpa_callback cb; ++ bool has_affinity = desc && ops->set_vq_affinity; + int i, err, queue_idx = 0; + +- masks = create_affinity_masks(nvqs, desc ? desc : &default_affd); +- if (!masks) +- return -ENOMEM; ++ if (has_affinity) { ++ masks = create_affinity_masks(nvqs, desc ? desc : &default_affd); ++ if (!masks) ++ return -ENOMEM; ++ } + + for (i = 0; i < nvqs; ++i) { + if (!names[i]) { +@@ -386,20 +389,22 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + goto err_setup_vq; + } + +- if (ops->set_vq_affinity) ++ if (has_affinity) + ops->set_vq_affinity(vdpa, i, &masks[i]); + } + + cb.callback = virtio_vdpa_config_cb; + cb.private = vd_dev; + ops->set_config_cb(vdpa, &cb); +- kfree(masks); ++ if (has_affinity) ++ kfree(masks); + + return 0; + + err_setup_vq: + virtio_vdpa_del_vqs(vdev); +- kfree(masks); ++ if (has_affinity) ++ kfree(masks); + return err; + } + +diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c +index 70a4752ed913a..fd603e06d07fe 100644 +--- a/fs/dlm/plock.c ++++ b/fs/dlm/plock.c +@@ -456,7 +456,8 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, + } + } else { + list_for_each_entry(iter, &recv_list, list) { +- if (!iter->info.wait) { ++ if (!iter->info.wait && ++ iter->info.fsid == info.fsid) { + op = iter; + break; + } +@@ -468,8 +469,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, + if (info.wait) + WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK); + else +- WARN_ON(op->info.fsid != info.fsid || +- op->info.number != info.number || ++ WARN_ON(op->info.number != info.number || + op->info.owner != info.owner || + op->info.optype != info.optype); + +diff --git a/fs/eventfd.c b/fs/eventfd.c +index 95850a13ce8d0..1ffbf7c1cd16d 100644 +--- a/fs/eventfd.c ++++ b/fs/eventfd.c +@@ -189,7 +189,7 @@ void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt) + { + lockdep_assert_held(&ctx->wqh.lock); + +- *cnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count; ++ *cnt = ((ctx->flags & EFD_SEMAPHORE) && ctx->count) ? 1 : ctx->count; + ctx->count -= *cnt; + } + EXPORT_SYMBOL_GPL(eventfd_ctx_do_read); +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 3fa5de892d89d..333439b3ac146 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -966,8 +966,9 @@ static inline int should_optimize_scan(struct ext4_allocation_context *ac) + * Return next linear group for allocation. If linear traversal should not be + * performed, this function just returns the same group + */ +-static int +-next_linear_group(struct ext4_allocation_context *ac, int group, int ngroups) ++static ext4_group_t ++next_linear_group(struct ext4_allocation_context *ac, ext4_group_t group, ++ ext4_group_t ngroups) + { + if (!should_optimize_scan(ac)) + goto inc_and_return; +@@ -2414,7 +2415,7 @@ static bool ext4_mb_good_group(struct ext4_allocation_context *ac, + + BUG_ON(cr < 0 || cr >= 4); + +- if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp) || !grp)) ++ if (unlikely(!grp || EXT4_MB_GRP_BBITMAP_CORRUPT(grp))) + return false; + + free = grp->bb_free; +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 0caf6c730ce34..6bcc3770ee19f 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2799,6 +2799,7 @@ static int ext4_add_nondir(handle_t *handle, + return err; + } + drop_nlink(inode); ++ ext4_mark_inode_dirty(handle, inode); + ext4_orphan_add(handle, inode); + unlock_new_inode(inode); + return err; +@@ -3436,6 +3437,7 @@ retry: + + err_drop_inode: + clear_nlink(inode); ++ ext4_mark_inode_dirty(handle, inode); + ext4_orphan_add(handle, inode); + unlock_new_inode(inode); + if (handle) +@@ -4021,6 +4023,7 @@ end_rename: + ext4_resetent(handle, &old, + old.inode->i_ino, old_file_type); + drop_nlink(whiteout); ++ ext4_mark_inode_dirty(handle, whiteout); + ext4_orphan_add(handle, whiteout); + } + unlock_new_inode(whiteout); +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +index 8fd3b7f9fb88e..b0597a539fc54 100644 +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -1701,9 +1701,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) + } + + f2fs_restore_inmem_curseg(sbi); ++ stat_inc_cp_count(sbi); + stop: + unblock_operations(sbi); +- stat_inc_cp_count(sbi->stat_info); + + if (cpc->reason & CP_RECOVERY) + f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver); +diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c +index 61c35b59126ec..fdbf994f12718 100644 +--- a/fs/f2fs/debug.c ++++ b/fs/f2fs/debug.c +@@ -215,6 +215,9 @@ static void update_general_status(struct f2fs_sb_info *sbi) + si->valid_blks[type] += blks; + } + ++ for (i = 0; i < MAX_CALL_TYPE; i++) ++ si->cp_call_count[i] = atomic_read(&sbi->cp_call_count[i]); ++ + for (i = 0; i < 2; i++) { + si->segment_count[i] = sbi->segment_count[i]; + si->block_count[i] = sbi->block_count[i]; +@@ -497,7 +500,9 @@ static int stat_show(struct seq_file *s, void *v) + seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", + si->prefree_count, si->free_segs, si->free_secs); + seq_printf(s, "CP calls: %d (BG: %d)\n", +- si->cp_count, si->bg_cp_count); ++ si->cp_call_count[TOTAL_CALL], ++ si->cp_call_count[BACKGROUND]); ++ seq_printf(s, "CP count: %d\n", si->cp_count); + seq_printf(s, " - cp blocks : %u\n", si->meta_count[META_CP]); + seq_printf(s, " - sit blocks : %u\n", + si->meta_count[META_SIT]); +@@ -511,12 +516,24 @@ static int stat_show(struct seq_file *s, void *v) + seq_printf(s, " - Total : %4d\n", si->nr_total_ckpt); + seq_printf(s, " - Cur time : %4d(ms)\n", si->cur_ckpt_time); + seq_printf(s, " - Peak time : %4d(ms)\n", si->peak_ckpt_time); +- seq_printf(s, "GC calls: %d (BG: %d)\n", +- si->call_count, si->bg_gc); +- seq_printf(s, " - data segments : %d (%d)\n", +- si->data_segs, si->bg_data_segs); +- seq_printf(s, " - node segments : %d (%d)\n", +- si->node_segs, si->bg_node_segs); ++ seq_printf(s, "GC calls: %d (gc_thread: %d)\n", ++ si->gc_call_count[BACKGROUND] + ++ si->gc_call_count[FOREGROUND], ++ si->gc_call_count[BACKGROUND]); ++ if (__is_large_section(sbi)) { ++ seq_printf(s, " - data sections : %d (BG: %d)\n", ++ si->gc_secs[DATA][BG_GC] + si->gc_secs[DATA][FG_GC], ++ si->gc_secs[DATA][BG_GC]); ++ seq_printf(s, " - node sections : %d (BG: %d)\n", ++ si->gc_secs[NODE][BG_GC] + si->gc_secs[NODE][FG_GC], ++ si->gc_secs[NODE][BG_GC]); ++ } ++ seq_printf(s, " - data segments : %d (BG: %d)\n", ++ si->gc_segs[DATA][BG_GC] + si->gc_segs[DATA][FG_GC], ++ si->gc_segs[DATA][BG_GC]); ++ seq_printf(s, " - node segments : %d (BG: %d)\n", ++ si->gc_segs[NODE][BG_GC] + si->gc_segs[NODE][FG_GC], ++ si->gc_segs[NODE][BG_GC]); + seq_puts(s, " - Reclaimed segs :\n"); + seq_printf(s, " - Normal : %d\n", sbi->gc_reclaimed_segs[GC_NORMAL]); + seq_printf(s, " - Idle CB : %d\n", sbi->gc_reclaimed_segs[GC_IDLE_CB]); +@@ -687,6 +704,8 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) + atomic_set(&sbi->inplace_count, 0); + for (i = META_CP; i < META_MAX; i++) + atomic_set(&sbi->meta_count[i], 0); ++ for (i = 0; i < MAX_CALL_TYPE; i++) ++ atomic_set(&sbi->cp_call_count[i], 0); + + atomic_set(&sbi->max_aw_cnt, 0); + +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index 271d4e7b22c91..cfb8e274c0699 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1377,6 +1377,13 @@ enum errors_option { + MOUNT_ERRORS_PANIC, /* panic on errors */ + }; + ++enum { ++ BACKGROUND, ++ FOREGROUND, ++ MAX_CALL_TYPE, ++ TOTAL_CALL = FOREGROUND, ++}; ++ + static inline int f2fs_test_bit(unsigned int nr, char *addr); + static inline void f2fs_set_bit(unsigned int nr, char *addr); + static inline void f2fs_clear_bit(unsigned int nr, char *addr); +@@ -1687,6 +1694,7 @@ struct f2fs_sb_info { + unsigned int io_skip_bggc; /* skip background gc for in-flight IO */ + unsigned int other_skip_bggc; /* skip background gc for other reasons */ + unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ ++ atomic_t cp_call_count[MAX_CALL_TYPE]; /* # of cp call */ + #endif + spinlock_t stat_lock; /* lock for stat operations */ + +@@ -3873,7 +3881,7 @@ struct f2fs_stat_info { + int nats, dirty_nats, sits, dirty_sits; + int free_nids, avail_nids, alloc_nids; + int total_count, utilization; +- int bg_gc, nr_wb_cp_data, nr_wb_data; ++ int nr_wb_cp_data, nr_wb_data; + int nr_rd_data, nr_rd_node, nr_rd_meta; + int nr_dio_read, nr_dio_write; + unsigned int io_skip_bggc, other_skip_bggc; +@@ -3893,9 +3901,11 @@ struct f2fs_stat_info { + int rsvd_segs, overp_segs; + int dirty_count, node_pages, meta_pages, compress_pages; + int compress_page_hit; +- int prefree_count, call_count, cp_count, bg_cp_count; +- int tot_segs, node_segs, data_segs, free_segs, free_secs; +- int bg_node_segs, bg_data_segs; ++ int prefree_count, free_segs, free_secs; ++ int cp_call_count[MAX_CALL_TYPE], cp_count; ++ int gc_call_count[MAX_CALL_TYPE]; ++ int gc_segs[2][2]; ++ int gc_secs[2][2]; + int tot_blks, data_blks, node_blks; + int bg_data_blks, bg_node_blks; + int curseg[NR_CURSEG_TYPE]; +@@ -3917,10 +3927,9 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) + return (struct f2fs_stat_info *)sbi->stat_info; + } + +-#define stat_inc_cp_count(si) ((si)->cp_count++) +-#define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++) +-#define stat_inc_call_count(si) ((si)->call_count++) +-#define stat_inc_bggc_count(si) ((si)->bg_gc++) ++#define stat_inc_cp_call_count(sbi, foreground) \ ++ atomic_inc(&sbi->cp_call_count[(foreground)]) ++#define stat_inc_cp_count(si) (F2FS_STAT(sbi)->cp_count++) + #define stat_io_skip_bggc_count(sbi) ((sbi)->io_skip_bggc++) + #define stat_other_skip_bggc_count(sbi) ((sbi)->other_skip_bggc++) + #define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++) +@@ -4005,18 +4014,12 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) + if (cur > max) \ + atomic_set(&F2FS_I_SB(inode)->max_aw_cnt, cur); \ + } while (0) +-#define stat_inc_seg_count(sbi, type, gc_type) \ +- do { \ +- struct f2fs_stat_info *si = F2FS_STAT(sbi); \ +- si->tot_segs++; \ +- if ((type) == SUM_TYPE_DATA) { \ +- si->data_segs++; \ +- si->bg_data_segs += (gc_type == BG_GC) ? 1 : 0; \ +- } else { \ +- si->node_segs++; \ +- si->bg_node_segs += (gc_type == BG_GC) ? 1 : 0; \ +- } \ +- } while (0) ++#define stat_inc_gc_call_count(sbi, foreground) \ ++ (F2FS_STAT(sbi)->gc_call_count[(foreground)]++) ++#define stat_inc_gc_sec_count(sbi, type, gc_type) \ ++ (F2FS_STAT(sbi)->gc_secs[(type)][(gc_type)]++) ++#define stat_inc_gc_seg_count(sbi, type, gc_type) \ ++ (F2FS_STAT(sbi)->gc_segs[(type)][(gc_type)]++) + + #define stat_inc_tot_blk_count(si, blks) \ + ((si)->tot_blks += (blks)) +@@ -4043,10 +4046,8 @@ void __init f2fs_create_root_stats(void); + void f2fs_destroy_root_stats(void); + void f2fs_update_sit_info(struct f2fs_sb_info *sbi); + #else +-#define stat_inc_cp_count(si) do { } while (0) +-#define stat_inc_bg_cp_count(si) do { } while (0) +-#define stat_inc_call_count(si) do { } while (0) +-#define stat_inc_bggc_count(si) do { } while (0) ++#define stat_inc_cp_call_count(sbi, foreground) do { } while (0) ++#define stat_inc_cp_count(sbi) do { } while (0) + #define stat_io_skip_bggc_count(sbi) do { } while (0) + #define stat_other_skip_bggc_count(sbi) do { } while (0) + #define stat_inc_dirty_inode(sbi, type) do { } while (0) +@@ -4074,7 +4075,9 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi); + #define stat_inc_seg_type(sbi, curseg) do { } while (0) + #define stat_inc_block_count(sbi, curseg) do { } while (0) + #define stat_inc_inplace_blocks(sbi) do { } while (0) +-#define stat_inc_seg_count(sbi, type, gc_type) do { } while (0) ++#define stat_inc_gc_call_count(sbi, foreground) do { } while (0) ++#define stat_inc_gc_sec_count(sbi, type, gc_type) do { } while (0) ++#define stat_inc_gc_seg_count(sbi, type, gc_type) do { } while (0) + #define stat_inc_tot_blk_count(si, blks) do { } while (0) + #define stat_inc_data_blk_count(sbi, blks, gc_type) do { } while (0) + #define stat_inc_node_blk_count(sbi, blks, gc_type) do { } while (0) +@@ -4469,7 +4472,8 @@ static inline bool f2fs_low_mem_mode(struct f2fs_sb_info *sbi) + static inline bool f2fs_may_compress(struct inode *inode) + { + if (IS_SWAPFILE(inode) || f2fs_is_pinned_file(inode) || +- f2fs_is_atomic_file(inode) || f2fs_has_inline_data(inode)) ++ f2fs_is_atomic_file(inode) || f2fs_has_inline_data(inode) || ++ f2fs_is_mmap_file(inode)) + return false; + return S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode); + } +diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c +index ead75c4e833d2..094b047d246c9 100644 +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -528,7 +528,11 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) + + file_accessed(file); + vma->vm_ops = &f2fs_file_vm_ops; ++ ++ f2fs_down_read(&F2FS_I(inode)->i_sem); + set_inode_flag(inode, FI_MMAP_FILE); ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++ + return 0; + } + +@@ -1725,6 +1729,7 @@ next_alloc: + if (has_not_enough_free_secs(sbi, 0, + GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) { + f2fs_down_write(&sbi->gc_lock); ++ stat_inc_gc_call_count(sbi, FOREGROUND); + err = f2fs_gc(sbi, &gc_control); + if (err && err != -ENODATA) + goto out_err; +@@ -1920,12 +1925,19 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) + int err = f2fs_convert_inline_inode(inode); + if (err) + return err; +- if (!f2fs_may_compress(inode)) +- return -EINVAL; +- if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode)) ++ ++ f2fs_down_write(&F2FS_I(inode)->i_sem); ++ if (!f2fs_may_compress(inode) || ++ (S_ISREG(inode->i_mode) && ++ F2FS_HAS_BLOCKS(inode))) { ++ f2fs_up_write(&F2FS_I(inode)->i_sem); + return -EINVAL; +- if (set_compress_context(inode)) +- return -EOPNOTSUPP; ++ } ++ err = set_compress_context(inode); ++ f2fs_up_write(&F2FS_I(inode)->i_sem); ++ ++ if (err) ++ return err; + } + } + +@@ -2466,6 +2478,7 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg) + + gc_control.init_gc_type = sync ? FG_GC : BG_GC; + gc_control.err_gc_skipped = sync; ++ stat_inc_gc_call_count(sbi, FOREGROUND); + ret = f2fs_gc(sbi, &gc_control); + out: + mnt_drop_write_file(filp); +@@ -2509,6 +2522,7 @@ do_more: + } + + gc_control.victim_segno = GET_SEGNO(sbi, range->start); ++ stat_inc_gc_call_count(sbi, FOREGROUND); + ret = f2fs_gc(sbi, &gc_control); + if (ret) { + if (ret == -EBUSY) +@@ -2980,6 +2994,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) + sm->last_victim[ALLOC_NEXT] = end_segno + 1; + + gc_control.victim_segno = start_segno; ++ stat_inc_gc_call_count(sbi, FOREGROUND); + ret = f2fs_gc(sbi, &gc_control); + if (ret == -EAGAIN) + ret = 0; +@@ -3953,6 +3968,7 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) + file_start_write(filp); + inode_lock(inode); + ++ f2fs_down_write(&F2FS_I(inode)->i_sem); + if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) { + ret = -EBUSY; + goto out; +@@ -3972,6 +3988,7 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) + f2fs_warn(sbi, "compression algorithm is successfully set, " + "but current kernel doesn't support this algorithm."); + out: ++ f2fs_up_write(&F2FS_I(inode)->i_sem); + inode_unlock(inode); + file_end_write(filp); + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 719b1ba32a78b..7d2736b66c702 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -121,8 +121,8 @@ static int gc_thread_func(void *data) + else + increase_sleep_time(gc_th, &wait_ms); + do_gc: +- if (!foreground) +- stat_inc_bggc_count(sbi->stat_info); ++ stat_inc_gc_call_count(sbi, foreground ? ++ FOREGROUND : BACKGROUND); + + sync_mode = F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC; + +@@ -1685,6 +1685,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + int seg_freed = 0, migrated = 0; + unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? + SUM_TYPE_DATA : SUM_TYPE_NODE; ++ unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE; + int submitted = 0; + + if (__is_large_section(sbi)) +@@ -1766,7 +1767,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + segno, gc_type, + force_migrate); + +- stat_inc_seg_count(sbi, type, gc_type); ++ stat_inc_gc_seg_count(sbi, data_type, gc_type); + sbi->gc_reclaimed_segs[sbi->gc_mode]++; + migrated++; + +@@ -1783,12 +1784,12 @@ skip: + } + + if (submitted) +- f2fs_submit_merged_write(sbi, +- (type == SUM_TYPE_NODE) ? NODE : DATA); ++ f2fs_submit_merged_write(sbi, data_type); + + blk_finish_plug(&plug); + +- stat_inc_call_count(sbi->stat_info); ++ if (migrated) ++ stat_inc_gc_sec_count(sbi, data_type, gc_type); + + return seg_freed; + } +@@ -1839,6 +1840,7 @@ gc_more: + * secure free segments which doesn't need fggc any more. + */ + if (prefree_segments(sbi)) { ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + ret = f2fs_write_checkpoint(sbi, &cpc); + if (ret) + goto stop; +@@ -1883,6 +1885,7 @@ retry: + round++; + if (skipped_round > MAX_SKIP_GC_COUNT && + skipped_round * 2 >= round) { ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + ret = f2fs_write_checkpoint(sbi, &cpc); + goto stop; + } +@@ -1898,6 +1901,7 @@ retry: + */ + if (free_sections(sbi) <= upper_secs + NR_GC_CHECKPOINT_SECS && + prefree_segments(sbi)) { ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + ret = f2fs_write_checkpoint(sbi, &cpc); + if (ret) + goto stop; +@@ -2023,6 +2027,7 @@ static int free_segment_range(struct f2fs_sb_info *sbi, + if (gc_only) + goto out; + ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + err = f2fs_write_checkpoint(sbi, &cpc); + if (err) + goto out; +@@ -2215,6 +2220,7 @@ out_drop_write: + clear_sbi_flag(sbi, SBI_IS_RESIZEFS); + set_sbi_flag(sbi, SBI_IS_DIRTY); + ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + err = f2fs_write_checkpoint(sbi, &cpc); + if (err) { + update_fs_metadata(sbi, secs); +diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c +index cf4327ad106c0..a99c151e3bdcf 100644 +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -396,6 +396,12 @@ static int do_read_inode(struct inode *inode) + fi->i_inline_xattr_size = 0; + } + ++ if (!sanity_check_inode(inode, node_page)) { ++ f2fs_put_page(node_page, 1); ++ f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); ++ return -EFSCORRUPTED; ++ } ++ + /* check data exist */ + if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) + __recover_inline_status(inode, node_page); +@@ -465,12 +471,6 @@ static int do_read_inode(struct inode *inode) + f2fs_init_read_extent_tree(inode, node_page); + f2fs_init_age_extent_tree(inode); + +- if (!sanity_check_inode(inode, node_page)) { +- f2fs_put_page(node_page, 1); +- f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); +- return -EFSCORRUPTED; +- } +- + if (!sanity_check_extent_cache(inode)) { + f2fs_put_page(node_page, 1); + f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); +diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c +index 58c1a0096f7de..5b632d2641d49 100644 +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -895,6 +895,7 @@ skip: + struct cp_control cpc = { + .reason = CP_RECOVERY, + }; ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + err = f2fs_write_checkpoint(sbi, &cpc); + } + } +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 6db410f1bb8ce..37196d7a9685c 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -433,6 +433,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) + .err_gc_skipped = false, + .nr_free_secs = 1 }; + f2fs_down_write(&sbi->gc_lock); ++ stat_inc_gc_call_count(sbi, FOREGROUND); + f2fs_gc(sbi, &gc_control); + } + } +@@ -510,8 +511,8 @@ do_sync: + + mutex_unlock(&sbi->flush_lock); + } ++ stat_inc_cp_call_count(sbi, BACKGROUND); + f2fs_sync_fs(sbi->sb, 1); +- stat_inc_bg_cp_count(sbi->stat_info); + } + + static int __submit_flush_wait(struct f2fs_sb_info *sbi, +@@ -3150,6 +3151,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) + goto out; + + f2fs_down_write(&sbi->gc_lock); ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + err = f2fs_write_checkpoint(sbi, &cpc); + f2fs_up_write(&sbi->gc_lock); + if (err) +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 3d91b5313947f..a6f283d34cd49 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -860,11 +860,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) + if (!name) + return -ENOMEM; + if (!strcmp(name, "adaptive")) { +- if (f2fs_sb_has_blkzoned(sbi)) { +- f2fs_warn(sbi, "adaptive mode is not allowed with zoned block device feature"); +- kfree(name); +- return -EINVAL; +- } + F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; + } else if (!strcmp(name, "lfs")) { + F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; +@@ -1329,6 +1324,11 @@ default_check: + F2FS_OPTION(sbi).discard_unit = + DISCARD_UNIT_SECTION; + } ++ ++ if (F2FS_OPTION(sbi).fs_mode != FS_MODE_LFS) { ++ f2fs_info(sbi, "Only lfs mode is allowed with zoned block device feature"); ++ return -EINVAL; ++ } + #else + f2fs_err(sbi, "Zoned block device support is not enabled"); + return -EINVAL; +@@ -1571,6 +1571,7 @@ static void f2fs_put_super(struct super_block *sb) + { + struct f2fs_sb_info *sbi = F2FS_SB(sb); + int i; ++ int err = 0; + bool done; + + /* unregister procfs/sysfs entries in advance to avoid race case */ +@@ -1597,7 +1598,8 @@ static void f2fs_put_super(struct super_block *sb) + struct cp_control cpc = { + .reason = CP_UMOUNT, + }; +- f2fs_write_checkpoint(sbi, &cpc); ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); ++ err = f2fs_write_checkpoint(sbi, &cpc); + } + + /* be sure to wait for any on-going discard commands */ +@@ -1606,7 +1608,8 @@ static void f2fs_put_super(struct super_block *sb) + struct cp_control cpc = { + .reason = CP_UMOUNT | CP_TRIMMED, + }; +- f2fs_write_checkpoint(sbi, &cpc); ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); ++ err = f2fs_write_checkpoint(sbi, &cpc); + } + + /* +@@ -1623,6 +1626,19 @@ static void f2fs_put_super(struct super_block *sb) + + f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); + ++ if (err) { ++ truncate_inode_pages_final(NODE_MAPPING(sbi)); ++ truncate_inode_pages_final(META_MAPPING(sbi)); ++ } ++ ++ for (i = 0; i < NR_COUNT_TYPE; i++) { ++ if (!get_pages(sbi, i)) ++ continue; ++ f2fs_err(sbi, "detect filesystem reference count leak during " ++ "umount, type: %d, count: %lld", i, get_pages(sbi, i)); ++ f2fs_bug_on(sbi, 1); ++ } ++ + f2fs_bug_on(sbi, sbi->fsync_node_num); + + f2fs_destroy_compress_inode(sbi); +@@ -1689,8 +1705,10 @@ int f2fs_sync_fs(struct super_block *sb, int sync) + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + return -EAGAIN; + +- if (sync) ++ if (sync) { ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + err = f2fs_issue_checkpoint(sbi); ++ } + + return err; + } +@@ -2189,6 +2207,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) + .nr_free_secs = 1 }; + + f2fs_down_write(&sbi->gc_lock); ++ stat_inc_gc_call_count(sbi, FOREGROUND); + err = f2fs_gc(sbi, &gc_control); + if (err == -ENODATA) { + err = 0; +@@ -2214,6 +2233,7 @@ skip_gc: + f2fs_down_write(&sbi->gc_lock); + cpc.reason = CP_PAUSE; + set_sbi_flag(sbi, SBI_CP_DISABLED); ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + err = f2fs_write_checkpoint(sbi, &cpc); + if (err) + goto out_unlock; +@@ -4833,6 +4853,7 @@ static void kill_f2fs_super(struct super_block *sb) + struct cp_control cpc = { + .reason = CP_UMOUNT, + }; ++ stat_inc_cp_call_count(sbi, TOTAL_CALL); + f2fs_write_checkpoint(sbi, &cpc); + } + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 8ea05340bad90..8e18c2d742ca9 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -356,6 +356,16 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + if (!strcmp(a->attr.name, "revoked_atomic_block")) + return sysfs_emit(buf, "%llu\n", sbi->revoked_atomic_block); + ++#ifdef CONFIG_F2FS_STAT_FS ++ if (!strcmp(a->attr.name, "cp_foreground_calls")) ++ return sysfs_emit(buf, "%d\n", ++ atomic_read(&sbi->cp_call_count[TOTAL_CALL]) - ++ atomic_read(&sbi->cp_call_count[BACKGROUND])); ++ if (!strcmp(a->attr.name, "cp_background_calls")) ++ return sysfs_emit(buf, "%d\n", ++ atomic_read(&sbi->cp_call_count[BACKGROUND])); ++#endif ++ + ui = (unsigned int *)(ptr + a->offset); + + return sysfs_emit(buf, "%u\n", *ui); +@@ -842,68 +852,160 @@ static struct f2fs_attr f2fs_attr_##_name = { \ + #define F2FS_GENERAL_RO_ATTR(name) \ + static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) + +-#define F2FS_STAT_ATTR(_struct_type, _struct_name, _name, _elname) \ +-static struct f2fs_attr f2fs_attr_##_name = { \ +- .attr = {.name = __stringify(_name), .mode = 0444 }, \ +- .show = f2fs_sbi_show, \ +- .struct_type = _struct_type, \ +- .offset = offsetof(struct _struct_name, _elname), \ +-} ++#ifdef CONFIG_F2FS_STAT_FS ++#define STAT_INFO_RO_ATTR(name, elname) \ ++ F2FS_RO_ATTR(STAT_INFO, f2fs_stat_info, name, elname) ++#endif + +-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time, +- urgent_sleep_time); +-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); +-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); +-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_request, max_discard_request); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, min_discard_issue_time, min_discard_issue_time); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, mid_discard_issue_time, mid_discard_issue_time); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_issue_time, max_discard_issue_time); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_io_aware_gran, discard_io_aware_gran); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_urgent_util, discard_urgent_util); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity); +-F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_ordered_discard, max_ordered_discard); +-F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_seq_blocks, min_seq_blocks); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks); +-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections); +-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); +-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); +-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio); +-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, max_roll_forward_node_blocks, max_rf_node_blocks); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, migration_granularity, migration_granularity); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, discard_idle_interval, +- interval_time[DISCARD_TIME]); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle_interval, interval_time[GC_TIME]); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, +- umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]); +-#ifdef CONFIG_F2FS_IOSTAT +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_period_ms, iostat_period_ms); ++#define GC_THREAD_RW_ATTR(name, elname) \ ++ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, name, elname) ++ ++#define SM_INFO_RW_ATTR(name, elname) \ ++ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, name, elname) ++ ++#define SM_INFO_GENERAL_RW_ATTR(elname) \ ++ SM_INFO_RW_ATTR(elname, elname) ++ ++#define DCC_INFO_RW_ATTR(name, elname) \ ++ F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, name, elname) ++ ++#define DCC_INFO_GENERAL_RW_ATTR(elname) \ ++ DCC_INFO_RW_ATTR(elname, elname) ++ ++#define NM_INFO_RW_ATTR(name, elname) \ ++ F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, name, elname) ++ ++#define NM_INFO_GENERAL_RW_ATTR(elname) \ ++ NM_INFO_RW_ATTR(elname, elname) ++ ++#define F2FS_SBI_RW_ATTR(name, elname) \ ++ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, name, elname) ++ ++#define F2FS_SBI_GENERAL_RW_ATTR(elname) \ ++ F2FS_SBI_RW_ATTR(elname, elname) ++ ++#define F2FS_SBI_GENERAL_RO_ATTR(elname) \ ++ F2FS_RO_ATTR(F2FS_SBI, f2fs_sb_info, elname, elname) ++ ++#ifdef CONFIG_F2FS_FAULT_INJECTION ++#define FAULT_INFO_GENERAL_RW_ATTR(type, elname) \ ++ F2FS_RW_ATTR(type, f2fs_fault_info, elname, elname) + #endif +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_io_bytes, max_io_bytes); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); ++ ++#define RESERVED_BLOCKS_GENERAL_RW_ATTR(elname) \ ++ F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, elname, elname) ++ ++#define CPRC_INFO_GENERAL_RW_ATTR(elname) \ ++ F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, elname, elname) ++ ++#define ATGC_INFO_RW_ATTR(name, elname) \ ++ F2FS_RW_ATTR(ATGC_INFO, atgc_management, name, elname) ++ ++/* GC_THREAD ATTR */ ++GC_THREAD_RW_ATTR(gc_urgent_sleep_time, urgent_sleep_time); ++GC_THREAD_RW_ATTR(gc_min_sleep_time, min_sleep_time); ++GC_THREAD_RW_ATTR(gc_max_sleep_time, max_sleep_time); ++GC_THREAD_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time); ++ ++/* SM_INFO ATTR */ ++SM_INFO_RW_ATTR(reclaim_segments, rec_prefree_segments); ++SM_INFO_GENERAL_RW_ATTR(ipu_policy); ++SM_INFO_GENERAL_RW_ATTR(min_ipu_util); ++SM_INFO_GENERAL_RW_ATTR(min_fsync_blocks); ++SM_INFO_GENERAL_RW_ATTR(min_seq_blocks); ++SM_INFO_GENERAL_RW_ATTR(min_hot_blocks); ++SM_INFO_GENERAL_RW_ATTR(min_ssr_sections); ++ ++/* DCC_INFO ATTR */ ++DCC_INFO_RW_ATTR(max_small_discards, max_discards); ++DCC_INFO_GENERAL_RW_ATTR(max_discard_request); ++DCC_INFO_GENERAL_RW_ATTR(min_discard_issue_time); ++DCC_INFO_GENERAL_RW_ATTR(mid_discard_issue_time); ++DCC_INFO_GENERAL_RW_ATTR(max_discard_issue_time); ++DCC_INFO_GENERAL_RW_ATTR(discard_io_aware_gran); ++DCC_INFO_GENERAL_RW_ATTR(discard_urgent_util); ++DCC_INFO_GENERAL_RW_ATTR(discard_granularity); ++DCC_INFO_GENERAL_RW_ATTR(max_ordered_discard); ++ ++/* NM_INFO ATTR */ ++NM_INFO_RW_ATTR(max_roll_forward_node_blocks, max_rf_node_blocks); ++NM_INFO_GENERAL_RW_ATTR(ram_thresh); ++NM_INFO_GENERAL_RW_ATTR(ra_nid_pages); ++NM_INFO_GENERAL_RW_ATTR(dirty_nats_ratio); ++ ++/* F2FS_SBI ATTR */ + F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); ++F2FS_SBI_RW_ATTR(gc_idle, gc_mode); ++F2FS_SBI_RW_ATTR(gc_urgent, gc_mode); ++F2FS_SBI_RW_ATTR(cp_interval, interval_time[CP_TIME]); ++F2FS_SBI_RW_ATTR(idle_interval, interval_time[REQ_TIME]); ++F2FS_SBI_RW_ATTR(discard_idle_interval, interval_time[DISCARD_TIME]); ++F2FS_SBI_RW_ATTR(gc_idle_interval, interval_time[GC_TIME]); ++F2FS_SBI_RW_ATTR(umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]); ++F2FS_SBI_RW_ATTR(gc_pin_file_thresh, gc_pin_file_threshold); ++F2FS_SBI_RW_ATTR(gc_reclaimed_segments, gc_reclaimed_segs); ++F2FS_SBI_GENERAL_RW_ATTR(max_victim_search); ++F2FS_SBI_GENERAL_RW_ATTR(migration_granularity); ++F2FS_SBI_GENERAL_RW_ATTR(dir_level); ++#ifdef CONFIG_F2FS_IOSTAT ++F2FS_SBI_GENERAL_RW_ATTR(iostat_enable); ++F2FS_SBI_GENERAL_RW_ATTR(iostat_period_ms); ++#endif ++F2FS_SBI_GENERAL_RW_ATTR(readdir_ra); ++F2FS_SBI_GENERAL_RW_ATTR(max_io_bytes); ++F2FS_SBI_GENERAL_RW_ATTR(data_io_flag); ++F2FS_SBI_GENERAL_RW_ATTR(node_io_flag); ++F2FS_SBI_GENERAL_RW_ATTR(gc_remaining_trials); ++F2FS_SBI_GENERAL_RW_ATTR(seq_file_ra_mul); ++F2FS_SBI_GENERAL_RW_ATTR(gc_segment_mode); ++F2FS_SBI_GENERAL_RW_ATTR(max_fragment_chunk); ++F2FS_SBI_GENERAL_RW_ATTR(max_fragment_hole); ++#ifdef CONFIG_F2FS_FS_COMPRESSION ++F2FS_SBI_GENERAL_RW_ATTR(compr_written_block); ++F2FS_SBI_GENERAL_RW_ATTR(compr_saved_block); ++F2FS_SBI_GENERAL_RW_ATTR(compr_new_inode); ++F2FS_SBI_GENERAL_RW_ATTR(compress_percent); ++F2FS_SBI_GENERAL_RW_ATTR(compress_watermark); ++#endif ++/* atomic write */ ++F2FS_SBI_GENERAL_RO_ATTR(current_atomic_write); ++F2FS_SBI_GENERAL_RW_ATTR(peak_atomic_write); ++F2FS_SBI_GENERAL_RW_ATTR(committed_atomic_block); ++F2FS_SBI_GENERAL_RW_ATTR(revoked_atomic_block); ++/* block age extent cache */ ++F2FS_SBI_GENERAL_RW_ATTR(hot_data_age_threshold); ++F2FS_SBI_GENERAL_RW_ATTR(warm_data_age_threshold); ++F2FS_SBI_GENERAL_RW_ATTR(last_age_weight); ++#ifdef CONFIG_BLK_DEV_ZONED ++F2FS_SBI_GENERAL_RO_ATTR(unusable_blocks_per_sec); ++#endif ++ ++/* STAT_INFO ATTR */ ++#ifdef CONFIG_F2FS_STAT_FS ++STAT_INFO_RO_ATTR(cp_foreground_calls, cp_call_count[FOREGROUND]); ++STAT_INFO_RO_ATTR(cp_background_calls, cp_call_count[BACKGROUND]); ++STAT_INFO_RO_ATTR(gc_foreground_calls, gc_call_count[FOREGROUND]); ++STAT_INFO_RO_ATTR(gc_background_calls, gc_call_count[BACKGROUND]); ++#endif ++ ++/* FAULT_INFO ATTR */ + #ifdef CONFIG_F2FS_FAULT_INJECTION +-F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); +-F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); ++FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_RATE, inject_rate); ++FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_TYPE, inject_type); + #endif +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, node_io_flag, node_io_flag); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_remaining_trials, gc_remaining_trials); +-F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, ckpt_thread_ioprio, ckpt_thread_ioprio); ++ ++/* RESERVED_BLOCKS ATTR */ ++RESERVED_BLOCKS_GENERAL_RW_ATTR(reserved_blocks); ++ ++/* CPRC_INFO ATTR */ ++CPRC_INFO_GENERAL_RW_ATTR(ckpt_thread_ioprio); ++ ++/* ATGC_INFO ATTR */ ++ATGC_INFO_RW_ATTR(atgc_candidate_ratio, candidate_ratio); ++ATGC_INFO_RW_ATTR(atgc_candidate_count, max_candidate_count); ++ATGC_INFO_RW_ATTR(atgc_age_weight, age_weight); ++ATGC_INFO_RW_ATTR(atgc_age_threshold, age_threshold); ++ + F2FS_GENERAL_RO_ATTR(dirty_segments); + F2FS_GENERAL_RO_ATTR(free_segments); + F2FS_GENERAL_RO_ATTR(ovp_segments); +@@ -917,10 +1019,6 @@ F2FS_GENERAL_RO_ATTR(main_blkaddr); + F2FS_GENERAL_RO_ATTR(pending_discard); + F2FS_GENERAL_RO_ATTR(gc_mode); + #ifdef CONFIG_F2FS_STAT_FS +-F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_foreground_calls, cp_count); +-F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_background_calls, bg_cp_count); +-F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, gc_foreground_calls, call_count); +-F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, gc_background_calls, bg_gc); + F2FS_GENERAL_RO_ATTR(moved_blocks_background); + F2FS_GENERAL_RO_ATTR(moved_blocks_foreground); + F2FS_GENERAL_RO_ATTR(avg_vblocks); +@@ -935,8 +1033,6 @@ F2FS_FEATURE_RO_ATTR(encrypted_casefold); + #endif /* CONFIG_FS_ENCRYPTION */ + #ifdef CONFIG_BLK_DEV_ZONED + F2FS_FEATURE_RO_ATTR(block_zoned); +-F2FS_RO_ATTR(F2FS_SBI, f2fs_sb_info, unusable_blocks_per_sec, +- unusable_blocks_per_sec); + #endif + F2FS_FEATURE_RO_ATTR(atomic_write); + F2FS_FEATURE_RO_ATTR(extra_attr); +@@ -956,37 +1052,9 @@ F2FS_FEATURE_RO_ATTR(casefold); + F2FS_FEATURE_RO_ATTR(readonly); + #ifdef CONFIG_F2FS_FS_COMPRESSION + F2FS_FEATURE_RO_ATTR(compression); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_written_block, compr_written_block); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_saved_block, compr_saved_block); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_new_inode, compr_new_inode); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compress_percent, compress_percent); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compress_watermark, compress_watermark); + #endif + F2FS_FEATURE_RO_ATTR(pin_file); + +-/* For ATGC */ +-F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_ratio, candidate_ratio); +-F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_count, max_candidate_count); +-F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_weight, age_weight); +-F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_threshold, age_threshold); +- +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, seq_file_ra_mul, seq_file_ra_mul); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_segment_mode, gc_segment_mode); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_reclaimed_segments, gc_reclaimed_segs); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_fragment_chunk, max_fragment_chunk); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_fragment_hole, max_fragment_hole); +- +-/* For atomic write */ +-F2FS_RO_ATTR(F2FS_SBI, f2fs_sb_info, current_atomic_write, current_atomic_write); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, peak_atomic_write, peak_atomic_write); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, committed_atomic_block, committed_atomic_block); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, revoked_atomic_block, revoked_atomic_block); +- +-/* For block age extent cache */ +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, hot_data_age_threshold, hot_data_age_threshold); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, warm_data_age_threshold, warm_data_age_threshold); +-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, last_age_weight, last_age_weight); +- + #define ATTR_LIST(name) (&f2fs_attr_##name.attr) + static struct attribute *f2fs_attrs[] = { + ATTR_LIST(gc_urgent_sleep_time), +diff --git a/fs/fs_context.c b/fs/fs_context.c +index 851214d1d013d..375023e40161d 100644 +--- a/fs/fs_context.c ++++ b/fs/fs_context.c +@@ -315,10 +315,31 @@ struct fs_context *fs_context_for_reconfigure(struct dentry *dentry, + } + EXPORT_SYMBOL(fs_context_for_reconfigure); + ++/** ++ * fs_context_for_submount: allocate a new fs_context for a submount ++ * @type: file_system_type of the new context ++ * @reference: reference dentry from which to copy relevant info ++ * ++ * Allocate a new fs_context suitable for a submount. This also ensures that ++ * the fc->security object is inherited from @reference (if needed). ++ */ + struct fs_context *fs_context_for_submount(struct file_system_type *type, + struct dentry *reference) + { +- return alloc_fs_context(type, reference, 0, 0, FS_CONTEXT_FOR_SUBMOUNT); ++ struct fs_context *fc; ++ int ret; ++ ++ fc = alloc_fs_context(type, reference, 0, 0, FS_CONTEXT_FOR_SUBMOUNT); ++ if (IS_ERR(fc)) ++ return fc; ++ ++ ret = security_fs_context_submount(fc, reference->d_sb); ++ if (ret) { ++ put_fs_context(fc); ++ return ERR_PTR(ret); ++ } ++ ++ return fc; + } + EXPORT_SYMBOL(fs_context_for_submount); + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 89d97f6188e05..acee575f9dc8b 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -19,7 +19,6 @@ + #include <linux/uio.h> + #include <linux/fs.h> + #include <linux/filelock.h> +-#include <linux/file.h> + + static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, + unsigned int open_flags, int opcode, +@@ -479,36 +478,48 @@ static void fuse_sync_writes(struct inode *inode) + fuse_release_nowrite(inode); + } + +-struct fuse_flush_args { +- struct fuse_args args; +- struct fuse_flush_in inarg; +- struct work_struct work; +- struct file *file; +-}; +- +-static int fuse_do_flush(struct fuse_flush_args *fa) ++static int fuse_flush(struct file *file, fl_owner_t id) + { +- int err; +- struct inode *inode = file_inode(fa->file); ++ struct inode *inode = file_inode(file); + struct fuse_mount *fm = get_fuse_mount(inode); ++ struct fuse_file *ff = file->private_data; ++ struct fuse_flush_in inarg; ++ FUSE_ARGS(args); ++ int err; ++ ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ ++ if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) ++ return 0; + + err = write_inode_now(inode, 1); + if (err) +- goto out; ++ return err; + + inode_lock(inode); + fuse_sync_writes(inode); + inode_unlock(inode); + +- err = filemap_check_errors(fa->file->f_mapping); ++ err = filemap_check_errors(file->f_mapping); + if (err) +- goto out; ++ return err; + + err = 0; + if (fm->fc->no_flush) + goto inval_attr_out; + +- err = fuse_simple_request(fm, &fa->args); ++ memset(&inarg, 0, sizeof(inarg)); ++ inarg.fh = ff->fh; ++ inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); ++ args.opcode = FUSE_FLUSH; ++ args.nodeid = get_node_id(inode); ++ args.in_numargs = 1; ++ args.in_args[0].size = sizeof(inarg); ++ args.in_args[0].value = &inarg; ++ args.force = true; ++ ++ err = fuse_simple_request(fm, &args); + if (err == -ENOSYS) { + fm->fc->no_flush = 1; + err = 0; +@@ -521,57 +532,9 @@ inval_attr_out: + */ + if (!err && fm->fc->writeback_cache) + fuse_invalidate_attr_mask(inode, STATX_BLOCKS); +- +-out: +- fput(fa->file); +- kfree(fa); + return err; + } + +-static void fuse_flush_async(struct work_struct *work) +-{ +- struct fuse_flush_args *fa = container_of(work, typeof(*fa), work); +- +- fuse_do_flush(fa); +-} +- +-static int fuse_flush(struct file *file, fl_owner_t id) +-{ +- struct fuse_flush_args *fa; +- struct inode *inode = file_inode(file); +- struct fuse_mount *fm = get_fuse_mount(inode); +- struct fuse_file *ff = file->private_data; +- +- if (fuse_is_bad(inode)) +- return -EIO; +- +- if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) +- return 0; +- +- fa = kzalloc(sizeof(*fa), GFP_KERNEL); +- if (!fa) +- return -ENOMEM; +- +- fa->inarg.fh = ff->fh; +- fa->inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); +- fa->args.opcode = FUSE_FLUSH; +- fa->args.nodeid = get_node_id(inode); +- fa->args.in_numargs = 1; +- fa->args.in_args[0].size = sizeof(fa->inarg); +- fa->args.in_args[0].value = &fa->inarg; +- fa->args.force = true; +- fa->file = get_file(file); +- +- /* Don't wait if the task is exiting */ +- if (current->flags & PF_EXITING) { +- INIT_WORK(&fa->work, fuse_flush_async); +- schedule_work(&fa->work); +- return 0; +- } +- +- return fuse_do_flush(fa); +-} +- + int fuse_fsync_common(struct file *file, loff_t start, loff_t end, + int datasync, int opcode) + { +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index 063133ec77f49..08ee293c4117c 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -508,11 +508,6 @@ void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len) + WARN_ON_ONCE(folio_test_writeback(folio)); + folio_cancel_dirty(folio); + iomap_page_release(folio); +- } else if (folio_test_large(folio)) { +- /* Must release the iop so the page can be split */ +- WARN_ON_ONCE(!folio_test_uptodate(folio) && +- folio_test_dirty(folio)); +- iomap_page_release(folio); + } + } + EXPORT_SYMBOL_GPL(iomap_invalidate_folio); +diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c +index ae99a7e232eeb..a82751e6c47f9 100644 +--- a/fs/jfs/jfs_extent.c ++++ b/fs/jfs/jfs_extent.c +@@ -311,6 +311,11 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) + * blocks in the map. in that case, we'll start off with the + * maximum free. + */ ++ ++ /* give up if no space left */ ++ if (bmp->db_maxfreebud == -1) ++ return -ENOSPC; ++ + max = (s64) 1 << bmp->db_maxfreebud; + if (*nblocks >= max && *nblocks > nbperpage) + nb = nblks = (max > nbperpage) ? max : nbperpage; +diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c +index 1d9488cf05348..87a0f207df0b9 100644 +--- a/fs/lockd/mon.c ++++ b/fs/lockd/mon.c +@@ -276,6 +276,9 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, + { + struct nsm_handle *new; + ++ if (!hostname) ++ return NULL; ++ + new = kzalloc(sizeof(*new) + hostname_len + 1, GFP_KERNEL); + if (unlikely(new == NULL)) + return NULL; +diff --git a/fs/namei.c b/fs/namei.c +index 7e5cb92feab3f..e18c8c9f1d9c6 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2890,7 +2890,7 @@ int path_pts(struct path *path) + dput(path->dentry); + path->dentry = parent; + child = d_hash_and_lookup(parent, &this); +- if (!child) ++ if (IS_ERR_OR_NULL(child)) + return -ENOENT; + + path->dentry = child; +diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c +index fea5f8821da5e..ce2ea62397972 100644 +--- a/fs/nfs/blocklayout/dev.c ++++ b/fs/nfs/blocklayout/dev.c +@@ -402,7 +402,7 @@ bl_parse_concat(struct nfs_server *server, struct pnfs_block_dev *d, + int ret, i; + + d->children = kcalloc(v->concat.volumes_count, +- sizeof(struct pnfs_block_dev), GFP_KERNEL); ++ sizeof(struct pnfs_block_dev), gfp_mask); + if (!d->children) + return -ENOMEM; + +@@ -431,7 +431,7 @@ bl_parse_stripe(struct nfs_server *server, struct pnfs_block_dev *d, + int ret, i; + + d->children = kcalloc(v->stripe.volumes_count, +- sizeof(struct pnfs_block_dev), GFP_KERNEL); ++ sizeof(struct pnfs_block_dev), gfp_mask); + if (!d->children) + return -ENOMEM; + +diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h +index 3cc027d3bd588..1607c23f68d41 100644 +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -489,6 +489,7 @@ extern const struct nfs_pgio_completion_ops nfs_async_read_completion_ops; + extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, + struct inode *inode, bool force_mds, + const struct nfs_pgio_completion_ops *compl_ops); ++extern bool nfs_read_alloc_scratch(struct nfs_pgio_header *hdr, size_t size); + extern int nfs_read_add_folio(struct nfs_pageio_descriptor *pgio, + struct nfs_open_context *ctx, + struct folio *folio); +diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c +index 05c3b4b2b3dd8..c190938142960 100644 +--- a/fs/nfs/nfs2xdr.c ++++ b/fs/nfs/nfs2xdr.c +@@ -949,7 +949,7 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, + + error = decode_filename_inline(xdr, &entry->name, &entry->len); + if (unlikely(error)) +- return -EAGAIN; ++ return error == -ENAMETOOLONG ? -ENAMETOOLONG : -EAGAIN; + + /* + * The type (size and byte order) of nfscookie isn't defined in +diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c +index 3b0b650c9c5ab..60f032be805ae 100644 +--- a/fs/nfs/nfs3xdr.c ++++ b/fs/nfs/nfs3xdr.c +@@ -1991,7 +1991,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, + + error = decode_inline_filename3(xdr, &entry->name, &entry->len); + if (unlikely(error)) +- return -EAGAIN; ++ return error == -ENAMETOOLONG ? -ENAMETOOLONG : -EAGAIN; + + error = decode_cookie3(xdr, &new_cookie); + if (unlikely(error)) +diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h +index 0fe5aacbcfdf1..b59876b01a1e3 100644 +--- a/fs/nfs/nfs42.h ++++ b/fs/nfs/nfs42.h +@@ -13,6 +13,7 @@ + * more? Need to consider not to pre-alloc too much for a compound. + */ + #define PNFS_LAYOUTSTATS_MAXDEV (4) ++#define READ_PLUS_SCRATCH_SIZE (16) + + /* nfs4.2proc.c */ + #ifdef CONFIG_NFS_V4_2 +diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c +index 5d7e0511f3513..d5ec3d5568da5 100644 +--- a/fs/nfs/nfs42proc.c ++++ b/fs/nfs/nfs42proc.c +@@ -471,8 +471,9 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, + continue; + } + break; +- } else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) { +- args.sync = true; ++ } else if (err == -NFS4ERR_OFFLOAD_NO_REQS && ++ args.sync != res.synchronous) { ++ args.sync = res.synchronous; + dst_exception.retry = 1; + continue; + } else if ((err == -ESTALE || +diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c +index a6df815a140c7..20aa5e746497d 100644 +--- a/fs/nfs/nfs42xdr.c ++++ b/fs/nfs/nfs42xdr.c +@@ -51,10 +51,16 @@ + (1 /* data_content4 */ + \ + 2 /* data_info4.di_offset */ + \ + 1 /* data_info4.di_length */) ++#define NFS42_READ_PLUS_HOLE_SEGMENT_SIZE \ ++ (1 /* data_content4 */ + \ ++ 2 /* data_info4.di_offset */ + \ ++ 2 /* data_info4.di_length */) ++#define READ_PLUS_SEGMENT_SIZE_DIFF (NFS42_READ_PLUS_HOLE_SEGMENT_SIZE - \ ++ NFS42_READ_PLUS_DATA_SEGMENT_SIZE) + #define decode_read_plus_maxsz (op_decode_hdr_maxsz + \ + 1 /* rpr_eof */ + \ + 1 /* rpr_contents count */ + \ +- NFS42_READ_PLUS_DATA_SEGMENT_SIZE) ++ NFS42_READ_PLUS_HOLE_SEGMENT_SIZE) + #define encode_seek_maxsz (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + \ + 2 /* offset */ + \ +@@ -781,8 +787,8 @@ static void nfs4_xdr_enc_read_plus(struct rpc_rqst *req, + encode_putfh(xdr, args->fh, &hdr); + encode_read_plus(xdr, args, &hdr); + +- rpc_prepare_reply_pages(req, args->pages, args->pgbase, +- args->count, hdr.replen); ++ rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->count, ++ hdr.replen - READ_PLUS_SEGMENT_SIZE_DIFF); + encode_nops(&hdr); + } + +@@ -1136,13 +1142,12 @@ static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res) + res->eof = be32_to_cpup(p++); + segments = be32_to_cpup(p++); + if (segments == 0) +- return status; ++ return 0; + + segs = kmalloc_array(segments, sizeof(*segs), GFP_KERNEL); + if (!segs) + return -ENOMEM; + +- status = -EIO; + for (i = 0; i < segments; i++) { + status = decode_read_plus_segment(xdr, &segs[i]); + if (status < 0) +@@ -1346,7 +1351,7 @@ static int nfs4_xdr_dec_read_plus(struct rpc_rqst *rqstp, + struct compound_hdr hdr; + int status; + +- xdr_set_scratch_buffer(xdr, res->scratch, sizeof(res->scratch)); ++ xdr_set_scratch_buffer(xdr, res->scratch, READ_PLUS_SCRATCH_SIZE); + + status = decode_compound_hdr(xdr, &hdr); + if (status) +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index fd752e0c4ec24..43d458965330f 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -5438,18 +5438,8 @@ static bool nfs4_read_plus_not_supported(struct rpc_task *task, + return false; + } + +-static inline void nfs4_read_plus_scratch_free(struct nfs_pgio_header *hdr) +-{ +- if (hdr->res.scratch) { +- kfree(hdr->res.scratch); +- hdr->res.scratch = NULL; +- } +-} +- + static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- nfs4_read_plus_scratch_free(hdr); +- + if (!nfs4_sequence_done(task, &hdr->res.seq_res)) + return -EAGAIN; + if (nfs4_read_stateid_changed(task, &hdr->args)) +@@ -5469,8 +5459,7 @@ static bool nfs42_read_plus_support(struct nfs_pgio_header *hdr, + /* Note: We don't use READ_PLUS with pNFS yet */ + if (nfs_server_capable(hdr->inode, NFS_CAP_READ_PLUS) && !hdr->ds_clp) { + msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ_PLUS]; +- hdr->res.scratch = kmalloc(32, GFP_KERNEL); +- return hdr->res.scratch != NULL; ++ return nfs_read_alloc_scratch(hdr, READ_PLUS_SCRATCH_SIZE); + } + return false; + } +diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c +index a0112ad4937aa..2e14ce2f82191 100644 +--- a/fs/nfs/pnfs_nfs.c ++++ b/fs/nfs/pnfs_nfs.c +@@ -943,7 +943,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, + * Test this address for session trunking and + * add as an alias + */ +- xprtdata.cred = nfs4_get_clid_cred(clp), ++ xprtdata.cred = nfs4_get_clid_cred(clp); + rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args, + rpc_clnt_setup_test_and_add_xprt, + &rpcdata); +diff --git a/fs/nfs/read.c b/fs/nfs/read.c +index f71eeee67e201..7dc21a48e3e7b 100644 +--- a/fs/nfs/read.c ++++ b/fs/nfs/read.c +@@ -47,6 +47,8 @@ static struct nfs_pgio_header *nfs_readhdr_alloc(void) + + static void nfs_readhdr_free(struct nfs_pgio_header *rhdr) + { ++ if (rhdr->res.scratch != NULL) ++ kfree(rhdr->res.scratch); + kmem_cache_free(nfs_rdata_cachep, rhdr); + } + +@@ -108,6 +110,14 @@ void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) + } + EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); + ++bool nfs_read_alloc_scratch(struct nfs_pgio_header *hdr, size_t size) ++{ ++ WARN_ON(hdr->res.scratch != NULL); ++ hdr->res.scratch = kmalloc(size, GFP_KERNEL); ++ return hdr->res.scratch != NULL; ++} ++EXPORT_SYMBOL_GPL(nfs_read_alloc_scratch); ++ + static void nfs_readpage_release(struct nfs_page *req, int error) + { + struct folio *folio = nfs_page_to_folio(req); +diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c +index 8e9c1a0f8d380..1ed2f691ebb90 100644 +--- a/fs/nfsd/blocklayoutxdr.c ++++ b/fs/nfsd/blocklayoutxdr.c +@@ -83,6 +83,15 @@ nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, + int len = sizeof(__be32), ret, i; + __be32 *p; + ++ /* ++ * See paragraph 5 of RFC 8881 S18.40.3. ++ */ ++ if (!gdp->gd_maxcount) { ++ if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) ++ return nfserr_resource; ++ return nfs_ok; ++ } ++ + p = xdr_reserve_space(xdr, len + sizeof(__be32)); + if (!p) + return nfserr_resource; +diff --git a/fs/nfsd/flexfilelayoutxdr.c b/fs/nfsd/flexfilelayoutxdr.c +index e81d2a5cf381e..bb205328e043d 100644 +--- a/fs/nfsd/flexfilelayoutxdr.c ++++ b/fs/nfsd/flexfilelayoutxdr.c +@@ -85,6 +85,15 @@ nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr, + int addr_len; + __be32 *p; + ++ /* ++ * See paragraph 5 of RFC 8881 S18.40.3. ++ */ ++ if (!gdp->gd_maxcount) { ++ if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) ++ return nfserr_resource; ++ return nfs_ok; ++ } ++ + /* len + padding for two strings */ + addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len; + ver_len = 20; +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index ee1a24debd60c..679d9be4abd4d 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -4681,20 +4681,17 @@ nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, + + *p++ = cpu_to_be32(gdev->gd_layout_type); + +- /* If maxcount is 0 then just update notifications */ +- if (gdev->gd_maxcount != 0) { +- ops = nfsd4_layout_ops[gdev->gd_layout_type]; +- nfserr = ops->encode_getdeviceinfo(xdr, gdev); +- if (nfserr) { +- /* +- * We don't bother to burden the layout drivers with +- * enforcing gd_maxcount, just tell the client to +- * come back with a bigger buffer if it's not enough. +- */ +- if (xdr->buf->len + 4 > gdev->gd_maxcount) +- goto toosmall; +- return nfserr; +- } ++ ops = nfsd4_layout_ops[gdev->gd_layout_type]; ++ nfserr = ops->encode_getdeviceinfo(xdr, gdev); ++ if (nfserr) { ++ /* ++ * We don't bother to burden the layout drivers with ++ * enforcing gd_maxcount, just tell the client to ++ * come back with a bigger buffer if it's not enough. ++ */ ++ if (xdr->buf->len + 4 > gdev->gd_maxcount) ++ goto toosmall; ++ return nfserr; + } + + if (gdev->gd_notify_types) { +diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c +index 52ccd34b1e792..a026dbd3593f6 100644 +--- a/fs/nls/nls_base.c ++++ b/fs/nls/nls_base.c +@@ -272,7 +272,7 @@ int unregister_nls(struct nls_table * nls) + return -EINVAL; + } + +-static struct nls_table *find_nls(char *charset) ++static struct nls_table *find_nls(const char *charset) + { + struct nls_table *nls; + spin_lock(&nls_lock); +@@ -288,7 +288,7 @@ static struct nls_table *find_nls(char *charset) + return nls; + } + +-struct nls_table *load_nls(char *charset) ++struct nls_table *load_nls(const char *charset) + { + return try_then_request_module(find_nls(charset), "nls_%s", charset); + } +diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c +index 17c52225b87d4..03bccfd183f3c 100644 +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -1535,6 +1535,10 @@ static int ocfs2_rename(struct mnt_idmap *idmap, + status = ocfs2_add_entry(handle, new_dentry, old_inode, + OCFS2_I(old_inode)->ip_blkno, + new_dir_bh, &target_insert); ++ if (status < 0) { ++ mlog_errno(status); ++ goto bail; ++ } + } + + old_inode->i_ctime = current_time(old_inode); +diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c +index ae1058fbfb5b2..8c60da7b4afd8 100644 +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -2052,7 +2052,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) + ovl_trusted_xattr_handlers; + sb->s_fs_info = ofs; + sb->s_flags |= SB_POSIXACL; +- sb->s_iflags |= SB_I_SKIP_SYNC; ++ sb->s_iflags |= SB_I_SKIP_SYNC | SB_I_IMA_UNVERIFIABLE_SIGNATURE; + + err = -ENOMEM; + root_dentry = ovl_get_root(sb, upperpath.dentry, oe); +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 05452c3b9872b..7394229816f37 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -3583,7 +3583,8 @@ static int proc_tid_comm_permission(struct mnt_idmap *idmap, + } + + static const struct inode_operations proc_tid_comm_inode_operations = { +- .permission = proc_tid_comm_permission, ++ .setattr = proc_setattr, ++ .permission = proc_tid_comm_permission, + }; + + /* +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 85aaf0fc6d7d1..eb6df190d7523 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -519,7 +519,7 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig, + sig ^= PERSISTENT_RAM_SIG; + + if (prz->buffer->sig == sig) { +- if (buffer_size(prz) == 0) { ++ if (buffer_size(prz) == 0 && buffer_start(prz) == 0) { + pr_debug("found existing empty buffer\n"); + return 0; + } +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index e3e4f40476579..c7afe433d991a 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -225,13 +225,22 @@ static void put_quota_format(struct quota_format_type *fmt) + + /* + * Dquot List Management: +- * The quota code uses four lists for dquot management: the inuse_list, +- * free_dquots, dqi_dirty_list, and dquot_hash[] array. A single dquot +- * structure may be on some of those lists, depending on its current state. ++ * The quota code uses five lists for dquot management: the inuse_list, ++ * releasing_dquots, free_dquots, dqi_dirty_list, and dquot_hash[] array. ++ * A single dquot structure may be on some of those lists, depending on ++ * its current state. + * + * All dquots are placed to the end of inuse_list when first created, and this + * list is used for invalidate operation, which must look at every dquot. + * ++ * When the last reference of a dquot will be dropped, the dquot will be ++ * added to releasing_dquots. We'd then queue work item which would call ++ * synchronize_srcu() and after that perform the final cleanup of all the ++ * dquots on the list. Both releasing_dquots and free_dquots use the ++ * dq_free list_head in the dquot struct. When a dquot is removed from ++ * releasing_dquots, a reference count is always subtracted, and if ++ * dq_count == 0 at that point, the dquot will be added to the free_dquots. ++ * + * Unused dquots (dq_count == 0) are added to the free_dquots list when freed, + * and this list is searched whenever we need an available dquot. Dquots are + * removed from the list as soon as they are used again, and +@@ -250,6 +259,7 @@ static void put_quota_format(struct quota_format_type *fmt) + + static LIST_HEAD(inuse_list); + static LIST_HEAD(free_dquots); ++static LIST_HEAD(releasing_dquots); + static unsigned int dq_hash_bits, dq_hash_mask; + static struct hlist_head *dquot_hash; + +@@ -260,6 +270,9 @@ static qsize_t inode_get_rsv_space(struct inode *inode); + static qsize_t __inode_get_rsv_space(struct inode *inode); + static int __dquot_initialize(struct inode *inode, int type); + ++static void quota_release_workfn(struct work_struct *work); ++static DECLARE_DELAYED_WORK(quota_release_work, quota_release_workfn); ++ + static inline unsigned int + hashfn(const struct super_block *sb, struct kqid qid) + { +@@ -305,12 +318,18 @@ static inline void put_dquot_last(struct dquot *dquot) + dqstats_inc(DQST_FREE_DQUOTS); + } + ++static inline void put_releasing_dquots(struct dquot *dquot) ++{ ++ list_add_tail(&dquot->dq_free, &releasing_dquots); ++} ++ + static inline void remove_free_dquot(struct dquot *dquot) + { + if (list_empty(&dquot->dq_free)) + return; + list_del_init(&dquot->dq_free); +- dqstats_dec(DQST_FREE_DQUOTS); ++ if (!atomic_read(&dquot->dq_count)) ++ dqstats_dec(DQST_FREE_DQUOTS); + } + + static inline void put_inuse(struct dquot *dquot) +@@ -336,6 +355,11 @@ static void wait_on_dquot(struct dquot *dquot) + mutex_unlock(&dquot->dq_lock); + } + ++static inline int dquot_active(struct dquot *dquot) ++{ ++ return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); ++} ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -351,14 +375,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot) + { + int ret = 1; + +- if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) ++ if (!dquot_active(dquot)) + return 0; + + if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NOLIST_DIRTY) + return test_and_set_bit(DQ_MOD_B, &dquot->dq_flags); + + /* If quota is dirty already, we don't have to acquire dq_list_lock */ +- if (test_bit(DQ_MOD_B, &dquot->dq_flags)) ++ if (dquot_dirty(dquot)) + return 1; + + spin_lock(&dq_list_lock); +@@ -440,7 +464,7 @@ int dquot_acquire(struct dquot *dquot) + smp_mb__before_atomic(); + set_bit(DQ_READ_B, &dquot->dq_flags); + /* Instantiate dquot if needed */ +- if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { ++ if (!dquot_active(dquot) && !dquot->dq_off) { + ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); + /* Write the info if needed */ + if (info_dirty(&dqopt->info[dquot->dq_id.type])) { +@@ -482,7 +506,7 @@ int dquot_commit(struct dquot *dquot) + goto out_lock; + /* Inactive dquot can be only if there was error during read/init + * => we have better not writing it */ +- if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) ++ if (dquot_active(dquot)) + ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); + else + ret = -EIO; +@@ -547,6 +571,8 @@ static void invalidate_dquots(struct super_block *sb, int type) + struct dquot *dquot, *tmp; + + restart: ++ flush_delayed_work("a_release_work); ++ + spin_lock(&dq_list_lock); + list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { + if (dquot->dq_sb != sb) +@@ -555,6 +581,12 @@ restart: + continue; + /* Wait for dquot users */ + if (atomic_read(&dquot->dq_count)) { ++ /* dquot in releasing_dquots, flush and retry */ ++ if (!list_empty(&dquot->dq_free)) { ++ spin_unlock(&dq_list_lock); ++ goto restart; ++ } ++ + atomic_inc(&dquot->dq_count); + spin_unlock(&dq_list_lock); + /* +@@ -597,7 +629,7 @@ int dquot_scan_active(struct super_block *sb, + + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, &inuse_list, dq_inuse) { +- if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) ++ if (!dquot_active(dquot)) + continue; + if (dquot->dq_sb != sb) + continue; +@@ -612,7 +644,7 @@ int dquot_scan_active(struct super_block *sb, + * outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); +- if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { ++ if (dquot_active(dquot)) { + ret = fn(dquot, priv); + if (ret < 0) + goto out; +@@ -628,6 +660,18 @@ out: + } + EXPORT_SYMBOL(dquot_scan_active); + ++static inline int dquot_write_dquot(struct dquot *dquot) ++{ ++ int ret = dquot->dq_sb->dq_op->write_dquot(dquot); ++ if (ret < 0) { ++ quota_error(dquot->dq_sb, "Can't write quota structure " ++ "(error %d). Quota may get out of sync!", ret); ++ /* Clear dirty bit anyway to avoid infinite loop. */ ++ clear_dquot_dirty(dquot); ++ } ++ return ret; ++} ++ + /* Write all dquot structures to quota files */ + int dquot_writeback_dquots(struct super_block *sb, int type) + { +@@ -651,23 +695,16 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + dquot = list_first_entry(&dirty, struct dquot, + dq_dirty); + +- WARN_ON(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); ++ WARN_ON(!dquot_active(dquot)); + + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ + dqgrab(dquot); + spin_unlock(&dq_list_lock); +- err = sb->dq_op->write_dquot(dquot); +- if (err) { +- /* +- * Clear dirty bit anyway to avoid infinite +- * loop here. +- */ +- clear_dquot_dirty(dquot); +- if (!ret) +- ret = err; +- } ++ err = dquot_write_dquot(dquot); ++ if (err && !ret) ++ ret = err; + dqput(dquot); + spin_lock(&dq_list_lock); + } +@@ -760,13 +797,54 @@ static struct shrinker dqcache_shrinker = { + .seeks = DEFAULT_SEEKS, + }; + ++/* ++ * Safely release dquot and put reference to dquot. ++ */ ++static void quota_release_workfn(struct work_struct *work) ++{ ++ struct dquot *dquot; ++ struct list_head rls_head; ++ ++ spin_lock(&dq_list_lock); ++ /* Exchange the list head to avoid livelock. */ ++ list_replace_init(&releasing_dquots, &rls_head); ++ spin_unlock(&dq_list_lock); ++ ++restart: ++ synchronize_srcu(&dquot_srcu); ++ spin_lock(&dq_list_lock); ++ while (!list_empty(&rls_head)) { ++ dquot = list_first_entry(&rls_head, struct dquot, dq_free); ++ /* Dquot got used again? */ ++ if (atomic_read(&dquot->dq_count) > 1) { ++ remove_free_dquot(dquot); ++ atomic_dec(&dquot->dq_count); ++ continue; ++ } ++ if (dquot_dirty(dquot)) { ++ spin_unlock(&dq_list_lock); ++ /* Commit dquot before releasing */ ++ dquot_write_dquot(dquot); ++ goto restart; ++ } ++ if (dquot_active(dquot)) { ++ spin_unlock(&dq_list_lock); ++ dquot->dq_sb->dq_op->release_dquot(dquot); ++ goto restart; ++ } ++ /* Dquot is inactive and clean, now move it to free list */ ++ remove_free_dquot(dquot); ++ atomic_dec(&dquot->dq_count); ++ put_dquot_last(dquot); ++ } ++ spin_unlock(&dq_list_lock); ++} ++ + /* + * Put reference to dquot + */ + void dqput(struct dquot *dquot) + { +- int ret; +- + if (!dquot) + return; + #ifdef CONFIG_QUOTA_DEBUG +@@ -778,7 +856,7 @@ void dqput(struct dquot *dquot) + } + #endif + dqstats_inc(DQST_DROPS); +-we_slept: ++ + spin_lock(&dq_list_lock); + if (atomic_read(&dquot->dq_count) > 1) { + /* We have more than one user... nothing to do */ +@@ -790,35 +868,15 @@ we_slept: + spin_unlock(&dq_list_lock); + return; + } ++ + /* Need to release dquot? */ +- if (dquot_dirty(dquot)) { +- spin_unlock(&dq_list_lock); +- /* Commit dquot before releasing */ +- ret = dquot->dq_sb->dq_op->write_dquot(dquot); +- if (ret < 0) { +- quota_error(dquot->dq_sb, "Can't write quota structure" +- " (error %d). Quota may get out of sync!", +- ret); +- /* +- * We clear dirty bit anyway, so that we avoid +- * infinite loop here +- */ +- clear_dquot_dirty(dquot); +- } +- goto we_slept; +- } +- if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { +- spin_unlock(&dq_list_lock); +- dquot->dq_sb->dq_op->release_dquot(dquot); +- goto we_slept; +- } +- atomic_dec(&dquot->dq_count); + #ifdef CONFIG_QUOTA_DEBUG + /* sanity check */ + BUG_ON(!list_empty(&dquot->dq_free)); + #endif +- put_dquot_last(dquot); ++ put_releasing_dquots(dquot); + spin_unlock(&dq_list_lock); ++ queue_delayed_work(system_unbound_wq, "a_release_work, 1); + } + EXPORT_SYMBOL(dqput); + +@@ -908,7 +966,7 @@ we_slept: + * already finished or it will be canceled due to dq_count > 1 test */ + wait_on_dquot(dquot); + /* Read the dquot / allocate space in quota file */ +- if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { ++ if (!dquot_active(dquot)) { + int err; + + err = sb->dq_op->acquire_dquot(dquot); +@@ -1425,7 +1483,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space) + return QUOTA_NL_NOWARN; + } + +-static int dquot_active(const struct inode *inode) ++static int inode_quota_active(const struct inode *inode) + { + struct super_block *sb = inode->i_sb; + +@@ -1448,7 +1506,7 @@ static int __dquot_initialize(struct inode *inode, int type) + qsize_t rsv; + int ret = 0; + +- if (!dquot_active(inode)) ++ if (!inode_quota_active(inode)) + return 0; + + dquots = i_dquot(inode); +@@ -1556,7 +1614,7 @@ bool dquot_initialize_needed(struct inode *inode) + struct dquot **dquots; + int i; + +- if (!dquot_active(inode)) ++ if (!inode_quota_active(inode)) + return false; + + dquots = i_dquot(inode); +@@ -1667,7 +1725,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) + int reserve = flags & DQUOT_SPACE_RESERVE; + struct dquot **dquots; + +- if (!dquot_active(inode)) { ++ if (!inode_quota_active(inode)) { + if (reserve) { + spin_lock(&inode->i_lock); + *inode_reserved_space(inode) += number; +@@ -1737,7 +1795,7 @@ int dquot_alloc_inode(struct inode *inode) + struct dquot_warn warn[MAXQUOTAS]; + struct dquot * const *dquots; + +- if (!dquot_active(inode)) ++ if (!inode_quota_active(inode)) + return 0; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + warn[cnt].w_type = QUOTA_NL_NOWARN; +@@ -1780,7 +1838,7 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) + struct dquot **dquots; + int cnt, index; + +- if (!dquot_active(inode)) { ++ if (!inode_quota_active(inode)) { + spin_lock(&inode->i_lock); + *inode_reserved_space(inode) -= number; + __inode_add_bytes(inode, number); +@@ -1822,7 +1880,7 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) + struct dquot **dquots; + int cnt, index; + +- if (!dquot_active(inode)) { ++ if (!inode_quota_active(inode)) { + spin_lock(&inode->i_lock); + *inode_reserved_space(inode) += number; + __inode_sub_bytes(inode, number); +@@ -1866,7 +1924,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) + struct dquot **dquots; + int reserve = flags & DQUOT_SPACE_RESERVE, index; + +- if (!dquot_active(inode)) { ++ if (!inode_quota_active(inode)) { + if (reserve) { + spin_lock(&inode->i_lock); + *inode_reserved_space(inode) -= number; +@@ -1921,7 +1979,7 @@ void dquot_free_inode(struct inode *inode) + struct dquot * const *dquots; + int index; + +- if (!dquot_active(inode)) ++ if (!inode_quota_active(inode)) + return; + + dquots = i_dquot(inode); +@@ -2093,7 +2151,7 @@ int dquot_transfer(struct mnt_idmap *idmap, struct inode *inode, + struct super_block *sb = inode->i_sb; + int ret; + +- if (!dquot_active(inode)) ++ if (!inode_quota_active(inode)) + return 0; + + if (i_uid_needs_update(idmap, iattr, inode)) { +diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c +index 4d11d60f493c1..dd58e0dca5e5a 100644 +--- a/fs/reiserfs/journal.c ++++ b/fs/reiserfs/journal.c +@@ -2326,7 +2326,7 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev, + int i, j; + + bh = __getblk(dev, block, bufsize); +- if (buffer_uptodate(bh)) ++ if (!bh || buffer_uptodate(bh)) + return (bh); + + if (block + BUFNR > max_block) { +@@ -2336,6 +2336,8 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev, + j = 1; + for (i = 1; i < blocks; i++) { + bh = __getblk(dev, block + i, bufsize); ++ if (!bh) ++ break; + if (buffer_uptodate(bh)) { + brelse(bh); + break; +diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h +index ca2da713c5fe9..87c6ce54c72d0 100644 +--- a/fs/smb/client/cifsglob.h ++++ b/fs/smb/client/cifsglob.h +@@ -1062,6 +1062,7 @@ struct cifs_ses { + unsigned long chans_need_reconnect; + /* ========= end: protected by chan_lock ======== */ + struct cifs_ses *dfs_root_ses; ++ struct nls_table *local_nls; + }; + + static inline bool +diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c +index a0c4e9874b010..a49f95ea7cf6f 100644 +--- a/fs/smb/client/cifssmb.c ++++ b/fs/smb/client/cifssmb.c +@@ -129,7 +129,7 @@ again: + } + spin_unlock(&server->srv_lock); + +- nls_codepage = load_nls_default(); ++ nls_codepage = ses->local_nls; + + /* + * need to prevent multiple threads trying to simultaneously +@@ -200,7 +200,6 @@ out: + rc = -EAGAIN; + } + +- unload_nls(nls_codepage); + return rc; + } + +diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c +index 853209268f507..e965196e4f746 100644 +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -1837,6 +1837,10 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) + CIFS_MAX_PASSWORD_LEN)) + return 0; + } ++ ++ if (strcmp(ctx->local_nls->charset, ses->local_nls->charset)) ++ return 0; ++ + return 1; + } + +@@ -2280,6 +2284,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) + + ses->sectype = ctx->sectype; + ses->sign = ctx->sign; ++ ses->local_nls = load_nls(ctx->local_nls->charset); + + /* add server as first channel */ + spin_lock(&ses->chan_lock); +diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c +index 70dbfe6584f9e..d7e85d9a26553 100644 +--- a/fs/smb/client/misc.c ++++ b/fs/smb/client/misc.c +@@ -95,6 +95,7 @@ sesInfoFree(struct cifs_ses *buf_to_free) + return; + } + ++ unload_nls(buf_to_free->local_nls); + atomic_dec(&sesInfoAllocCount); + kfree(buf_to_free->serverOS); + kfree(buf_to_free->serverDomain); +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index e04766fe6f803..a457f07f820dc 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -242,7 +242,7 @@ again: + } + spin_unlock(&server->srv_lock); + +- nls_codepage = load_nls_default(); ++ nls_codepage = ses->local_nls; + + /* + * need to prevent multiple threads trying to simultaneously +@@ -324,7 +324,6 @@ out: + rc = -EAGAIN; + } + failed: +- unload_nls(nls_codepage); + return rc; + } + +diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c +index ced7a9e916f01..9df121bdf3492 100644 +--- a/fs/smb/server/server.c ++++ b/fs/smb/server/server.c +@@ -286,6 +286,7 @@ static void handle_ksmbd_work(struct work_struct *wk) + static int queue_ksmbd_work(struct ksmbd_conn *conn) + { + struct ksmbd_work *work; ++ int err; + + work = ksmbd_alloc_work_struct(); + if (!work) { +@@ -297,7 +298,11 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn) + work->request_buf = conn->request_buf; + conn->request_buf = NULL; + +- ksmbd_init_smb_server(work); ++ err = ksmbd_init_smb_server(work); ++ if (err) { ++ ksmbd_free_work_struct(work); ++ return 0; ++ } + + ksmbd_conn_enqueue_request(work); + atomic_inc(&conn->r_count); +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 6d0896c76b098..a61bc3a2649cb 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -87,9 +87,9 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn + */ + int smb2_get_ksmbd_tcon(struct ksmbd_work *work) + { +- struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); ++ struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); + unsigned int cmd = le16_to_cpu(req_hdr->Command); +- int tree_id; ++ unsigned int tree_id; + + if (cmd == SMB2_TREE_CONNECT_HE || + cmd == SMB2_CANCEL_HE || +@@ -114,7 +114,7 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work) + pr_err("The first operation in the compound does not have tcon\n"); + return -EINVAL; + } +- if (work->tcon->id != tree_id) { ++ if (tree_id != UINT_MAX && work->tcon->id != tree_id) { + pr_err("tree id(%u) is different with id(%u) in first operation\n", + tree_id, work->tcon->id); + return -EINVAL; +@@ -559,9 +559,9 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work) + */ + int smb2_check_user_session(struct ksmbd_work *work) + { +- struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); ++ struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); + struct ksmbd_conn *conn = work->conn; +- unsigned int cmd = conn->ops->get_cmd_val(work); ++ unsigned int cmd = le16_to_cpu(req_hdr->Command); + unsigned long long sess_id; + + /* +@@ -587,7 +587,7 @@ int smb2_check_user_session(struct ksmbd_work *work) + pr_err("The first operation in the compound does not have sess\n"); + return -EINVAL; + } +- if (work->sess->id != sess_id) { ++ if (sess_id != ULLONG_MAX && work->sess->id != sess_id) { + pr_err("session id(%llu) is different with the first operation(%lld)\n", + sess_id, work->sess->id); + return -EINVAL; +@@ -6223,6 +6223,11 @@ int smb2_read(struct ksmbd_work *work) + unsigned int max_read_size = conn->vals->max_read_size; + + WORK_BUFFERS(work, req, rsp); ++ if (work->next_smb2_rcv_hdr_off) { ++ work->send_no_response = 1; ++ err = -EOPNOTSUPP; ++ goto out; ++ } + + if (test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_PIPE)) { +@@ -8623,7 +8628,8 @@ int smb3_decrypt_req(struct ksmbd_work *work) + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf); + int rc = 0; + +- if (buf_data_size < sizeof(struct smb2_hdr)) { ++ if (pdu_length < sizeof(struct smb2_transform_hdr) || ++ buf_data_size < sizeof(struct smb2_hdr)) { + pr_err("Transform message is too small (%u)\n", + pdu_length); + return -ECONNABORTED; +diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c +index 3e391a7d5a3ab..27b8bd039791e 100644 +--- a/fs/smb/server/smb_common.c ++++ b/fs/smb/server/smb_common.c +@@ -388,26 +388,29 @@ static struct smb_version_cmds smb1_server_cmds[1] = { + [SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, }, + }; + +-static void init_smb1_server(struct ksmbd_conn *conn) ++static int init_smb1_server(struct ksmbd_conn *conn) + { + conn->ops = &smb1_server_ops; + conn->cmds = smb1_server_cmds; + conn->max_cmds = ARRAY_SIZE(smb1_server_cmds); ++ return 0; + } + +-void ksmbd_init_smb_server(struct ksmbd_work *work) ++int ksmbd_init_smb_server(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; + __le32 proto; + +- if (conn->need_neg == false) +- return; +- + proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; ++ if (conn->need_neg == false) { ++ if (proto == SMB1_PROTO_NUMBER) ++ return -EINVAL; ++ return 0; ++ } ++ + if (proto == SMB1_PROTO_NUMBER) +- init_smb1_server(conn); +- else +- init_smb3_11_server(conn); ++ return init_smb1_server(conn); ++ return init_smb3_11_server(conn); + } + + int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, +diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h +index 6b0d5f1fe85ca..f0134d16067fb 100644 +--- a/fs/smb/server/smb_common.h ++++ b/fs/smb/server/smb_common.h +@@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn); + + int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count); + +-void ksmbd_init_smb_server(struct ksmbd_work *work); ++int ksmbd_init_smb_server(struct ksmbd_work *work); + + struct ksmbd_kstat; + int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, +diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c +index 911cb3d294b86..93f73c35a9c5c 100644 +--- a/fs/smb/server/vfs.c ++++ b/fs/smb/server/vfs.c +@@ -423,7 +423,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + { + char *stream_buf = NULL, *wbuf; + struct mnt_idmap *idmap = file_mnt_idmap(fp->filp); +- size_t size, v_len; ++ size_t size; ++ ssize_t v_len; + int err = 0; + + ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n", +@@ -440,9 +441,9 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + fp->stream.name, + fp->stream.size, + &stream_buf); +- if ((int)v_len < 0) { ++ if (v_len < 0) { + pr_err("not found stream in xattr : %zd\n", v_len); +- err = (int)v_len; ++ err = v_len; + goto out; + } + +diff --git a/fs/splice.c b/fs/splice.c +index 030e162985b5d..3ae2de263e806 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1153,10 +1153,8 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, + if ((in->f_flags | out->f_flags) & O_NONBLOCK) + flags |= SPLICE_F_NONBLOCK; + +- return splice_pipe_to_pipe(ipipe, opipe, len, flags); +- } +- +- if (ipipe) { ++ ret = splice_pipe_to_pipe(ipipe, opipe, len, flags); ++ } else if (ipipe) { + if (off_in) + return -ESPIPE; + if (off_out) { +@@ -1181,18 +1179,11 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, + ret = do_splice_from(ipipe, out, &offset, len, flags); + file_end_write(out); + +- if (ret > 0) +- fsnotify_modify(out); +- + if (!off_out) + out->f_pos = offset; + else + *off_out = offset; +- +- return ret; +- } +- +- if (opipe) { ++ } else if (opipe) { + if (off_out) + return -ESPIPE; + if (off_in) { +@@ -1208,18 +1199,25 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, + + ret = splice_file_to_pipe(in, opipe, &offset, len, flags); + +- if (ret > 0) +- fsnotify_access(in); +- + if (!off_in) + in->f_pos = offset; + else + *off_in = offset; ++ } else { ++ ret = -EINVAL; ++ } + +- return ret; ++ if (ret > 0) { ++ /* ++ * Generate modify out before access in: ++ * do_splice_from() may've already sent modify out, ++ * and this ensures the events get merged. ++ */ ++ fsnotify_modify(out); ++ fsnotify_access(in); + } + +- return -EINVAL; ++ return ret; + } + + static long __do_splice(struct file *in, loff_t __user *off_in, +@@ -1348,6 +1346,9 @@ static long vmsplice_to_user(struct file *file, struct iov_iter *iter, + pipe_unlock(pipe); + } + ++ if (ret > 0) ++ fsnotify_access(file); ++ + return ret; + } + +@@ -1377,8 +1378,10 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter, + if (!ret) + ret = iter_to_pipe(iter, pipe, buf_flag); + pipe_unlock(pipe); +- if (ret > 0) ++ if (ret > 0) { + wakeup_pipe_readers(pipe); ++ fsnotify_modify(file); ++ } + return ret; + } + +@@ -1812,6 +1815,11 @@ long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags) + } + } + ++ if (ret > 0) { ++ fsnotify_access(in); ++ fsnotify_modify(out); ++ } ++ + return ret; + } + +diff --git a/fs/verity/signature.c b/fs/verity/signature.c +index b8c51ad40d3a3..5694daf378e78 100644 +--- a/fs/verity/signature.c ++++ b/fs/verity/signature.c +@@ -54,6 +54,22 @@ int fsverity_verify_signature(const struct fsverity_info *vi, + return 0; + } + ++ if (fsverity_keyring->keys.nr_leaves_on_tree == 0) { ++ /* ++ * The ".fs-verity" keyring is empty, due to builtin signatures ++ * being supported by the kernel but not actually being used. ++ * In this case, verify_pkcs7_signature() would always return an ++ * error, usually ENOKEY. It could also be EBADMSG if the ++ * PKCS#7 is malformed, but that isn't very important to ++ * distinguish. So, just skip to ENOKEY to avoid the attack ++ * surface of the PKCS#7 parser, which would otherwise be ++ * reachable by any task able to execute FS_IOC_ENABLE_VERITY. ++ */ ++ fsverity_err(inode, ++ "fs-verity keyring is empty, rejecting signed file!"); ++ return -ENOKEY; ++ } ++ + d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL); + if (!d) + return -ENOMEM; +diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h +index 016d5a302b84a..bd3a99b0106bf 100644 +--- a/include/crypto/algapi.h ++++ b/include/crypto/algapi.h +@@ -12,6 +12,7 @@ + #include <linux/cache.h> + #include <linux/crypto.h> + #include <linux/types.h> ++#include <linux/workqueue.h> + + /* + * Maximum values for blocksize and alignmask, used to allocate +@@ -83,6 +84,8 @@ struct crypto_instance { + struct crypto_spawn *spawns; + }; + ++ struct work_struct free_work; ++ + void *__ctx[] CRYPTO_MINALIGN_ATTR; + }; + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8280xp.h b/include/dt-bindings/clock/qcom,gcc-sc8280xp.h +index 721105ea4fad8..8454915917849 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8280xp.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8280xp.h +@@ -494,5 +494,15 @@ + #define USB30_SEC_GDSC 11 + #define EMAC_0_GDSC 12 + #define EMAC_1_GDSC 13 ++#define USB4_1_GDSC 14 ++#define USB4_GDSC 15 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 16 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 17 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF0_GDSC 18 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF1_GDSC 19 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 20 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 21 ++#define HLOS1_VOTE_TURING_MMU_TBU2_GDSC 22 ++#define HLOS1_VOTE_TURING_MMU_TBU3_GDSC 23 + + #endif +diff --git a/include/dt-bindings/clock/qcom,qdu1000-gcc.h b/include/dt-bindings/clock/qcom,qdu1000-gcc.h +index ddbc6b825e80c..2fd36cbfddbb2 100644 +--- a/include/dt-bindings/clock/qcom,qdu1000-gcc.h ++++ b/include/dt-bindings/clock/qcom,qdu1000-gcc.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + /* +- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #ifndef _DT_BINDINGS_CLK_QCOM_GCC_QDU1000_H +@@ -138,6 +138,8 @@ + #define GCC_AGGRE_NOC_ECPRI_GSI_CLK 128 + #define GCC_PCIE_0_PIPE_CLK_SRC 129 + #define GCC_PCIE_0_PHY_AUX_CLK_SRC 130 ++#define GCC_GPLL1_OUT_EVEN 131 ++#define GCC_DDRSS_ECPRI_GSI_CLK 132 + + /* GCC resets */ + #define GCC_ECPRI_CC_BCR 0 +diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h +index 14dc461b0e829..255701e1251b4 100644 +--- a/include/linux/arm_sdei.h ++++ b/include/linux/arm_sdei.h +@@ -47,10 +47,12 @@ int sdei_unregister_ghes(struct ghes *ghes); + int sdei_mask_local_cpu(void); + int sdei_unmask_local_cpu(void); + void __init sdei_init(void); ++void sdei_handler_abort(void); + #else + static inline int sdei_mask_local_cpu(void) { return 0; } + static inline int sdei_unmask_local_cpu(void) { return 0; } + static inline void sdei_init(void) { } ++static inline void sdei_handler_abort(void) { } + #endif /* CONFIG_ARM_SDE_INTERFACE */ + + +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 67e942d776bd8..2e2cd4b824e7f 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -546,6 +546,7 @@ struct request_queue { + #define QUEUE_FLAG_ADD_RANDOM 10 /* Contributes to random pool */ + #define QUEUE_FLAG_SYNCHRONOUS 11 /* always completes in submit context */ + #define QUEUE_FLAG_SAME_FORCE 12 /* force complete on same CPU */ ++#define QUEUE_FLAG_HW_WC 18 /* Write back caching supported */ + #define QUEUE_FLAG_INIT_DONE 14 /* queue is initialized */ + #define QUEUE_FLAG_STABLE_WRITES 15 /* don't modify blks until WB is done */ + #define QUEUE_FLAG_POLL 16 /* IO polling enabled if set */ +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 4e4c4fe369118..7cbc10073a1fe 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -360,6 +360,7 @@ struct hid_item { + #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18) + #define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19) + #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20) ++#define HID_QUIRK_NOINVERT BIT(21) + #define HID_QUIRK_FULLSPEED_INTERVAL BIT(28) + #define HID_QUIRK_NO_INIT_REPORTS BIT(29) + #define HID_QUIRK_NO_IGNORE BIT(30) +diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h +index 1ed52441972f9..10a1e81434cb9 100644 +--- a/include/linux/if_arp.h ++++ b/include/linux/if_arp.h +@@ -53,6 +53,10 @@ static inline bool dev_is_mac_header_xmit(const struct net_device *dev) + case ARPHRD_NONE: + case ARPHRD_RAWIP: + case ARPHRD_PIMREG: ++ /* PPP adds its l2 header automatically in ppp_start_xmit(). ++ * This makes it look like an l3 device to __bpf_redirect() and tcf_mirred_init(). ++ */ ++ case ARPHRD_PPP: + return false; + default: + return true; +diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h +index 73f5c120def88..2a36f3218b510 100644 +--- a/include/linux/kernfs.h ++++ b/include/linux/kernfs.h +@@ -550,6 +550,10 @@ static inline int kernfs_setattr(struct kernfs_node *kn, + const struct iattr *iattr) + { return -ENOSYS; } + ++static inline __poll_t kernfs_generic_poll(struct kernfs_open_file *of, ++ struct poll_table_struct *pt) ++{ return -ENOSYS; } ++ + static inline void kernfs_notify(struct kernfs_node *kn) { } + + static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name, +diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h +index 6bb55e61e8e87..fb9f5f00a7789 100644 +--- a/include/linux/lsm_hook_defs.h ++++ b/include/linux/lsm_hook_defs.h +@@ -54,6 +54,7 @@ LSM_HOOK(int, 0, bprm_creds_from_file, struct linux_binprm *bprm, struct file *f + LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm) + LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm) + LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm) ++LSM_HOOK(int, 0, fs_context_submount, struct fs_context *fc, struct super_block *reference) + LSM_HOOK(int, 0, fs_context_dup, struct fs_context *fc, + struct fs_context *src_sc) + LSM_HOOK(int, -ENOPARAM, fs_context_parse_param, struct fs_context *fc, +diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h +index 222d7370134c7..7f2921217f50b 100644 +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -284,6 +284,11 @@ struct mem_cgroup { + atomic_long_t memory_events[MEMCG_NR_MEMORY_EVENTS]; + atomic_long_t memory_events_local[MEMCG_NR_MEMORY_EVENTS]; + ++ /* ++ * Hint of reclaim pressure for socket memroy management. Note ++ * that this indicator should NOT be used in legacy cgroup mode ++ * where socket memory is accounted/charged separately. ++ */ + unsigned long socket_pressure; + + /* Legacy tcp memory accounting */ +@@ -1743,8 +1748,8 @@ void mem_cgroup_sk_alloc(struct sock *sk); + void mem_cgroup_sk_free(struct sock *sk); + static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) + { +- if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && memcg->tcpmem_pressure) +- return true; ++ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) ++ return !!memcg->tcpmem_pressure; + do { + if (time_before(jiffies, READ_ONCE(memcg->socket_pressure))) + return true; +diff --git a/include/linux/nls.h b/include/linux/nls.h +index 499e486b3722d..e0bf8367b274a 100644 +--- a/include/linux/nls.h ++++ b/include/linux/nls.h +@@ -47,7 +47,7 @@ enum utf16_endian { + /* nls_base.c */ + extern int __register_nls(struct nls_table *, struct module *); + extern int unregister_nls(struct nls_table *); +-extern struct nls_table *load_nls(char *); ++extern struct nls_table *load_nls(const char *charset); + extern void unload_nls(struct nls_table *); + extern struct nls_table *load_nls_default(void); + #define register_nls(nls) __register_nls((nls), THIS_MODULE) +diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h +index fa030d93b768e..27373024856dc 100644 +--- a/include/linux/nvmem-consumer.h ++++ b/include/linux/nvmem-consumer.h +@@ -256,7 +256,7 @@ static inline struct nvmem_device *of_nvmem_device_get(struct device_node *np, + static inline struct device_node * + of_nvmem_layout_get_container(struct nvmem_device *nvmem) + { +- return ERR_PTR(-EOPNOTSUPP); ++ return NULL; + } + #endif /* CONFIG_NVMEM && CONFIG_OF */ + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index c69a2cc1f4123..7ee498cd1f374 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -467,6 +467,7 @@ struct pci_dev { + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + ++ spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ + u32 saved_config_space[16]; /* Config space saved at suspend time */ + struct hlist_head saved_cap_space; + int rom_attr_enabled; /* Display of ROM attribute enabled? */ +@@ -1217,11 +1218,40 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val); + int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val); + int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val); + int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val); +-int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, +- u16 clear, u16 set); ++int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos, ++ u16 clear, u16 set); ++int pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos, ++ u16 clear, u16 set); + int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, + u32 clear, u32 set); + ++/** ++ * pcie_capability_clear_and_set_word - RMW accessor for PCI Express Capability Registers ++ * @dev: PCI device structure of the PCI Express device ++ * @pos: PCI Express Capability Register ++ * @clear: Clear bitmask ++ * @set: Set bitmask ++ * ++ * Perform a Read-Modify-Write (RMW) operation using @clear and @set ++ * bitmasks on PCI Express Capability Register at @pos. Certain PCI Express ++ * Capability Registers are accessed concurrently in RMW fashion, hence ++ * require locking which is handled transparently to the caller. ++ */ ++static inline int pcie_capability_clear_and_set_word(struct pci_dev *dev, ++ int pos, ++ u16 clear, u16 set) ++{ ++ switch (pos) { ++ case PCI_EXP_LNKCTL: ++ case PCI_EXP_RTCTL: ++ return pcie_capability_clear_and_set_word_locked(dev, pos, ++ clear, set); ++ default: ++ return pcie_capability_clear_and_set_word_unlocked(dev, pos, ++ clear, set); ++ } ++} ++ + static inline int pcie_capability_set_word(struct pci_dev *dev, int pos, + u16 set) + { +diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h +index c758809d5bcf3..53974d79d98e8 100644 +--- a/include/linux/pid_namespace.h ++++ b/include/linux/pid_namespace.h +@@ -17,18 +17,10 @@ + struct fs_pin; + + #if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE) +-/* +- * sysctl for vm.memfd_noexec +- * 0: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL +- * acts like MFD_EXEC was set. +- * 1: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL +- * acts like MFD_NOEXEC_SEAL was set. +- * 2: memfd_create() without MFD_NOEXEC_SEAL will be +- * rejected. +- */ +-#define MEMFD_NOEXEC_SCOPE_EXEC 0 +-#define MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL 1 +-#define MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED 2 ++/* modes for vm.memfd_noexec sysctl */ ++#define MEMFD_NOEXEC_SCOPE_EXEC 0 /* MFD_EXEC implied if unset */ ++#define MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL 1 /* MFD_NOEXEC_SEAL implied if unset */ ++#define MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED 2 /* same as 1, except MFD_EXEC rejected */ + #endif + + struct pid_namespace { +diff --git a/include/linux/security.h b/include/linux/security.h +index e2734e9e44d5c..274c75fa2e272 100644 +--- a/include/linux/security.h ++++ b/include/linux/security.h +@@ -293,6 +293,7 @@ int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file); + int security_bprm_check(struct linux_binprm *bprm); + void security_bprm_committing_creds(struct linux_binprm *bprm); + void security_bprm_committed_creds(struct linux_binprm *bprm); ++int security_fs_context_submount(struct fs_context *fc, struct super_block *reference); + int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc); + int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param); + int security_sb_alloc(struct super_block *sb); +@@ -629,6 +630,11 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm) + { + } + ++static inline int security_fs_context_submount(struct fs_context *fc, ++ struct super_block *reference) ++{ ++ return 0; ++} + static inline int security_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc) + { +diff --git a/include/linux/thermal.h b/include/linux/thermal.h +index 87837094d549f..dee66ade89a03 100644 +--- a/include/linux/thermal.h ++++ b/include/linux/thermal.h +@@ -301,14 +301,14 @@ int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp); + #ifdef CONFIG_THERMAL + struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, + void *, struct thermal_zone_device_ops *, +- struct thermal_zone_params *, int, int); ++ const struct thermal_zone_params *, int, int); + + void thermal_zone_device_unregister(struct thermal_zone_device *); + + struct thermal_zone_device * + thermal_zone_device_register_with_trips(const char *, struct thermal_trip *, int, int, + void *, struct thermal_zone_device_ops *, +- struct thermal_zone_params *, int, int); ++ const struct thermal_zone_params *, int, int); + + void *thermal_zone_device_priv(struct thermal_zone_device *tzd); + const char *thermal_zone_device_type(struct thermal_zone_device *tzd); +@@ -348,7 +348,7 @@ void thermal_zone_device_critical(struct thermal_zone_device *tz); + static inline struct thermal_zone_device *thermal_zone_device_register( + const char *type, int trips, int mask, void *devdata, + struct thermal_zone_device_ops *ops, +- struct thermal_zone_params *tzp, ++ const struct thermal_zone_params *tzp, + int passive_delay, int polling_delay) + { return ERR_PTR(-ENODEV); } + static inline void thermal_zone_device_unregister( +diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h +index c55fc453e33b5..6a41ad2ca84cc 100644 +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -875,7 +875,8 @@ extern int perf_uprobe_init(struct perf_event *event, + extern void perf_uprobe_destroy(struct perf_event *event); + extern int bpf_get_uprobe_info(const struct perf_event *event, + u32 *fd_type, const char **filename, +- u64 *probe_offset, bool perf_type_tracepoint); ++ u64 *probe_offset, u64 *probe_addr, ++ bool perf_type_tracepoint); + #endif + extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, + char *filter_str); +diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h +index 350d49012659b..28aeef8f9e7b5 100644 +--- a/include/linux/usb/typec_altmode.h ++++ b/include/linux/usb/typec_altmode.h +@@ -67,7 +67,7 @@ struct typec_altmode_ops { + + int typec_altmode_enter(struct typec_altmode *altmode, u32 *vdo); + int typec_altmode_exit(struct typec_altmode *altmode); +-void typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); ++int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); + int typec_altmode_vdm(struct typec_altmode *altmode, + const u32 header, const u32 *vdo, int count); + int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf, +diff --git a/include/media/cec.h b/include/media/cec.h +index abee41ae02d0e..9c007f83569aa 100644 +--- a/include/media/cec.h ++++ b/include/media/cec.h +@@ -113,22 +113,25 @@ struct cec_fh { + #define CEC_FREE_TIME_TO_USEC(ft) ((ft) * 2400) + + struct cec_adap_ops { +- /* Low-level callbacks */ ++ /* Low-level callbacks, called with adap->lock held */ + int (*adap_enable)(struct cec_adapter *adap, bool enable); + int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); + int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable); + int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); +- void (*adap_configured)(struct cec_adapter *adap, bool configured); ++ void (*adap_unconfigured)(struct cec_adapter *adap); + int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg); ++ void (*adap_nb_transmit_canceled)(struct cec_adapter *adap, ++ const struct cec_msg *msg); + void (*adap_status)(struct cec_adapter *adap, struct seq_file *file); + void (*adap_free)(struct cec_adapter *adap); + +- /* Error injection callbacks */ ++ /* Error injection callbacks, called without adap->lock held */ + int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf); + bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line); + +- /* High-level CEC message callback */ ++ /* High-level CEC message callback, called without adap->lock held */ ++ void (*configured)(struct cec_adapter *adap); + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); + }; + +diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h +index 872dcb91a540e..3ff822ebb3a47 100644 +--- a/include/net/bluetooth/hci.h ++++ b/include/net/bluetooth/hci.h +@@ -309,6 +309,26 @@ enum { + * to support it. + */ + HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, ++ ++ /* When this quirk is set, MSFT extension monitor tracking by ++ * address filter is supported. Since tracking quantity of each ++ * pattern is limited, this feature supports tracking multiple ++ * devices concurrently if controller supports multiple ++ * address filters. ++ * ++ * This quirk must be set before hci_register_dev is called. ++ */ ++ HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, ++ ++ /* ++ * When this quirk is set, LE Coded PHY shall not be used. This is ++ * required for some Intel controllers which erroneously claim to ++ * support it but it causes problems with extended scanning. ++ * ++ * This quirk can be set before hci_register_dev is called or ++ * during the hdev->setup vendor callback. ++ */ ++ HCI_QUIRK_BROKEN_LE_CODED, + }; + + /* HCI device flags */ +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index 870b6d3c5146b..3190ca493bd18 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -321,8 +321,8 @@ struct adv_monitor { + + #define HCI_MAX_SHORT_NAME_LENGTH 10 + +-#define HCI_CONN_HANDLE_UNSET 0xffff + #define HCI_CONN_HANDLE_MAX 0x0eff ++#define HCI_CONN_HANDLE_UNSET(_handle) (_handle > HCI_CONN_HANDLE_MAX) + + /* Min encryption key size to match with SMP */ + #define HCI_MIN_ENC_KEY_SIZE 7 +@@ -741,6 +741,7 @@ struct hci_conn { + unsigned long flags; + + enum conn_reasons conn_reason; ++ __u8 abort_reason; + + __u32 clock; + __u16 clock_accuracy; +@@ -760,7 +761,6 @@ struct hci_conn { + struct delayed_work auto_accept_work; + struct delayed_work idle_work; + struct delayed_work le_conn_timeout; +- struct work_struct le_scan_cleanup; + + struct device dev; + struct dentry *debugfs; +@@ -976,6 +976,10 @@ enum { + HCI_CONN_SCANNING, + HCI_CONN_AUTH_FAILURE, + HCI_CONN_PER_ADV, ++ HCI_CONN_BIG_CREATED, ++ HCI_CONN_CREATE_CIS, ++ HCI_CONN_BIG_SYNC, ++ HCI_CONN_BIG_SYNC_FAILED, + }; + + static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) +@@ -1117,6 +1121,32 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev, + return NULL; + } + ++static inline struct hci_conn * ++hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev, ++ bdaddr_t *ba, ++ __u8 big, __u8 bis) ++{ ++ struct hci_conn_hash *h = &hdev->conn_hash; ++ struct hci_conn *c; ++ ++ rcu_read_lock(); ++ ++ list_for_each_entry_rcu(c, &h->list, list) { ++ if (bacmp(&c->dst, ba) || c->type != ISO_LINK || ++ !test_bit(HCI_CONN_PER_ADV, &c->flags)) ++ continue; ++ ++ if (c->iso_qos.bcast.big == big && ++ c->iso_qos.bcast.bis == bis) { ++ rcu_read_unlock(); ++ return c; ++ } ++ } ++ rcu_read_unlock(); ++ ++ return NULL; ++} ++ + static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, + __u16 handle) + { +@@ -1261,6 +1291,29 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev, + return NULL; + } + ++static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *hdev, ++ __u8 handle) ++{ ++ struct hci_conn_hash *h = &hdev->conn_hash; ++ struct hci_conn *c; ++ ++ rcu_read_lock(); ++ ++ list_for_each_entry_rcu(c, &h->list, list) { ++ if (c->type != ISO_LINK) ++ continue; ++ ++ if (handle == c->iso_qos.bcast.big) { ++ rcu_read_unlock(); ++ return c; ++ } ++ } ++ ++ rcu_read_unlock(); ++ ++ return NULL; ++} ++ + static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, + __u8 type, __u16 state) + { +@@ -1326,7 +1379,8 @@ int hci_disconnect(struct hci_conn *conn, __u8 reason); + bool hci_setup_sync(struct hci_conn *conn, __u16 handle); + void hci_sco_setup(struct hci_conn *conn, __u8 status); + bool hci_iso_setup_path(struct hci_conn *conn); +-int hci_le_create_cis(struct hci_conn *conn); ++int hci_le_create_cis_pending(struct hci_dev *hdev); ++int hci_conn_check_create_cis(struct hci_conn *conn); + + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + u8 role); +@@ -1353,6 +1407,9 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u16 setting, struct bt_codec *codec); + struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos); ++struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, ++ struct bt_iso_qos *qos, ++ __u8 base_len, __u8 *base); + struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos); + struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, +@@ -1715,7 +1772,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn); + #define scan_2m(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_2M) || \ + ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_2M)) + +-#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED)) ++#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED) && \ ++ !test_bit(HCI_QUIRK_BROKEN_LE_CODED, \ ++ &(dev)->quirks)) + + #define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \ + ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED)) +diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h +index 2495be4d8b828..b516a0f4a55b8 100644 +--- a/include/net/bluetooth/hci_sync.h ++++ b/include/net/bluetooth/hci_sync.h +@@ -124,7 +124,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason); + + int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn); + +-int hci_le_create_cis_sync(struct hci_dev *hdev, struct hci_conn *conn); ++int hci_le_create_cis_sync(struct hci_dev *hdev); + + int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle); + +diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h +index 6f15e6fa154e6..53bd2d02a4f0d 100644 +--- a/include/net/lwtunnel.h ++++ b/include/net/lwtunnel.h +@@ -16,9 +16,12 @@ + #define LWTUNNEL_STATE_INPUT_REDIRECT BIT(1) + #define LWTUNNEL_STATE_XMIT_REDIRECT BIT(2) + ++/* LWTUNNEL_XMIT_CONTINUE should be distinguishable from dst_output return ++ * values (NET_XMIT_xxx and NETDEV_TX_xxx in linux/netdevice.h) for safety. ++ */ + enum { + LWTUNNEL_XMIT_DONE, +- LWTUNNEL_XMIT_CONTINUE, ++ LWTUNNEL_XMIT_CONTINUE = 0x100, + }; + + +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index 67d81f7186660..52b336ada480c 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1192,9 +1192,11 @@ struct ieee80211_tx_info { + u8 ampdu_ack_len; + u8 ampdu_len; + u8 antenna; ++ u8 pad; + u16 tx_time; + u8 flags; +- void *status_driver_data[18 / sizeof(void *)]; ++ u8 pad2; ++ void *status_driver_data[16 / sizeof(void *)]; + } status; + struct { + struct ieee80211_tx_rate driver_rates[ +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 182337a8cf94a..ca6435f5d821e 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -355,7 +355,6 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, + struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, + bool force_schedule); + +-void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks); + static inline void tcp_dec_quickack_mode(struct sock *sk, + const unsigned int pkts) + { +diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h +index 0f29799efa021..6b90b476a03cb 100644 +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -763,7 +763,7 @@ extern void scsi_remove_host(struct Scsi_Host *); + extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *); + extern int scsi_host_busy(struct Scsi_Host *shost); + extern void scsi_host_put(struct Scsi_Host *t); +-extern struct Scsi_Host *scsi_host_lookup(unsigned short); ++extern struct Scsi_Host *scsi_host_lookup(unsigned int hostnum); + extern const char *scsi_host_state_name(enum scsi_host_state); + extern void scsi_host_complete_all_commands(struct Scsi_Host *shost, + enum scsi_host_status status); +diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h +index 7e42a5b7558bf..ff0a931833e25 100644 +--- a/include/uapi/linux/sync_file.h ++++ b/include/uapi/linux/sync_file.h +@@ -56,7 +56,7 @@ struct sync_fence_info { + * @name: name of fence + * @status: status of fence. 1: signaled 0:active <0:error + * @flags: sync_file_info flags +- * @num_fences number of fences in the sync_file ++ * @num_fences: number of fences in the sync_file + * @pad: padding for 64-bit alignment, should always be zero + * @sync_fence_info: pointer to array of struct &sync_fence_info with all + * fences in the sync_file +diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h +index 4e8d6240e589b..af5f5e588d5f4 100644 +--- a/include/ufs/ufs.h ++++ b/include/ufs/ufs.h +@@ -102,6 +102,12 @@ enum { + UPIU_CMD_FLAGS_READ = 0x40, + }; + ++/* UPIU response flags */ ++enum { ++ UPIU_RSP_FLAG_UNDERFLOW = 0x20, ++ UPIU_RSP_FLAG_OVERFLOW = 0x40, ++}; ++ + /* UPIU Task Attributes */ + enum { + UPIU_TASK_ATTR_SIMPLE = 0x00, +diff --git a/init/Kconfig b/init/Kconfig +index 32c24950c4ced..c70617066a4c8 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -629,6 +629,7 @@ config TASK_IO_ACCOUNTING + + config PSI + bool "Pressure stall information tracking" ++ select KERNFS + help + Collect metrics that indicate how overcommitted the CPU, memory, + and IO capacity are in the system. +diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c +index 399e9a15c38d6..2c03bc881edfd 100644 +--- a/io_uring/io-wq.c ++++ b/io_uring/io-wq.c +@@ -174,6 +174,16 @@ static void io_worker_ref_put(struct io_wq *wq) + complete(&wq->worker_done); + } + ++bool io_wq_worker_stopped(void) ++{ ++ struct io_worker *worker = current->worker_private; ++ ++ if (WARN_ON_ONCE(!io_wq_current_is_worker())) ++ return true; ++ ++ return test_bit(IO_WQ_BIT_EXIT, &worker->wq->state); ++} ++ + static void io_worker_cancel_cb(struct io_worker *worker) + { + struct io_wq_acct *acct = io_wq_get_acct(worker); +@@ -1285,13 +1295,16 @@ static int io_wq_cpu_offline(unsigned int cpu, struct hlist_node *node) + return __io_wq_cpu_online(wq, cpu, false); + } + +-int io_wq_cpu_affinity(struct io_wq *wq, cpumask_var_t mask) ++int io_wq_cpu_affinity(struct io_uring_task *tctx, cpumask_var_t mask) + { ++ if (!tctx || !tctx->io_wq) ++ return -EINVAL; ++ + rcu_read_lock(); + if (mask) +- cpumask_copy(wq->cpu_mask, mask); ++ cpumask_copy(tctx->io_wq->cpu_mask, mask); + else +- cpumask_copy(wq->cpu_mask, cpu_possible_mask); ++ cpumask_copy(tctx->io_wq->cpu_mask, cpu_possible_mask); + rcu_read_unlock(); + + return 0; +diff --git a/io_uring/io-wq.h b/io_uring/io-wq.h +index 31228426d1924..2b2a6406dd8ee 100644 +--- a/io_uring/io-wq.h ++++ b/io_uring/io-wq.h +@@ -50,8 +50,9 @@ void io_wq_put_and_exit(struct io_wq *wq); + void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work); + void io_wq_hash_work(struct io_wq_work *work, void *val); + +-int io_wq_cpu_affinity(struct io_wq *wq, cpumask_var_t mask); ++int io_wq_cpu_affinity(struct io_uring_task *tctx, cpumask_var_t mask); + int io_wq_max_workers(struct io_wq *wq, int *new_count); ++bool io_wq_worker_stopped(void); + + static inline bool io_wq_is_hashed(struct io_wq_work *work) + { +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index a57bdf336ca8a..d3b36197087a5 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -231,7 +231,6 @@ static inline void req_fail_link_node(struct io_kiocb *req, int res) + static inline void io_req_add_to_cache(struct io_kiocb *req, struct io_ring_ctx *ctx) + { + wq_stack_add_head(&req->comp_list, &ctx->submit_state.free_list); +- kasan_poison_object_data(req_cachep, req); + } + + static __cold void io_ring_ctx_ref_free(struct percpu_ref *ref) +@@ -1690,6 +1689,9 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min) + break; + nr_events += ret; + ret = 0; ++ ++ if (task_sigpending(current)) ++ return -EINTR; + } while (nr_events < min && !need_resched()); + + return ret; +@@ -2048,6 +2050,8 @@ fail: + if (!needs_poll) { + if (!(req->ctx->flags & IORING_SETUP_IOPOLL)) + break; ++ if (io_wq_worker_stopped()) ++ break; + cond_resched(); + continue; + } +@@ -2468,7 +2472,9 @@ static bool io_get_sqe(struct io_ring_ctx *ctx, const struct io_uring_sqe **sqe) + } + + /* drop invalid entries */ ++ spin_lock(&ctx->completion_lock); + ctx->cq_extra--; ++ spin_unlock(&ctx->completion_lock); + WRITE_ONCE(ctx->rings->sq_dropped, + READ_ONCE(ctx->rings->sq_dropped) + 1); + return false; +@@ -4173,16 +4179,28 @@ static int io_register_enable_rings(struct io_ring_ctx *ctx) + return 0; + } + ++static __cold int __io_register_iowq_aff(struct io_ring_ctx *ctx, ++ cpumask_var_t new_mask) ++{ ++ int ret; ++ ++ if (!(ctx->flags & IORING_SETUP_SQPOLL)) { ++ ret = io_wq_cpu_affinity(current->io_uring, new_mask); ++ } else { ++ mutex_unlock(&ctx->uring_lock); ++ ret = io_sqpoll_wq_cpu_affinity(ctx, new_mask); ++ mutex_lock(&ctx->uring_lock); ++ } ++ ++ return ret; ++} ++ + static __cold int io_register_iowq_aff(struct io_ring_ctx *ctx, + void __user *arg, unsigned len) + { +- struct io_uring_task *tctx = current->io_uring; + cpumask_var_t new_mask; + int ret; + +- if (!tctx || !tctx->io_wq) +- return -EINVAL; +- + if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) + return -ENOMEM; + +@@ -4203,19 +4221,14 @@ static __cold int io_register_iowq_aff(struct io_ring_ctx *ctx, + return -EFAULT; + } + +- ret = io_wq_cpu_affinity(tctx->io_wq, new_mask); ++ ret = __io_register_iowq_aff(ctx, new_mask); + free_cpumask_var(new_mask); + return ret; + } + + static __cold int io_unregister_iowq_aff(struct io_ring_ctx *ctx) + { +- struct io_uring_task *tctx = current->io_uring; +- +- if (!tctx || !tctx->io_wq) +- return -EINVAL; +- +- return io_wq_cpu_affinity(tctx->io_wq, NULL); ++ return __io_register_iowq_aff(ctx, NULL); + } + + static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx, +diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h +index 259bf798a390e..97cfb3f2f06d0 100644 +--- a/io_uring/io_uring.h ++++ b/io_uring/io_uring.h +@@ -361,7 +361,6 @@ static inline struct io_kiocb *io_extract_req(struct io_ring_ctx *ctx) + struct io_kiocb *req; + + req = container_of(ctx->submit_state.free_list.next, struct io_kiocb, comp_list); +- kasan_unpoison_object_data(req_cachep, req); + wq_stack_extract(&ctx->submit_state.free_list); + return req; + } +diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c +index 5e329e3cd4706..bd6c2c7959a5b 100644 +--- a/io_uring/sqpoll.c ++++ b/io_uring/sqpoll.c +@@ -421,3 +421,20 @@ err: + io_sq_thread_finish(ctx); + return ret; + } ++ ++__cold int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx, ++ cpumask_var_t mask) ++{ ++ struct io_sq_data *sqd = ctx->sq_data; ++ int ret = -EINVAL; ++ ++ if (sqd) { ++ io_sq_thread_park(sqd); ++ /* Don't set affinity for a dying thread */ ++ if (sqd->thread) ++ ret = io_wq_cpu_affinity(sqd->thread->io_uring, mask); ++ io_sq_thread_unpark(sqd); ++ } ++ ++ return ret; ++} +diff --git a/io_uring/sqpoll.h b/io_uring/sqpoll.h +index e1b8d508d22d1..8df37e8c91493 100644 +--- a/io_uring/sqpoll.h ++++ b/io_uring/sqpoll.h +@@ -27,3 +27,4 @@ void io_sq_thread_park(struct io_sq_data *sqd); + void io_sq_thread_unpark(struct io_sq_data *sqd); + void io_put_sq_data(struct io_sq_data *sqd); + void io_sqpoll_wait_sq(struct io_ring_ctx *ctx); ++int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx, cpumask_var_t mask); +diff --git a/kernel/auditsc.c b/kernel/auditsc.c +index addeed3df15d3..8dfd581cd5543 100644 +--- a/kernel/auditsc.c ++++ b/kernel/auditsc.c +@@ -2456,6 +2456,8 @@ void __audit_inode_child(struct inode *parent, + } + } + ++ cond_resched(); ++ + /* is there a matching child entry? */ + list_for_each_entry(n, &context->names_list, list) { + /* can only match entries that have a name */ +diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c +index 8b4e92439d1d6..9976149ec42f0 100644 +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -6126,7 +6126,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf, + const char *tname, *mname, *tag_value; + u32 vlen, elem_id, mid; + +- *flag = 0; + again: + tname = __btf_name_by_offset(btf, t->name_off); + if (!btf_type_is_struct(t)) { +@@ -6135,6 +6134,14 @@ again: + } + + vlen = btf_type_vlen(t); ++ if (BTF_INFO_KIND(t->info) == BTF_KIND_UNION && vlen != 1 && !(*flag & PTR_UNTRUSTED)) ++ /* ++ * walking unions yields untrusted pointers ++ * with exception of __bpf_md_ptr and other ++ * unions with a single member ++ */ ++ *flag |= PTR_UNTRUSTED; ++ + if (off + size > t->size) { + /* If the last element is a variable size array, we may + * need to relax the rule. +@@ -6295,15 +6302,6 @@ error: + * of this field or inside of this struct + */ + if (btf_type_is_struct(mtype)) { +- if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION && +- btf_type_vlen(mtype) != 1) +- /* +- * walking unions yields untrusted pointers +- * with exception of __bpf_md_ptr and other +- * unions with a single member +- */ +- *flag |= PTR_UNTRUSTED; +- + /* our field must be inside that union or struct */ + t = mtype; + +@@ -6361,7 +6359,7 @@ error: + * that also allows using an array of int as a scratch + * space. e.g. skb->cb[]. + */ +- if (off + size > mtrue_end) { ++ if (off + size > mtrue_end && !(*flag & PTR_UNTRUSTED)) { + bpf_log(log, + "access beyond the end of member %s (mend:%u) in struct %s with off %u size %u\n", + mname, mtrue_end, tname, off, size); +@@ -6469,7 +6467,7 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log, + bool strict) + { + const struct btf_type *type; +- enum bpf_type_flag flag; ++ enum bpf_type_flag flag = 0; + int err; + + /* Are we already done? */ +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index f12565ba136b0..8c5daa841704b 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -2218,7 +2218,7 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset + case BPF_DYNPTR_TYPE_XDP: + { + void *xdp_ptr = bpf_xdp_pointer(ptr->data, ptr->offset + offset, len); +- if (xdp_ptr) ++ if (!IS_ERR_OR_NULL(xdp_ptr)) + return xdp_ptr; + + bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer, len, false); +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 4fbfe1d086467..ae391e8256551 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -4790,20 +4790,22 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + struct bpf_reg_state *reg, u32 regno) + { + const char *targ_name = btf_type_name(kptr_field->kptr.btf, kptr_field->kptr.btf_id); +- int perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; ++ int perm_flags; + const char *reg_name = ""; + +- /* Only unreferenced case accepts untrusted pointers */ +- if (kptr_field->type == BPF_KPTR_UNREF) +- perm_flags |= PTR_UNTRUSTED; ++ if (btf_is_kernel(reg->btf)) { ++ perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; ++ ++ /* Only unreferenced case accepts untrusted pointers */ ++ if (kptr_field->type == BPF_KPTR_UNREF) ++ perm_flags |= PTR_UNTRUSTED; ++ } else { ++ perm_flags = PTR_MAYBE_NULL | MEM_ALLOC; ++ } + + if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags)) + goto bad_type; + +- if (!btf_is_kernel(reg->btf)) { +- verbose(env, "R%d must point to kernel BTF\n", regno); +- return -EINVAL; +- } + /* We need to verify reg->type and reg->btf, before accessing reg->btf */ + reg_name = btf_type_name(reg->btf, reg->btf_id); + +@@ -4816,7 +4818,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + if (__check_ptr_off_reg(env, reg, regno, true)) + return -EACCES; + +- /* A full type match is needed, as BTF can be vmlinux or module BTF, and ++ /* A full type match is needed, as BTF can be vmlinux, module or prog BTF, and + * we also need to take into account the reg->off. + * + * We want to support cases like: +@@ -5893,6 +5895,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, + type_is_rcu_or_null(env, reg, field_name, btf_id)) { + /* __rcu tagged pointers can be NULL */ + flag |= MEM_RCU | PTR_MAYBE_NULL; ++ ++ /* We always trust them */ ++ if (type_is_rcu_or_null(env, reg, field_name, btf_id) && ++ flag & PTR_UNTRUSTED) ++ flag &= ~PTR_UNTRUSTED; + } else if (flag & (MEM_PERCPU | MEM_USER)) { + /* keep as-is */ + } else { +@@ -7549,7 +7556,10 @@ found: + verbose(env, "verifier internal error: unimplemented handling of MEM_ALLOC\n"); + return -EFAULT; + } +- /* Handled by helper specific checks */ ++ if (meta->func_id == BPF_FUNC_kptr_xchg) { ++ if (map_kptr_match_type(env, meta->kptr_field, reg, regno)) ++ return -EACCES; ++ } + break; + case PTR_TO_BTF_ID | MEM_PERCPU: + case PTR_TO_BTF_ID | MEM_PERCPU | PTR_TRUSTED: +@@ -7601,17 +7611,6 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, + if (arg_type_is_dynptr(arg_type) && type == PTR_TO_STACK) + return 0; + +- if ((type_is_ptr_alloc_obj(type) || type_is_non_owning_ref(type)) && reg->off) { +- if (reg_find_field_offset(reg, reg->off, BPF_GRAPH_NODE_OR_ROOT)) +- return __check_ptr_off_reg(env, reg, regno, true); +- +- verbose(env, "R%d must have zero offset when passed to release func\n", +- regno); +- verbose(env, "No graph node or root found at R%d type:%s off:%d\n", regno, +- btf_type_name(reg->btf, reg->btf_id), reg->off); +- return -EINVAL; +- } +- + /* Doing check_ptr_off_reg check for the offset will catch this + * because fixed_off_ok is false, but checking here allows us + * to give the user a better error message. +@@ -13598,6 +13597,12 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + return -EINVAL; + } + ++ /* check src2 operand */ ++ err = check_reg_arg(env, insn->dst_reg, SRC_OP); ++ if (err) ++ return err; ++ ++ dst_reg = ®s[insn->dst_reg]; + if (BPF_SRC(insn->code) == BPF_X) { + if (insn->imm != 0) { + verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); +@@ -13609,12 +13614,13 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + if (err) + return err; + +- if (is_pointer_value(env, insn->src_reg)) { ++ src_reg = ®s[insn->src_reg]; ++ if (!(reg_is_pkt_pointer_any(dst_reg) && reg_is_pkt_pointer_any(src_reg)) && ++ is_pointer_value(env, insn->src_reg)) { + verbose(env, "R%d pointer comparison prohibited\n", + insn->src_reg); + return -EACCES; + } +- src_reg = ®s[insn->src_reg]; + } else { + if (insn->src_reg != BPF_REG_0) { + verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); +@@ -13622,12 +13628,6 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + } + } + +- /* check src2 operand */ +- err = check_reg_arg(env, insn->dst_reg, SRC_OP); +- if (err) +- return err; +- +- dst_reg = ®s[insn->dst_reg]; + is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; + + if (BPF_SRC(insn->code) == BPF_K) { +diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c +index 2c76fcd9f0bcb..7c5153273c1a8 100644 +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -1611,11 +1611,16 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, + } + + /* +- * Skip the whole subtree if the cpumask remains the same +- * and has no partition root state and force flag not set. ++ * Skip the whole subtree if ++ * 1) the cpumask remains the same, ++ * 2) has no partition root state, ++ * 3) force flag not set, and ++ * 4) for v2 load balance state same as its parent. + */ + if (!cp->partition_root_state && !force && +- cpumask_equal(tmp->new_cpus, cp->effective_cpus)) { ++ cpumask_equal(tmp->new_cpus, cp->effective_cpus) && ++ (!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) || ++ (is_sched_load_balance(parent) == is_sched_load_balance(cp)))) { + pos_css = css_rightmost_descendant(pos_css); + continue; + } +@@ -1698,6 +1703,20 @@ update_parent_subparts: + + update_tasks_cpumask(cp, tmp->new_cpus); + ++ /* ++ * On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE ++ * from parent if current cpuset isn't a valid partition root ++ * and their load balance states differ. ++ */ ++ if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) && ++ !is_partition_valid(cp) && ++ (is_sched_load_balance(parent) != is_sched_load_balance(cp))) { ++ if (is_sched_load_balance(parent)) ++ set_bit(CS_SCHED_LOAD_BALANCE, &cp->flags); ++ else ++ clear_bit(CS_SCHED_LOAD_BALANCE, &cp->flags); ++ } ++ + /* + * On legacy hierarchy, if the effective cpumask of any non- + * empty cpuset is changed, we need to rebuild sched domains. +@@ -3245,6 +3264,14 @@ static int cpuset_css_online(struct cgroup_subsys_state *css) + cs->use_parent_ecpus = true; + parent->child_ecpus_count++; + } ++ ++ /* ++ * For v2, clear CS_SCHED_LOAD_BALANCE if parent is isolated ++ */ ++ if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) && ++ !is_sched_load_balance(parent)) ++ clear_bit(CS_SCHED_LOAD_BALANCE, &cs->flags); ++ + spin_unlock_irq(&callback_lock); + + if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags)) +diff --git a/kernel/cpu.c b/kernel/cpu.c +index f4a2c5845bcbd..20b3817cdf56c 100644 +--- a/kernel/cpu.c ++++ b/kernel/cpu.c +@@ -1215,8 +1215,22 @@ out: + return ret; + } + ++struct cpu_down_work { ++ unsigned int cpu; ++ enum cpuhp_state target; ++}; ++ ++static long __cpu_down_maps_locked(void *arg) ++{ ++ struct cpu_down_work *work = arg; ++ ++ return _cpu_down(work->cpu, 0, work->target); ++} ++ + static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target) + { ++ struct cpu_down_work work = { .cpu = cpu, .target = target, }; ++ + /* + * If the platform does not support hotplug, report it explicitly to + * differentiate it from a transient offlining failure. +@@ -1225,7 +1239,15 @@ static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target) + return -EOPNOTSUPP; + if (cpu_hotplug_disabled) + return -EBUSY; +- return _cpu_down(cpu, 0, target); ++ ++ /* ++ * Ensure that the control task does not run on the to be offlined ++ * CPU to prevent a deadlock against cfs_b->period_timer. ++ */ ++ cpu = cpumask_any_but(cpu_online_mask, cpu); ++ if (cpu >= nr_cpu_ids) ++ return -EBUSY; ++ return work_on_cpu(cpu, __cpu_down_maps_locked, &work); + } + + static int cpu_down(unsigned int cpu, enum cpuhp_state target) +diff --git a/kernel/kprobes.c b/kernel/kprobes.c +index 00e177de91ccd..3da9726232ff9 100644 +--- a/kernel/kprobes.c ++++ b/kernel/kprobes.c +@@ -1545,6 +1545,17 @@ static int check_ftrace_location(struct kprobe *p) + return 0; + } + ++static bool is_cfi_preamble_symbol(unsigned long addr) ++{ ++ char symbuf[KSYM_NAME_LEN]; ++ ++ if (lookup_symbol_name(addr, symbuf)) ++ return false; ++ ++ return str_has_prefix("__cfi_", symbuf) || ++ str_has_prefix("__pfx_", symbuf); ++} ++ + static int check_kprobe_address_safe(struct kprobe *p, + struct module **probed_mod) + { +@@ -1563,7 +1574,8 @@ static int check_kprobe_address_safe(struct kprobe *p, + within_kprobe_blacklist((unsigned long) p->addr) || + jump_label_text_reserved(p->addr, p->addr) || + static_call_text_reserved(p->addr, p->addr) || +- find_bug((unsigned long)p->addr)) { ++ find_bug((unsigned long)p->addr) || ++ is_cfi_preamble_symbol((unsigned long)p->addr)) { + ret = -EINVAL; + goto out; + } +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index 2dc4d5a1f1ff8..fde338606ce83 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1735,7 +1735,7 @@ static bool copy_data(struct prb_data_ring *data_ring, + if (!buf || !buf_size) + return true; + +- data_size = min_t(u16, buf_size, len); ++ data_size = min_t(unsigned int, buf_size, len); + + memcpy(&buf[0], data, data_size); /* LMM(copy_data:A) */ + return true; +diff --git a/kernel/rcu/refscale.c b/kernel/rcu/refscale.c +index 1970ce5f22d40..71d138573856f 100644 +--- a/kernel/rcu/refscale.c ++++ b/kernel/rcu/refscale.c +@@ -1107,12 +1107,11 @@ ref_scale_init(void) + VERBOSE_SCALEOUT("Starting %d reader threads", nreaders); + + for (i = 0; i < nreaders; i++) { ++ init_waitqueue_head(&reader_tasks[i].wq); + firsterr = torture_create_kthread(ref_scale_reader, (void *)i, + reader_tasks[i].task); + if (torture_init_error(firsterr)) + goto unwind; +- +- init_waitqueue_head(&(reader_tasks[i].wq)); + } + + // Main Task +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 00e0e50741153..185d3d749f6b6 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -25,7 +25,7 @@ unsigned int sysctl_sched_rt_period = 1000000; + int sysctl_sched_rt_runtime = 950000; + + #ifdef CONFIG_SYSCTL +-static int sysctl_sched_rr_timeslice = (MSEC_PER_SEC / HZ) * RR_TIMESLICE; ++static int sysctl_sched_rr_timeslice = (MSEC_PER_SEC * RR_TIMESLICE) / HZ; + static int sched_rt_handler(struct ctl_table *table, int write, void *buffer, + size_t *lenp, loff_t *ppos); + static int sched_rr_handler(struct ctl_table *table, int write, void *buffer, +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index 91836b727cef5..0600e16dbafef 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -473,8 +473,8 @@ static void clocksource_watchdog(struct timer_list *unused) + /* Check the deviation from the watchdog clocksource. */ + md = cs->uncertainty_margin + watchdog->uncertainty_margin; + if (abs(cs_nsec - wd_nsec) > md) { +- u64 cs_wd_msec; +- u64 wd_msec; ++ s64 cs_wd_msec; ++ s64 wd_msec; + u32 wd_rem; + + pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n", +@@ -483,8 +483,8 @@ static void clocksource_watchdog(struct timer_list *unused) + watchdog->name, wd_nsec, wdnow, wdlast, watchdog->mask); + pr_warn(" '%s' cs_nsec: %lld cs_now: %llx cs_last: %llx mask: %llx\n", + cs->name, cs_nsec, csnow, cslast, cs->mask); +- cs_wd_msec = div_u64_rem(cs_nsec - wd_nsec, 1000U * 1000U, &wd_rem); +- wd_msec = div_u64_rem(wd_nsec, 1000U * 1000U, &wd_rem); ++ cs_wd_msec = div_s64_rem(cs_nsec - wd_nsec, 1000 * 1000, &wd_rem); ++ wd_msec = div_s64_rem(wd_nsec, 1000 * 1000, &wd_rem); + pr_warn(" Clocksource '%s' skewed %lld ns (%lld ms) over watchdog '%s' interval of %lld ns (%lld ms)\n", + cs->name, cs_nsec - wd_nsec, cs_wd_msec, watchdog->name, wd_nsec, wd_msec); + if (curr_clocksource == cs) +diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c +index 4df14db4da490..87015e9deacc9 100644 +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -1045,7 +1045,7 @@ static bool report_idle_softirq(void) + return false; + + /* On RT, softirqs handling may be waiting on some lock */ +- if (!local_bh_blocked()) ++ if (local_bh_blocked()) + return false; + + pr_warn("NOHZ tick-stop error: local softirq work is pending, handler #%02x!!!\n", +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index a53524f3f7d82..3d8d5c383dfe5 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2391,7 +2391,7 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id, + #ifdef CONFIG_UPROBE_EVENTS + if (flags & TRACE_EVENT_FL_UPROBE) + err = bpf_get_uprobe_info(event, fd_type, buf, +- probe_offset, ++ probe_offset, probe_addr, + event->attr.type == PERF_TYPE_TRACEPOINT); + #endif + } +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index f4855be6ac2b5..146b1c8d7e449 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -6690,10 +6690,36 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf, + + #endif + ++static int open_pipe_on_cpu(struct trace_array *tr, int cpu) ++{ ++ if (cpu == RING_BUFFER_ALL_CPUS) { ++ if (cpumask_empty(tr->pipe_cpumask)) { ++ cpumask_setall(tr->pipe_cpumask); ++ return 0; ++ } ++ } else if (!cpumask_test_cpu(cpu, tr->pipe_cpumask)) { ++ cpumask_set_cpu(cpu, tr->pipe_cpumask); ++ return 0; ++ } ++ return -EBUSY; ++} ++ ++static void close_pipe_on_cpu(struct trace_array *tr, int cpu) ++{ ++ if (cpu == RING_BUFFER_ALL_CPUS) { ++ WARN_ON(!cpumask_full(tr->pipe_cpumask)); ++ cpumask_clear(tr->pipe_cpumask); ++ } else { ++ WARN_ON(!cpumask_test_cpu(cpu, tr->pipe_cpumask)); ++ cpumask_clear_cpu(cpu, tr->pipe_cpumask); ++ } ++} ++ + static int tracing_open_pipe(struct inode *inode, struct file *filp) + { + struct trace_array *tr = inode->i_private; + struct trace_iterator *iter; ++ int cpu; + int ret; + + ret = tracing_check_open_get_tr(tr); +@@ -6701,13 +6727,16 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) + return ret; + + mutex_lock(&trace_types_lock); ++ cpu = tracing_get_cpu(inode); ++ ret = open_pipe_on_cpu(tr, cpu); ++ if (ret) ++ goto fail_pipe_on_cpu; + + /* create a buffer to store the information to pass to userspace */ + iter = kzalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) { + ret = -ENOMEM; +- __trace_array_put(tr); +- goto out; ++ goto fail_alloc_iter; + } + + trace_seq_init(&iter->seq); +@@ -6730,7 +6759,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) + + iter->tr = tr; + iter->array_buffer = &tr->array_buffer; +- iter->cpu_file = tracing_get_cpu(inode); ++ iter->cpu_file = cpu; + mutex_init(&iter->mutex); + filp->private_data = iter; + +@@ -6740,12 +6769,15 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) + nonseekable_open(inode, filp); + + tr->trace_ref++; +-out: ++ + mutex_unlock(&trace_types_lock); + return ret; + + fail: + kfree(iter); ++fail_alloc_iter: ++ close_pipe_on_cpu(tr, cpu); ++fail_pipe_on_cpu: + __trace_array_put(tr); + mutex_unlock(&trace_types_lock); + return ret; +@@ -6762,7 +6794,7 @@ static int tracing_release_pipe(struct inode *inode, struct file *file) + + if (iter->trace->pipe_close) + iter->trace->pipe_close(iter); +- ++ close_pipe_on_cpu(tr, iter->cpu_file); + mutex_unlock(&trace_types_lock); + + free_cpumask_var(iter->started); +@@ -7558,6 +7590,11 @@ out: + return ret; + } + ++static void tracing_swap_cpu_buffer(void *tr) ++{ ++ update_max_tr_single((struct trace_array *)tr, current, smp_processor_id()); ++} ++ + static ssize_t + tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt, + loff_t *ppos) +@@ -7616,13 +7653,15 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt, + ret = tracing_alloc_snapshot_instance(tr); + if (ret < 0) + break; +- local_irq_disable(); + /* Now, we're going to swap */ +- if (iter->cpu_file == RING_BUFFER_ALL_CPUS) ++ if (iter->cpu_file == RING_BUFFER_ALL_CPUS) { ++ local_irq_disable(); + update_max_tr(tr, current, smp_processor_id(), NULL); +- else +- update_max_tr_single(tr, current, iter->cpu_file); +- local_irq_enable(); ++ local_irq_enable(); ++ } else { ++ smp_call_function_single(iter->cpu_file, tracing_swap_cpu_buffer, ++ (void *)tr, 1); ++ } + break; + default: + if (tr->allocated_snapshot) { +@@ -9426,6 +9465,9 @@ static struct trace_array *trace_array_create(const char *name) + if (!alloc_cpumask_var(&tr->tracing_cpumask, GFP_KERNEL)) + goto out_free_tr; + ++ if (!zalloc_cpumask_var(&tr->pipe_cpumask, GFP_KERNEL)) ++ goto out_free_tr; ++ + tr->trace_flags = global_trace.trace_flags & ~ZEROED_TRACE_FLAGS; + + cpumask_copy(tr->tracing_cpumask, cpu_all_mask); +@@ -9467,6 +9509,7 @@ static struct trace_array *trace_array_create(const char *name) + out_free_tr: + ftrace_free_ftrace_ops(tr); + free_trace_buffers(tr); ++ free_cpumask_var(tr->pipe_cpumask); + free_cpumask_var(tr->tracing_cpumask); + kfree(tr->name); + kfree(tr); +@@ -9569,6 +9612,7 @@ static int __remove_instance(struct trace_array *tr) + } + kfree(tr->topts); + ++ free_cpumask_var(tr->pipe_cpumask); + free_cpumask_var(tr->tracing_cpumask); + kfree(tr->name); + kfree(tr); +@@ -10366,12 +10410,14 @@ __init static int tracer_alloc_buffers(void) + if (trace_create_savedcmd() < 0) + goto out_free_temp_buffer; + ++ if (!zalloc_cpumask_var(&global_trace.pipe_cpumask, GFP_KERNEL)) ++ goto out_free_savedcmd; ++ + /* TODO: make the number of buffers hot pluggable with CPUS */ + if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) { + MEM_FAIL(1, "tracer: failed to allocate ring buffer!\n"); +- goto out_free_savedcmd; ++ goto out_free_pipe_cpumask; + } +- + if (global_trace.buffer_disabled) + tracing_off(); + +@@ -10424,6 +10470,8 @@ __init static int tracer_alloc_buffers(void) + + return 0; + ++out_free_pipe_cpumask: ++ free_cpumask_var(global_trace.pipe_cpumask); + out_free_savedcmd: + free_saved_cmdlines_buffer(savedcmd); + out_free_temp_buffer: +diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h +index 2daeac8e690a6..b577f65a63f11 100644 +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -366,6 +366,8 @@ struct trace_array { + struct list_head events; + struct trace_event_file *trace_marker_file; + cpumask_var_t tracing_cpumask; /* only trace on set CPUs */ ++ /* one per_cpu trace_pipe can be opened by only one user */ ++ cpumask_var_t pipe_cpumask; + int ref; + int trace_ref; + #ifdef CONFIG_FUNCTION_TRACER +diff --git a/kernel/trace/trace_hwlat.c b/kernel/trace/trace_hwlat.c +index 2f37a6e68aa9f..b791524a6536a 100644 +--- a/kernel/trace/trace_hwlat.c ++++ b/kernel/trace/trace_hwlat.c +@@ -635,7 +635,7 @@ static int s_mode_show(struct seq_file *s, void *v) + else + seq_printf(s, "%s", thread_mode_str[mode]); + +- if (mode != MODE_MAX) ++ if (mode < MODE_MAX - 1) /* if mode is any but last */ + seq_puts(s, " "); + + return 0; +diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c +index 7b47e9a2c0102..9173fcfc03820 100644 +--- a/kernel/trace/trace_uprobe.c ++++ b/kernel/trace/trace_uprobe.c +@@ -1416,7 +1416,7 @@ static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func, + + int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type, + const char **filename, u64 *probe_offset, +- bool perf_type_tracepoint) ++ u64 *probe_addr, bool perf_type_tracepoint) + { + const char *pevent = trace_event_name(event->tp_event); + const char *group = event->tp_event->class->system; +@@ -1433,6 +1433,7 @@ int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type, + : BPF_FD_TYPE_UPROBE; + *filename = tu->filename; + *probe_offset = tu->offset; ++ *probe_addr = 0; + return 0; + } + #endif /* CONFIG_PERF_EVENTS */ +diff --git a/lib/iov_iter.c b/lib/iov_iter.c +index 061cc3ed58f5b..dac0ec7b9436e 100644 +--- a/lib/iov_iter.c ++++ b/lib/iov_iter.c +@@ -2086,14 +2086,14 @@ static ssize_t iov_iter_extract_bvec_pages(struct iov_iter *i, + size_t *offset0) + { + struct page **p, *page; +- size_t skip = i->iov_offset, offset; ++ size_t skip = i->iov_offset, offset, size; + int k; + + for (;;) { + if (i->nr_segs == 0) + return 0; +- maxsize = min(maxsize, i->bvec->bv_len - skip); +- if (maxsize) ++ size = min(maxsize, i->bvec->bv_len - skip); ++ if (size) + break; + i->iov_offset = 0; + i->nr_segs--; +@@ -2106,16 +2106,16 @@ static ssize_t iov_iter_extract_bvec_pages(struct iov_iter *i, + offset = skip % PAGE_SIZE; + *offset0 = offset; + +- maxpages = want_pages_array(pages, maxsize, offset, maxpages); ++ maxpages = want_pages_array(pages, size, offset, maxpages); + if (!maxpages) + return -ENOMEM; + p = *pages; + for (k = 0; k < maxpages; k++) + p[k] = page + k; + +- maxsize = min_t(size_t, maxsize, maxpages * PAGE_SIZE - offset); +- iov_iter_advance(i, maxsize); +- return maxsize; ++ size = min_t(size_t, size, maxpages * PAGE_SIZE - offset); ++ iov_iter_advance(i, size); ++ return size; + } + + /* +@@ -2130,14 +2130,14 @@ static ssize_t iov_iter_extract_kvec_pages(struct iov_iter *i, + { + struct page **p, *page; + const void *kaddr; +- size_t skip = i->iov_offset, offset, len; ++ size_t skip = i->iov_offset, offset, len, size; + int k; + + for (;;) { + if (i->nr_segs == 0) + return 0; +- maxsize = min(maxsize, i->kvec->iov_len - skip); +- if (maxsize) ++ size = min(maxsize, i->kvec->iov_len - skip); ++ if (size) + break; + i->iov_offset = 0; + i->nr_segs--; +@@ -2149,13 +2149,13 @@ static ssize_t iov_iter_extract_kvec_pages(struct iov_iter *i, + offset = (unsigned long)kaddr & ~PAGE_MASK; + *offset0 = offset; + +- maxpages = want_pages_array(pages, maxsize, offset, maxpages); ++ maxpages = want_pages_array(pages, size, offset, maxpages); + if (!maxpages) + return -ENOMEM; + p = *pages; + + kaddr -= offset; +- len = offset + maxsize; ++ len = offset + size; + for (k = 0; k < maxpages; k++) { + size_t seg = min_t(size_t, len, PAGE_SIZE); + +@@ -2169,9 +2169,9 @@ static ssize_t iov_iter_extract_kvec_pages(struct iov_iter *i, + kaddr += PAGE_SIZE; + } + +- maxsize = min_t(size_t, maxsize, maxpages * PAGE_SIZE - offset); +- iov_iter_advance(i, maxsize); +- return maxsize; ++ size = min_t(size_t, size, maxpages * PAGE_SIZE - offset); ++ iov_iter_advance(i, size); ++ return size; + } + + /* +diff --git a/lib/sbitmap.c b/lib/sbitmap.c +index eff4e42c425a4..d0a5081dfd122 100644 +--- a/lib/sbitmap.c ++++ b/lib/sbitmap.c +@@ -550,7 +550,7 @@ EXPORT_SYMBOL_GPL(sbitmap_queue_min_shallow_depth); + + static void __sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr) + { +- int i, wake_index; ++ int i, wake_index, woken; + + if (!atomic_read(&sbq->ws_active)) + return; +@@ -567,13 +567,12 @@ static void __sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr) + */ + wake_index = sbq_index_inc(wake_index); + +- /* +- * It is sufficient to wake up at least one waiter to +- * guarantee forward progress. +- */ +- if (waitqueue_active(&ws->wait) && +- wake_up_nr(&ws->wait, nr)) +- break; ++ if (waitqueue_active(&ws->wait)) { ++ woken = wake_up_nr(&ws->wait, nr); ++ if (woken == nr) ++ break; ++ nr -= woken; ++ } + } + + if (wake_index != atomic_read(&sbq->wake_index)) +diff --git a/lib/xarray.c b/lib/xarray.c +index 2071a3718f4ed..142e36f9dfda1 100644 +--- a/lib/xarray.c ++++ b/lib/xarray.c +@@ -206,7 +206,7 @@ static void *xas_descend(struct xa_state *xas, struct xa_node *node) + void *entry = xa_entry(xas->xa, node, offset); + + xas->xa_node = node; +- if (xa_is_sibling(entry)) { ++ while (xa_is_sibling(entry)) { + offset = xa_to_sibling(entry); + entry = xa_entry(xas->xa, node, offset); + if (node->shift && xa_is_node(entry)) +diff --git a/mm/memfd.c b/mm/memfd.c +index e763e76f11064..d65485c762def 100644 +--- a/mm/memfd.c ++++ b/mm/memfd.c +@@ -268,11 +268,32 @@ long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg) + + #define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | MFD_NOEXEC_SEAL | MFD_EXEC) + ++static int check_sysctl_memfd_noexec(unsigned int *flags) ++{ ++#ifdef CONFIG_SYSCTL ++ int sysctl = task_active_pid_ns(current)->memfd_noexec_scope; ++ ++ if (!(*flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) { ++ if (sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL) ++ *flags |= MFD_NOEXEC_SEAL; ++ else ++ *flags |= MFD_EXEC; ++ } ++ ++ if (!(*flags & MFD_NOEXEC_SEAL) && sysctl >= MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED) { ++ pr_err_ratelimited( ++ "%s[%d]: memfd_create() requires MFD_NOEXEC_SEAL with vm.memfd_noexec=%d\n", ++ current->comm, task_pid_nr(current), sysctl); ++ return -EACCES; ++ } ++#endif ++ return 0; ++} ++ + SYSCALL_DEFINE2(memfd_create, + const char __user *, uname, + unsigned int, flags) + { +- char comm[TASK_COMM_LEN]; + unsigned int *file_seals; + struct file *file; + int fd, error; +@@ -294,35 +315,15 @@ SYSCALL_DEFINE2(memfd_create, + return -EINVAL; + + if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) { +-#ifdef CONFIG_SYSCTL +- int sysctl = MEMFD_NOEXEC_SCOPE_EXEC; +- struct pid_namespace *ns; +- +- ns = task_active_pid_ns(current); +- if (ns) +- sysctl = ns->memfd_noexec_scope; +- +- switch (sysctl) { +- case MEMFD_NOEXEC_SCOPE_EXEC: +- flags |= MFD_EXEC; +- break; +- case MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL: +- flags |= MFD_NOEXEC_SEAL; +- break; +- default: +- pr_warn_once( +- "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n", +- task_pid_nr(current), get_task_comm(comm, current)); +- return -EINVAL; +- } +-#else +- flags |= MFD_EXEC; +-#endif + pr_warn_once( +- "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n", +- task_pid_nr(current), get_task_comm(comm, current)); ++ "%s[%d]: memfd_create() called without MFD_EXEC or MFD_NOEXEC_SEAL set\n", ++ current->comm, task_pid_nr(current)); + } + ++ error = check_sysctl_memfd_noexec(&flags); ++ if (error < 0) ++ return error; ++ + /* length includes terminating zero */ + len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1); + if (len <= 0) +diff --git a/mm/shmem.c b/mm/shmem.c +index fe208a072e594..87cc98a9a014a 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -3506,6 +3506,8 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) + unsigned long long size; + char *rest; + int opt; ++ kuid_t kuid; ++ kgid_t kgid; + + opt = fs_parse(fc, shmem_fs_parameters, param, &result); + if (opt < 0) +@@ -3541,14 +3543,32 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) + ctx->mode = result.uint_32 & 07777; + break; + case Opt_uid: +- ctx->uid = make_kuid(current_user_ns(), result.uint_32); +- if (!uid_valid(ctx->uid)) ++ kuid = make_kuid(current_user_ns(), result.uint_32); ++ if (!uid_valid(kuid)) + goto bad_value; ++ ++ /* ++ * The requested uid must be representable in the ++ * filesystem's idmapping. ++ */ ++ if (!kuid_has_mapping(fc->user_ns, kuid)) ++ goto bad_value; ++ ++ ctx->uid = kuid; + break; + case Opt_gid: +- ctx->gid = make_kgid(current_user_ns(), result.uint_32); +- if (!gid_valid(ctx->gid)) ++ kgid = make_kgid(current_user_ns(), result.uint_32); ++ if (!gid_valid(kgid)) + goto bad_value; ++ ++ /* ++ * The requested gid must be representable in the ++ * filesystem's idmapping. ++ */ ++ if (!kgid_has_mapping(fc->user_ns, kgid)) ++ goto bad_value; ++ ++ ctx->gid = kgid; + break; + case Opt_huge: + ctx->huge = result.uint_32; +diff --git a/mm/util.c b/mm/util.c +index dd12b9531ac4c..406634f26918c 100644 +--- a/mm/util.c ++++ b/mm/util.c +@@ -1071,7 +1071,9 @@ void mem_dump_obj(void *object) + if (vmalloc_dump_obj(object)) + return; + +- if (virt_addr_valid(object)) ++ if (is_vmalloc_addr(object)) ++ type = "vmalloc memory"; ++ else if (virt_addr_valid(object)) + type = "non-slab/vmalloc memory"; + else if (object == NULL) + type = "NULL pointer"; +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 73a0077ee3afc..d78dfb071f89d 100644 +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -4228,14 +4228,32 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms) + #ifdef CONFIG_PRINTK + bool vmalloc_dump_obj(void *object) + { +- struct vm_struct *vm; + void *objp = (void *)PAGE_ALIGN((unsigned long)object); ++ const void *caller; ++ struct vm_struct *vm; ++ struct vmap_area *va; ++ unsigned long addr; ++ unsigned int nr_pages; + +- vm = find_vm_area(objp); +- if (!vm) ++ if (!spin_trylock(&vmap_area_lock)) ++ return false; ++ va = __find_vmap_area((unsigned long)objp, &vmap_area_root); ++ if (!va) { ++ spin_unlock(&vmap_area_lock); + return false; ++ } ++ ++ vm = va->vm; ++ if (!vm) { ++ spin_unlock(&vmap_area_lock); ++ return false; ++ } ++ addr = (unsigned long)vm->addr; ++ caller = vm->caller; ++ nr_pages = vm->nr_pages; ++ spin_unlock(&vmap_area_lock); + pr_cont(" %u-page vmalloc region starting at %#lx allocated at %pS\n", +- vm->nr_pages, (unsigned long)vm->addr, vm->caller); ++ nr_pages, addr, caller); + return true; + } + #endif +diff --git a/mm/vmpressure.c b/mm/vmpressure.c +index b52644771cc43..22c6689d93027 100644 +--- a/mm/vmpressure.c ++++ b/mm/vmpressure.c +@@ -244,6 +244,14 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree, + if (mem_cgroup_disabled()) + return; + ++ /* ++ * The in-kernel users only care about the reclaim efficiency ++ * for this @memcg rather than the whole subtree, and there ++ * isn't and won't be any in-kernel user in a legacy cgroup. ++ */ ++ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && !tree) ++ return; ++ + vmpr = memcg_to_vmpressure(memcg); + + /* +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 7ff3389c677f9..caf17b7c1b9f0 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4853,7 +4853,8 @@ static int lru_gen_memcg_seg(struct lruvec *lruvec) + * the eviction + ******************************************************************************/ + +-static bool sort_folio(struct lruvec *lruvec, struct folio *folio, int tier_idx) ++static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_control *sc, ++ int tier_idx) + { + bool success; + int gen = folio_lru_gen(folio); +@@ -4904,6 +4905,13 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, int tier_idx) + return true; + } + ++ /* ineligible */ ++ if (zone > sc->reclaim_idx) { ++ gen = folio_inc_gen(lruvec, folio, false); ++ list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]); ++ return true; ++ } ++ + /* waiting for writeback */ + if (folio_test_locked(folio) || folio_test_writeback(folio) || + (type == LRU_GEN_FILE && folio_test_dirty(folio))) { +@@ -4952,7 +4960,8 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca + static int scan_folios(struct lruvec *lruvec, struct scan_control *sc, + int type, int tier, struct list_head *list) + { +- int gen, zone; ++ int i; ++ int gen; + enum vm_event_item item; + int sorted = 0; + int scanned = 0; +@@ -4968,9 +4977,10 @@ static int scan_folios(struct lruvec *lruvec, struct scan_control *sc, + + gen = lru_gen_from_seq(lrugen->min_seq[type]); + +- for (zone = sc->reclaim_idx; zone >= 0; zone--) { ++ for (i = MAX_NR_ZONES; i > 0; i--) { + LIST_HEAD(moved); + int skipped = 0; ++ int zone = (sc->reclaim_idx + i) % MAX_NR_ZONES; + struct list_head *head = &lrugen->folios[gen][type][zone]; + + while (!list_empty(head)) { +@@ -4984,7 +4994,7 @@ static int scan_folios(struct lruvec *lruvec, struct scan_control *sc, + + scanned += delta; + +- if (sort_folio(lruvec, folio, tier)) ++ if (sort_folio(lruvec, folio, sc, tier)) + sorted += delta; + else if (isolate_folio(lruvec, folio, sc)) { + list_add(&folio->lru, list); +diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c +index 3c27ffb781e3e..f3f6782894239 100644 +--- a/net/9p/trans_virtio.c ++++ b/net/9p/trans_virtio.c +@@ -384,7 +384,7 @@ static void handle_rerror(struct p9_req_t *req, int in_hdr_len, + void *to = req->rc.sdata + in_hdr_len; + + // Fits entirely into the static data? Nothing to do. +- if (req->rc.size < in_hdr_len) ++ if (req->rc.size < in_hdr_len || !pages) + return; + + // Really long error message? Tough, truncate the reply. Might get +@@ -428,7 +428,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, + struct page **in_pages = NULL, **out_pages = NULL; + struct virtio_chan *chan = client->trans; + struct scatterlist *sgs[4]; +- size_t offs; ++ size_t offs = 0; + int need_drop = 0; + int kicked = 0; + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index 31c115b225e7e..eb2802ef34bfe 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -178,57 +178,6 @@ static void hci_conn_cleanup(struct hci_conn *conn) + hci_conn_put(conn); + } + +-static void le_scan_cleanup(struct work_struct *work) +-{ +- struct hci_conn *conn = container_of(work, struct hci_conn, +- le_scan_cleanup); +- struct hci_dev *hdev = conn->hdev; +- struct hci_conn *c = NULL; +- +- BT_DBG("%s hcon %p", hdev->name, conn); +- +- hci_dev_lock(hdev); +- +- /* Check that the hci_conn is still around */ +- rcu_read_lock(); +- list_for_each_entry_rcu(c, &hdev->conn_hash.list, list) { +- if (c == conn) +- break; +- } +- rcu_read_unlock(); +- +- if (c == conn) { +- hci_connect_le_scan_cleanup(conn, 0x00); +- hci_conn_cleanup(conn); +- } +- +- hci_dev_unlock(hdev); +- hci_dev_put(hdev); +- hci_conn_put(conn); +-} +- +-static void hci_connect_le_scan_remove(struct hci_conn *conn) +-{ +- BT_DBG("%s hcon %p", conn->hdev->name, conn); +- +- /* We can't call hci_conn_del/hci_conn_cleanup here since that +- * could deadlock with another hci_conn_del() call that's holding +- * hci_dev_lock and doing cancel_delayed_work_sync(&conn->disc_work). +- * Instead, grab temporary extra references to the hci_dev and +- * hci_conn and perform the necessary cleanup in a separate work +- * callback. +- */ +- +- hci_dev_hold(conn->hdev); +- hci_conn_get(conn); +- +- /* Even though we hold a reference to the hdev, many other +- * things might get cleaned up meanwhile, including the hdev's +- * own workqueue, so we can't use that for scheduling. +- */ +- schedule_work(&conn->le_scan_cleanup); +-} +- + static void hci_acl_create_connection(struct hci_conn *conn) + { + struct hci_dev *hdev = conn->hdev; +@@ -679,13 +628,6 @@ static void hci_conn_timeout(struct work_struct *work) + if (refcnt > 0) + return; + +- /* LE connections in scanning state need special handling */ +- if (conn->state == BT_CONNECT && conn->type == LE_LINK && +- test_bit(HCI_CONN_SCANNING, &conn->flags)) { +- hci_connect_le_scan_remove(conn); +- return; +- } +- + hci_abort_conn(conn, hci_proto_disconn_ind(conn)); + } + +@@ -791,7 +733,8 @@ struct iso_list_data { + u16 sync_handle; + }; + int count; +- struct iso_cig_params pdu; ++ bool big_term; ++ bool big_sync_term; + }; + + static void bis_list(struct hci_conn *conn, void *data) +@@ -809,17 +752,6 @@ static void bis_list(struct hci_conn *conn, void *data) + d->count++; + } + +-static void find_bis(struct hci_conn *conn, void *data) +-{ +- struct iso_list_data *d = data; +- +- /* Ignore unicast */ +- if (bacmp(&conn->dst, BDADDR_ANY)) +- return; +- +- d->count++; +-} +- + static int terminate_big_sync(struct hci_dev *hdev, void *data) + { + struct iso_list_data *d = data; +@@ -828,11 +760,8 @@ static int terminate_big_sync(struct hci_dev *hdev, void *data) + + hci_remove_ext_adv_instance_sync(hdev, d->bis, NULL); + +- /* Check if ISO connection is a BIS and terminate BIG if there are +- * no other connections using it. +- */ +- hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d); +- if (d->count) ++ /* Only terminate BIG if it has been created */ ++ if (!d->big_term) + return 0; + + return hci_le_terminate_big_sync(hdev, d->big, +@@ -844,19 +773,21 @@ static void terminate_big_destroy(struct hci_dev *hdev, void *data, int err) + kfree(data); + } + +-static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis) ++static int hci_le_terminate_big(struct hci_dev *hdev, struct hci_conn *conn) + { + struct iso_list_data *d; + int ret; + +- bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", big, bis); ++ bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", conn->iso_qos.bcast.big, ++ conn->iso_qos.bcast.bis); + + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + +- d->big = big; +- d->bis = bis; ++ d->big = conn->iso_qos.bcast.big; ++ d->bis = conn->iso_qos.bcast.bis; ++ d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, &conn->flags); + + ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d, + terminate_big_destroy); +@@ -873,31 +804,26 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data) + bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", d->big, + d->sync_handle); + +- /* Check if ISO connection is a BIS and terminate BIG if there are +- * no other connections using it. +- */ +- hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d); +- if (d->count) +- return 0; +- +- hci_le_big_terminate_sync(hdev, d->big); ++ if (d->big_sync_term) ++ hci_le_big_terminate_sync(hdev, d->big); + + return hci_le_pa_terminate_sync(hdev, d->sync_handle); + } + +-static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle) ++static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn) + { + struct iso_list_data *d; + int ret; + +- bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle); ++ bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle); + + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->big = big; +- d->sync_handle = sync_handle; ++ d->sync_handle = conn->sync_handle; ++ d->big_sync_term = test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags); + + ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d, + terminate_big_destroy); +@@ -916,6 +842,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle) + static void bis_cleanup(struct hci_conn *conn) + { + struct hci_dev *hdev = conn->hdev; ++ struct hci_conn *bis; + + bt_dev_dbg(hdev, "conn %p", conn); + +@@ -923,11 +850,25 @@ static void bis_cleanup(struct hci_conn *conn) + if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags)) + return; + +- hci_le_terminate_big(hdev, conn->iso_qos.bcast.big, +- conn->iso_qos.bcast.bis); ++ /* Check if ISO connection is a BIS and terminate advertising ++ * set and BIG if there are no other connections using it. ++ */ ++ bis = hci_conn_hash_lookup_bis(hdev, BDADDR_ANY, ++ conn->iso_qos.bcast.big, ++ conn->iso_qos.bcast.bis); ++ if (bis) ++ return; ++ ++ hci_le_terminate_big(hdev, conn); + } else { ++ bis = hci_conn_hash_lookup_big_any_dst(hdev, ++ conn->iso_qos.bcast.big); ++ ++ if (bis) ++ return; ++ + hci_le_big_terminate(hdev, conn->iso_qos.bcast.big, +- conn->sync_handle); ++ conn); + } + } + +@@ -983,6 +924,25 @@ static void cis_cleanup(struct hci_conn *conn) + hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig); + } + ++static u16 hci_conn_hash_alloc_unset(struct hci_dev *hdev) ++{ ++ struct hci_conn_hash *h = &hdev->conn_hash; ++ struct hci_conn *c; ++ u16 handle = HCI_CONN_HANDLE_MAX + 1; ++ ++ rcu_read_lock(); ++ ++ list_for_each_entry_rcu(c, &h->list, list) { ++ /* Find the first unused handle */ ++ if (handle == 0xffff || c->handle != handle) ++ break; ++ handle++; ++ } ++ rcu_read_unlock(); ++ ++ return handle; ++} ++ + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + u8 role) + { +@@ -996,7 +956,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + + bacpy(&conn->dst, dst); + bacpy(&conn->src, &hdev->bdaddr); +- conn->handle = HCI_CONN_HANDLE_UNSET; ++ conn->handle = hci_conn_hash_alloc_unset(hdev); + conn->hdev = hdev; + conn->type = type; + conn->role = role; +@@ -1059,7 +1019,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept); + INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle); + INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout); +- INIT_WORK(&conn->le_scan_cleanup, le_scan_cleanup); + + atomic_set(&conn->refcnt, 0); + +@@ -1081,6 +1040,29 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + return conn; + } + ++static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason) ++{ ++ if (!reason) ++ reason = HCI_ERROR_REMOTE_USER_TERM; ++ ++ /* Due to race, SCO/ISO conn might be not established yet at this point, ++ * and nothing else will clean it up. In other cases it is done via HCI ++ * events. ++ */ ++ switch (conn->type) { ++ case SCO_LINK: ++ case ESCO_LINK: ++ if (HCI_CONN_HANDLE_UNSET(conn->handle)) ++ hci_conn_failed(conn, reason); ++ break; ++ case ISO_LINK: ++ if (conn->state != BT_CONNECTED && ++ !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ++ hci_conn_failed(conn, reason); ++ break; ++ } ++} ++ + static void hci_conn_unlink(struct hci_conn *conn) + { + struct hci_dev *hdev = conn->hdev; +@@ -1103,14 +1085,7 @@ static void hci_conn_unlink(struct hci_conn *conn) + if (!test_bit(HCI_UP, &hdev->flags)) + continue; + +- /* Due to race, SCO connection might be not established +- * yet at this point. Delete it now, otherwise it is +- * possible for it to be stuck and can't be deleted. +- */ +- if ((child->type == SCO_LINK || +- child->type == ESCO_LINK) && +- child->handle == HCI_CONN_HANDLE_UNSET) +- hci_conn_del(child); ++ hci_conn_cleanup_child(child, conn->abort_reason); + } + + return; +@@ -1495,10 +1470,10 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos) + + /* This function requires the caller holds hdev->lock */ + static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, +- struct bt_iso_qos *qos) ++ struct bt_iso_qos *qos, __u8 base_len, ++ __u8 *base) + { + struct hci_conn *conn; +- struct iso_list_data data; + int err; + + /* Let's make sure that le is enabled.*/ +@@ -1516,24 +1491,27 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, + if (err) + return ERR_PTR(err); + +- data.big = qos->bcast.big; +- data.bis = qos->bcast.bis; +- data.count = 0; +- +- /* Check if there is already a matching BIG/BIS */ +- hci_conn_hash_list_state(hdev, bis_list, ISO_LINK, BT_BOUND, &data); +- if (data.count) ++ /* Check if the LE Create BIG command has already been sent */ ++ conn = hci_conn_hash_lookup_per_adv_bis(hdev, dst, qos->bcast.big, ++ qos->bcast.big); ++ if (conn) + return ERR_PTR(-EADDRINUSE); + +- conn = hci_conn_hash_lookup_bis(hdev, dst, qos->bcast.big, qos->bcast.bis); +- if (conn) ++ /* Check BIS settings against other bound BISes, since all ++ * BISes in a BIG must have the same value for all parameters ++ */ ++ conn = hci_conn_hash_lookup_bis(hdev, dst, qos->bcast.big, ++ qos->bcast.bis); ++ ++ if (conn && (memcmp(qos, &conn->iso_qos, sizeof(*qos)) || ++ base_len != conn->le_per_adv_data_len || ++ memcmp(conn->le_per_adv_data, base, base_len))) + return ERR_PTR(-EADDRINUSE); + + conn = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); + if (!conn) + return ERR_PTR(-ENOMEM); + +- set_bit(HCI_CONN_PER_ADV, &conn->flags); + conn->state = BT_CONNECT; + + hci_conn_hold(conn); +@@ -1707,52 +1685,25 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, + return sco; + } + +-static void cis_add(struct iso_list_data *d, struct bt_iso_qos *qos) +-{ +- struct hci_cis_params *cis = &d->pdu.cis[d->pdu.cp.num_cis]; +- +- cis->cis_id = qos->ucast.cis; +- cis->c_sdu = cpu_to_le16(qos->ucast.out.sdu); +- cis->p_sdu = cpu_to_le16(qos->ucast.in.sdu); +- cis->c_phy = qos->ucast.out.phy ? qos->ucast.out.phy : qos->ucast.in.phy; +- cis->p_phy = qos->ucast.in.phy ? qos->ucast.in.phy : qos->ucast.out.phy; +- cis->c_rtn = qos->ucast.out.rtn; +- cis->p_rtn = qos->ucast.in.rtn; +- +- d->pdu.cp.num_cis++; +-} +- +-static void cis_list(struct hci_conn *conn, void *data) +-{ +- struct iso_list_data *d = data; +- +- /* Skip if broadcast/ANY address */ +- if (!bacmp(&conn->dst, BDADDR_ANY)) +- return; +- +- if (d->cig != conn->iso_qos.ucast.cig || d->cis == BT_ISO_QOS_CIS_UNSET || +- d->cis != conn->iso_qos.ucast.cis) +- return; +- +- d->count++; +- +- if (d->pdu.cp.cig_id == BT_ISO_QOS_CIG_UNSET || +- d->count >= ARRAY_SIZE(d->pdu.cis)) +- return; +- +- cis_add(d, &conn->iso_qos); +-} +- + static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos) + { + struct hci_dev *hdev = conn->hdev; + struct hci_cp_le_create_big cp; ++ struct iso_list_data data; + + memset(&cp, 0, sizeof(cp)); + ++ data.big = qos->bcast.big; ++ data.bis = qos->bcast.bis; ++ data.count = 0; ++ ++ /* Create a BIS for each bound connection */ ++ hci_conn_hash_list_state(hdev, bis_list, ISO_LINK, ++ BT_BOUND, &data); ++ + cp.handle = qos->bcast.big; + cp.adv_handle = qos->bcast.bis; +- cp.num_bis = 0x01; ++ cp.num_bis = data.count; + hci_cpu_to_le24(qos->bcast.out.interval, cp.bis.sdu_interval); + cp.bis.sdu = cpu_to_le16(qos->bcast.out.sdu); + cp.bis.latency = cpu_to_le16(qos->bcast.out.latency); +@@ -1766,25 +1717,62 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos) + return hci_send_cmd(hdev, HCI_OP_LE_CREATE_BIG, sizeof(cp), &cp); + } + +-static void set_cig_params_complete(struct hci_dev *hdev, void *data, int err) ++static int set_cig_params_sync(struct hci_dev *hdev, void *data) + { +- struct iso_cig_params *pdu = data; ++ u8 cig_id = PTR_ERR(data); ++ struct hci_conn *conn; ++ struct bt_iso_qos *qos; ++ struct iso_cig_params pdu; ++ u8 cis_id; + +- bt_dev_dbg(hdev, ""); ++ conn = hci_conn_hash_lookup_cig(hdev, cig_id); ++ if (!conn) ++ return 0; + +- if (err) +- bt_dev_err(hdev, "Unable to set CIG parameters: %d", err); ++ memset(&pdu, 0, sizeof(pdu)); + +- kfree(pdu); +-} ++ qos = &conn->iso_qos; ++ pdu.cp.cig_id = cig_id; ++ hci_cpu_to_le24(qos->ucast.out.interval, pdu.cp.c_interval); ++ hci_cpu_to_le24(qos->ucast.in.interval, pdu.cp.p_interval); ++ pdu.cp.sca = qos->ucast.sca; ++ pdu.cp.packing = qos->ucast.packing; ++ pdu.cp.framing = qos->ucast.framing; ++ pdu.cp.c_latency = cpu_to_le16(qos->ucast.out.latency); ++ pdu.cp.p_latency = cpu_to_le16(qos->ucast.in.latency); ++ ++ /* Reprogram all CIS(s) with the same CIG, valid range are: ++ * num_cis: 0x00 to 0x1F ++ * cis_id: 0x00 to 0xEF ++ */ ++ for (cis_id = 0x00; cis_id < 0xf0 && ++ pdu.cp.num_cis < ARRAY_SIZE(pdu.cis); cis_id++) { ++ struct hci_cis_params *cis; + +-static int set_cig_params_sync(struct hci_dev *hdev, void *data) +-{ +- struct iso_cig_params *pdu = data; +- u32 plen; ++ conn = hci_conn_hash_lookup_cis(hdev, NULL, 0, cig_id, cis_id); ++ if (!conn) ++ continue; ++ ++ qos = &conn->iso_qos; ++ ++ cis = &pdu.cis[pdu.cp.num_cis++]; ++ cis->cis_id = cis_id; ++ cis->c_sdu = cpu_to_le16(conn->iso_qos.ucast.out.sdu); ++ cis->p_sdu = cpu_to_le16(conn->iso_qos.ucast.in.sdu); ++ cis->c_phy = qos->ucast.out.phy ? qos->ucast.out.phy : ++ qos->ucast.in.phy; ++ cis->p_phy = qos->ucast.in.phy ? qos->ucast.in.phy : ++ qos->ucast.out.phy; ++ cis->c_rtn = qos->ucast.out.rtn; ++ cis->p_rtn = qos->ucast.in.rtn; ++ } ++ ++ if (!pdu.cp.num_cis) ++ return 0; + +- plen = sizeof(pdu->cp) + pdu->cp.num_cis * sizeof(pdu->cis[0]); +- return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_CIG_PARAMS, plen, pdu, ++ return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_CIG_PARAMS, ++ sizeof(pdu.cp) + ++ pdu.cp.num_cis * sizeof(pdu.cis[0]), &pdu, + HCI_CMD_TIMEOUT); + } + +@@ -1792,7 +1780,6 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) + { + struct hci_dev *hdev = conn->hdev; + struct iso_list_data data; +- struct iso_cig_params *pdu; + + memset(&data, 0, sizeof(data)); + +@@ -1819,60 +1806,31 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) + qos->ucast.cig = data.cig; + } + +- data.pdu.cp.cig_id = qos->ucast.cig; +- hci_cpu_to_le24(qos->ucast.out.interval, data.pdu.cp.c_interval); +- hci_cpu_to_le24(qos->ucast.in.interval, data.pdu.cp.p_interval); +- data.pdu.cp.sca = qos->ucast.sca; +- data.pdu.cp.packing = qos->ucast.packing; +- data.pdu.cp.framing = qos->ucast.framing; +- data.pdu.cp.c_latency = cpu_to_le16(qos->ucast.out.latency); +- data.pdu.cp.p_latency = cpu_to_le16(qos->ucast.in.latency); +- + if (qos->ucast.cis != BT_ISO_QOS_CIS_UNSET) { +- data.count = 0; +- data.cig = qos->ucast.cig; +- data.cis = qos->ucast.cis; +- +- hci_conn_hash_list_state(hdev, cis_list, ISO_LINK, BT_BOUND, +- &data); +- if (data.count) ++ if (hci_conn_hash_lookup_cis(hdev, NULL, 0, qos->ucast.cig, ++ qos->ucast.cis)) + return false; +- +- cis_add(&data, qos); ++ goto done; + } + +- /* Reprogram all CIS(s) with the same CIG */ +- for (data.cig = qos->ucast.cig, data.cis = 0x00; data.cis < 0x11; ++ /* Allocate first available CIS if not set */ ++ for (data.cig = qos->ucast.cig, data.cis = 0x00; data.cis < 0xf0; + data.cis++) { +- data.count = 0; +- +- hci_conn_hash_list_state(hdev, cis_list, ISO_LINK, BT_BOUND, +- &data); +- if (data.count) +- continue; +- +- /* Allocate a CIS if not set */ +- if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET) { ++ if (!hci_conn_hash_lookup_cis(hdev, NULL, 0, data.cig, ++ data.cis)) { + /* Update CIS */ + qos->ucast.cis = data.cis; +- cis_add(&data, qos); ++ break; + } + } + +- if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET || !data.pdu.cp.num_cis) +- return false; +- +- pdu = kzalloc(sizeof(*pdu), GFP_KERNEL); +- if (!pdu) ++ if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET) + return false; + +- memcpy(pdu, &data.pdu, sizeof(*pdu)); +- +- if (hci_cmd_sync_queue(hdev, set_cig_params_sync, pdu, +- set_cig_params_complete) < 0) { +- kfree(pdu); ++done: ++ if (hci_cmd_sync_queue(hdev, set_cig_params_sync, ++ ERR_PTR(qos->ucast.cig), NULL) < 0) + return false; +- } + + return true; + } +@@ -1971,59 +1929,47 @@ bool hci_iso_setup_path(struct hci_conn *conn) + return true; + } + +-static int hci_create_cis_sync(struct hci_dev *hdev, void *data) ++int hci_conn_check_create_cis(struct hci_conn *conn) + { +- return hci_le_create_cis_sync(hdev, data); +-} ++ if (conn->type != ISO_LINK || !bacmp(&conn->dst, BDADDR_ANY)) ++ return -EINVAL; + +-int hci_le_create_cis(struct hci_conn *conn) +-{ +- struct hci_conn *cis; +- struct hci_link *link, *t; +- struct hci_dev *hdev = conn->hdev; +- int err; ++ if (!conn->parent || conn->parent->state != BT_CONNECTED || ++ conn->state != BT_CONNECT || HCI_CONN_HANDLE_UNSET(conn->handle)) ++ return 1; + +- bt_dev_dbg(hdev, "hcon %p", conn); ++ return 0; ++} + +- switch (conn->type) { +- case LE_LINK: +- if (conn->state != BT_CONNECTED || list_empty(&conn->link_list)) +- return -EINVAL; ++static int hci_create_cis_sync(struct hci_dev *hdev, void *data) ++{ ++ return hci_le_create_cis_sync(hdev); ++} + +- cis = NULL; ++int hci_le_create_cis_pending(struct hci_dev *hdev) ++{ ++ struct hci_conn *conn; ++ bool pending = false; + +- /* hci_conn_link uses list_add_tail_rcu so the list is in +- * the same order as the connections are requested. +- */ +- list_for_each_entry_safe(link, t, &conn->link_list, list) { +- if (link->conn->state == BT_BOUND) { +- err = hci_le_create_cis(link->conn); +- if (err) +- return err; ++ rcu_read_lock(); + +- cis = link->conn; +- } ++ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { ++ if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) { ++ rcu_read_unlock(); ++ return -EBUSY; + } + +- return cis ? 0 : -EINVAL; +- case ISO_LINK: +- cis = conn; +- break; +- default: +- return -EINVAL; ++ if (!hci_conn_check_create_cis(conn)) ++ pending = true; + } + +- if (cis->state == BT_CONNECT) ++ rcu_read_unlock(); ++ ++ if (!pending) + return 0; + + /* Queue Create CIS */ +- err = hci_cmd_sync_queue(hdev, hci_create_cis_sync, cis, NULL); +- if (err) +- return err; +- +- cis->state = BT_CONNECT; +- +- return 0; ++ return hci_cmd_sync_queue(hdev, hci_create_cis_sync, NULL, NULL); + } + + static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, +@@ -2053,16 +1999,6 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, + qos->latency = conn->le_conn_latency; + } + +-static void hci_bind_bis(struct hci_conn *conn, +- struct bt_iso_qos *qos) +-{ +- /* Update LINK PHYs according to QoS preference */ +- conn->le_tx_phy = qos->bcast.out.phy; +- conn->le_tx_phy = qos->bcast.out.phy; +- conn->iso_qos = *qos; +- conn->state = BT_BOUND; +-} +- + static int create_big_sync(struct hci_dev *hdev, void *data) + { + struct hci_conn *conn = data; +@@ -2185,27 +2121,80 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) + } + } + +-struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, +- __u8 dst_type, struct bt_iso_qos *qos, +- __u8 base_len, __u8 *base) ++struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, ++ struct bt_iso_qos *qos, ++ __u8 base_len, __u8 *base) + { + struct hci_conn *conn; +- int err; ++ __u8 eir[HCI_MAX_PER_AD_LENGTH]; ++ ++ if (base_len && base) ++ base_len = eir_append_service_data(eir, 0, 0x1851, ++ base, base_len); + + /* We need hci_conn object using the BDADDR_ANY as dst */ +- conn = hci_add_bis(hdev, dst, qos); ++ conn = hci_add_bis(hdev, dst, qos, base_len, eir); + if (IS_ERR(conn)) + return conn; + +- hci_bind_bis(conn, qos); ++ /* Update LINK PHYs according to QoS preference */ ++ conn->le_tx_phy = qos->bcast.out.phy; ++ conn->le_tx_phy = qos->bcast.out.phy; + + /* Add Basic Announcement into Peridic Adv Data if BASE is set */ + if (base_len && base) { +- base_len = eir_append_service_data(conn->le_per_adv_data, 0, +- 0x1851, base, base_len); ++ memcpy(conn->le_per_adv_data, eir, sizeof(eir)); + conn->le_per_adv_data_len = base_len; + } + ++ hci_iso_qos_setup(hdev, conn, &qos->bcast.out, ++ conn->le_tx_phy ? conn->le_tx_phy : ++ hdev->le_tx_def_phys); ++ ++ conn->iso_qos = *qos; ++ conn->state = BT_BOUND; ++ ++ return conn; ++} ++ ++static void bis_mark_per_adv(struct hci_conn *conn, void *data) ++{ ++ struct iso_list_data *d = data; ++ ++ /* Skip if not broadcast/ANY address */ ++ if (bacmp(&conn->dst, BDADDR_ANY)) ++ return; ++ ++ if (d->big != conn->iso_qos.bcast.big || ++ d->bis == BT_ISO_QOS_BIS_UNSET || ++ d->bis != conn->iso_qos.bcast.bis) ++ return; ++ ++ set_bit(HCI_CONN_PER_ADV, &conn->flags); ++} ++ ++struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, ++ __u8 dst_type, struct bt_iso_qos *qos, ++ __u8 base_len, __u8 *base) ++{ ++ struct hci_conn *conn; ++ int err; ++ struct iso_list_data data; ++ ++ conn = hci_bind_bis(hdev, dst, qos, base_len, base); ++ if (IS_ERR(conn)) ++ return conn; ++ ++ data.big = qos->bcast.big; ++ data.bis = qos->bcast.bis; ++ ++ /* Set HCI_CONN_PER_ADV for all bound connections, to mark that ++ * the start periodic advertising and create BIG commands have ++ * been queued ++ */ ++ hci_conn_hash_list_state(hdev, bis_mark_per_adv, ISO_LINK, ++ BT_BOUND, &data); ++ + /* Queue start periodic advertising and create BIG */ + err = hci_cmd_sync_queue(hdev, create_big_sync, conn, + create_big_complete); +@@ -2214,10 +2203,6 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, + return ERR_PTR(err); + } + +- hci_iso_qos_setup(hdev, conn, &qos->bcast.out, +- conn->le_tx_phy ? conn->le_tx_phy : +- hdev->le_tx_def_phys); +- + return conn; + } + +@@ -2259,11 +2244,9 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, + return ERR_PTR(-ENOLINK); + } + +- /* If LE is already connected and CIS handle is already set proceed to +- * Create CIS immediately. +- */ +- if (le->state == BT_CONNECTED && cis->handle != HCI_CONN_HANDLE_UNSET) +- hci_le_create_cis(cis); ++ cis->state = BT_CONNECT; ++ ++ hci_le_create_cis_pending(hdev); + + return cis; + } +@@ -2850,81 +2833,46 @@ u32 hci_conn_get_phy(struct hci_conn *conn) + return phys; + } + +-int hci_abort_conn(struct hci_conn *conn, u8 reason) ++static int abort_conn_sync(struct hci_dev *hdev, void *data) + { +- int r = 0; ++ struct hci_conn *conn; ++ u16 handle = PTR_ERR(data); + +- if (test_and_set_bit(HCI_CONN_CANCEL, &conn->flags)) ++ conn = hci_conn_hash_lookup_handle(hdev, handle); ++ if (!conn) + return 0; + +- switch (conn->state) { +- case BT_CONNECTED: +- case BT_CONFIG: +- if (conn->type == AMP_LINK) { +- struct hci_cp_disconn_phy_link cp; ++ return hci_abort_conn_sync(hdev, conn, conn->abort_reason); ++} + +- cp.phy_handle = HCI_PHY_HANDLE(conn->handle); +- cp.reason = reason; +- r = hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK, +- sizeof(cp), &cp); +- } else { +- struct hci_cp_disconnect dc; ++int hci_abort_conn(struct hci_conn *conn, u8 reason) ++{ ++ struct hci_dev *hdev = conn->hdev; + +- dc.handle = cpu_to_le16(conn->handle); +- dc.reason = reason; +- r = hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, +- sizeof(dc), &dc); +- } ++ /* If abort_reason has already been set it means the connection is ++ * already being aborted so don't attempt to overwrite it. ++ */ ++ if (conn->abort_reason) ++ return 0; + +- conn->state = BT_DISCONN; ++ bt_dev_dbg(hdev, "handle 0x%2.2x reason 0x%2.2x", conn->handle, reason); + +- break; +- case BT_CONNECT: +- if (conn->type == LE_LINK) { +- if (test_bit(HCI_CONN_SCANNING, &conn->flags)) +- break; +- r = hci_send_cmd(conn->hdev, +- HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); +- } else if (conn->type == ACL_LINK) { +- if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2) +- break; +- r = hci_send_cmd(conn->hdev, +- HCI_OP_CREATE_CONN_CANCEL, +- 6, &conn->dst); +- } +- break; +- case BT_CONNECT2: +- if (conn->type == ACL_LINK) { +- struct hci_cp_reject_conn_req rej; +- +- bacpy(&rej.bdaddr, &conn->dst); +- rej.reason = reason; +- +- r = hci_send_cmd(conn->hdev, +- HCI_OP_REJECT_CONN_REQ, +- sizeof(rej), &rej); +- } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) { +- struct hci_cp_reject_sync_conn_req rej; +- +- bacpy(&rej.bdaddr, &conn->dst); +- +- /* SCO rejection has its own limited set of +- * allowed error values (0x0D-0x0F) which isn't +- * compatible with most values passed to this +- * function. To be safe hard-code one of the +- * values that's suitable for SCO. +- */ +- rej.reason = HCI_ERROR_REJ_LIMITED_RESOURCES; ++ conn->abort_reason = reason; + +- r = hci_send_cmd(conn->hdev, +- HCI_OP_REJECT_SYNC_CONN_REQ, +- sizeof(rej), &rej); ++ /* If the connection is pending check the command opcode since that ++ * might be blocking on hci_cmd_sync_work while waiting its respective ++ * event so we need to hci_cmd_sync_cancel to cancel it. ++ */ ++ if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) { ++ switch (hci_skb_event(hdev->sent_cmd)) { ++ case HCI_EV_LE_CONN_COMPLETE: ++ case HCI_EV_LE_ENHANCED_CONN_COMPLETE: ++ case HCI_EVT_LE_CIS_ESTABLISHED: ++ hci_cmd_sync_cancel(hdev, -ECANCELED); ++ break; + } +- break; +- default: +- conn->state = BT_CLOSED; +- break; + } + +- return r; ++ return hci_cmd_sync_queue(hdev, abort_conn_sync, ERR_PTR(conn->handle), ++ NULL); + } +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 1ec83985f1ab0..2c845c9a26be0 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -1074,9 +1074,9 @@ void hci_uuids_clear(struct hci_dev *hdev) + + void hci_link_keys_clear(struct hci_dev *hdev) + { +- struct link_key *key; ++ struct link_key *key, *tmp; + +- list_for_each_entry(key, &hdev->link_keys, list) { ++ list_for_each_entry_safe(key, tmp, &hdev->link_keys, list) { + list_del_rcu(&key->list); + kfree_rcu(key, rcu); + } +@@ -1084,9 +1084,9 @@ void hci_link_keys_clear(struct hci_dev *hdev) + + void hci_smp_ltks_clear(struct hci_dev *hdev) + { +- struct smp_ltk *k; ++ struct smp_ltk *k, *tmp; + +- list_for_each_entry(k, &hdev->long_term_keys, list) { ++ list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + list_del_rcu(&k->list); + kfree_rcu(k, rcu); + } +@@ -1094,9 +1094,9 @@ void hci_smp_ltks_clear(struct hci_dev *hdev) + + void hci_smp_irks_clear(struct hci_dev *hdev) + { +- struct smp_irk *k; ++ struct smp_irk *k, *tmp; + +- list_for_each_entry(k, &hdev->identity_resolving_keys, list) { ++ list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { + list_del_rcu(&k->list); + kfree_rcu(k, rcu); + } +@@ -1104,9 +1104,9 @@ void hci_smp_irks_clear(struct hci_dev *hdev) + + void hci_blocked_keys_clear(struct hci_dev *hdev) + { +- struct blocked_key *b; ++ struct blocked_key *b, *tmp; + +- list_for_each_entry(b, &hdev->blocked_keys, list) { ++ list_for_each_entry_safe(b, tmp, &hdev->blocked_keys, list) { + list_del_rcu(&b->list); + kfree_rcu(b, rcu); + } +@@ -1949,15 +1949,15 @@ int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) + + switch (hci_get_adv_monitor_offload_ext(hdev)) { + case HCI_ADV_MONITOR_EXT_NONE: +- bt_dev_dbg(hdev, "%s add monitor %d status %d", hdev->name, ++ bt_dev_dbg(hdev, "add monitor %d status %d", + monitor->handle, status); + /* Message was not forwarded to controller - not an error */ + break; + + case HCI_ADV_MONITOR_EXT_MSFT: + status = msft_add_monitor_pattern(hdev, monitor); +- bt_dev_dbg(hdev, "%s add monitor %d msft status %d", hdev->name, +- monitor->handle, status); ++ bt_dev_dbg(hdev, "add monitor %d msft status %d", ++ handle, status); + break; + } + +@@ -1976,15 +1976,15 @@ static int hci_remove_adv_monitor(struct hci_dev *hdev, + + switch (hci_get_adv_monitor_offload_ext(hdev)) { + case HCI_ADV_MONITOR_EXT_NONE: /* also goes here when powered off */ +- bt_dev_dbg(hdev, "%s remove monitor %d status %d", hdev->name, ++ bt_dev_dbg(hdev, "remove monitor %d status %d", + monitor->handle, status); + goto free_monitor; + + case HCI_ADV_MONITOR_EXT_MSFT: + handle = monitor->handle; + status = msft_remove_monitor(hdev, monitor); +- bt_dev_dbg(hdev, "%s remove monitor %d msft status %d", +- hdev->name, handle, status); ++ bt_dev_dbg(hdev, "remove monitor %d msft status %d", ++ handle, status); + break; + } + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index cb0b5fe7a6f8c..5f4af2cfd21d8 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3173,7 +3173,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, + * As the connection handle is set here for the first time, it indicates + * whether the connection is already set up. + */ +- if (conn->handle != HCI_CONN_HANDLE_UNSET) { ++ if (!HCI_CONN_HANDLE_UNSET(conn->handle)) { + bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection"); + goto unlock; + } +@@ -3803,6 +3803,22 @@ static u8 hci_cc_le_read_buffer_size_v2(struct hci_dev *hdev, void *data, + return rp->status; + } + ++static void hci_unbound_cis_failed(struct hci_dev *hdev, u8 cig, u8 status) ++{ ++ struct hci_conn *conn, *tmp; ++ ++ lockdep_assert_held(&hdev->lock); ++ ++ list_for_each_entry_safe(conn, tmp, &hdev->conn_hash.list, list) { ++ if (conn->type != ISO_LINK || !bacmp(&conn->dst, BDADDR_ANY) || ++ conn->state == BT_OPEN || conn->iso_qos.ucast.cig != cig) ++ continue; ++ ++ if (HCI_CONN_HANDLE_UNSET(conn->handle)) ++ hci_conn_failed(conn, status); ++ } ++} ++ + static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data, + struct sk_buff *skb) + { +@@ -3810,6 +3826,7 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data, + struct hci_cp_le_set_cig_params *cp; + struct hci_conn *conn; + u8 status = rp->status; ++ bool pending = false; + int i; + + bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); +@@ -3822,12 +3839,15 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data, + + hci_dev_lock(hdev); + ++ /* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E page 2554 ++ * ++ * If the Status return parameter is non-zero, then the state of the CIG ++ * and its CIS configurations shall not be changed by the command. If ++ * the CIG did not already exist, it shall not be created. ++ */ + if (status) { +- while ((conn = hci_conn_hash_lookup_cig(hdev, rp->cig_id))) { +- conn->state = BT_CLOSED; +- hci_connect_cfm(conn, status); +- hci_conn_del(conn); +- } ++ /* Keep current configuration, fail only the unbound CIS */ ++ hci_unbound_cis_failed(hdev, rp->cig_id, status); + goto unlock; + } + +@@ -3851,13 +3871,15 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data, + + bt_dev_dbg(hdev, "%p handle 0x%4.4x parent %p", conn, + conn->handle, conn->parent); +- +- /* Create CIS if LE is already connected */ +- if (conn->parent && conn->parent->state == BT_CONNECTED) +- hci_le_create_cis(conn); ++ ++ if (conn->state == BT_CONNECT) ++ pending = true; + } + + unlock: ++ if (pending) ++ hci_le_create_cis_pending(hdev); ++ + hci_dev_unlock(hdev); + + return rp->status; +@@ -4223,6 +4245,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data, + static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) + { + struct hci_cp_le_create_cis *cp; ++ bool pending = false; + int i; + + bt_dev_dbg(hdev, "status 0x%2.2x", status); +@@ -4245,12 +4268,18 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (conn) { ++ if (test_and_clear_bit(HCI_CONN_CREATE_CIS, ++ &conn->flags)) ++ pending = true; + conn->state = BT_CLOSED; + hci_connect_cfm(conn, status); + hci_conn_del(conn); + } + } + ++ if (pending) ++ hci_le_create_cis_pending(hdev); ++ + hci_dev_unlock(hdev); + } + +@@ -4998,7 +5027,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, + * As the connection handle is set here for the first time, it indicates + * whether the connection is already set up. + */ +- if (conn->handle != HCI_CONN_HANDLE_UNSET) { ++ if (!HCI_CONN_HANDLE_UNSET(conn->handle)) { + bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection"); + goto unlock; + } +@@ -5862,7 +5891,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, + * As the connection handle is set here for the first time, it indicates + * whether the connection is already set up. + */ +- if (conn->handle != HCI_CONN_HANDLE_UNSET) { ++ if (!HCI_CONN_HANDLE_UNSET(conn->handle)) { + bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection"); + goto unlock; + } +@@ -6788,6 +6817,8 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data, + { + struct hci_evt_le_cis_established *ev = data; + struct hci_conn *conn; ++ struct bt_iso_qos *qos; ++ bool pending = false; + u16 handle = __le16_to_cpu(ev->handle); + + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); +@@ -6809,21 +6840,41 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data, + goto unlock; + } + +- if (conn->role == HCI_ROLE_SLAVE) { +- __le32 interval; ++ qos = &conn->iso_qos; + +- memset(&interval, 0, sizeof(interval)); ++ pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, &conn->flags); + +- memcpy(&interval, ev->c_latency, sizeof(ev->c_latency)); +- conn->iso_qos.ucast.in.interval = le32_to_cpu(interval); +- memcpy(&interval, ev->p_latency, sizeof(ev->p_latency)); +- conn->iso_qos.ucast.out.interval = le32_to_cpu(interval); +- conn->iso_qos.ucast.in.latency = le16_to_cpu(ev->interval); +- conn->iso_qos.ucast.out.latency = le16_to_cpu(ev->interval); +- conn->iso_qos.ucast.in.sdu = le16_to_cpu(ev->c_mtu); +- conn->iso_qos.ucast.out.sdu = le16_to_cpu(ev->p_mtu); +- conn->iso_qos.ucast.in.phy = ev->c_phy; +- conn->iso_qos.ucast.out.phy = ev->p_phy; ++ /* Convert ISO Interval (1.25 ms slots) to SDU Interval (us) */ ++ qos->ucast.in.interval = le16_to_cpu(ev->interval) * 1250; ++ qos->ucast.out.interval = qos->ucast.in.interval; ++ ++ switch (conn->role) { ++ case HCI_ROLE_SLAVE: ++ /* Convert Transport Latency (us) to Latency (msec) */ ++ qos->ucast.in.latency = ++ DIV_ROUND_CLOSEST(get_unaligned_le24(ev->c_latency), ++ 1000); ++ qos->ucast.out.latency = ++ DIV_ROUND_CLOSEST(get_unaligned_le24(ev->p_latency), ++ 1000); ++ qos->ucast.in.sdu = le16_to_cpu(ev->c_mtu); ++ qos->ucast.out.sdu = le16_to_cpu(ev->p_mtu); ++ qos->ucast.in.phy = ev->c_phy; ++ qos->ucast.out.phy = ev->p_phy; ++ break; ++ case HCI_ROLE_MASTER: ++ /* Convert Transport Latency (us) to Latency (msec) */ ++ qos->ucast.out.latency = ++ DIV_ROUND_CLOSEST(get_unaligned_le24(ev->c_latency), ++ 1000); ++ qos->ucast.in.latency = ++ DIV_ROUND_CLOSEST(get_unaligned_le24(ev->p_latency), ++ 1000); ++ qos->ucast.out.sdu = le16_to_cpu(ev->c_mtu); ++ qos->ucast.in.sdu = le16_to_cpu(ev->p_mtu); ++ qos->ucast.out.phy = ev->c_phy; ++ qos->ucast.in.phy = ev->p_phy; ++ break; + } + + if (!ev->status) { +@@ -6834,10 +6885,14 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data, + goto unlock; + } + ++ conn->state = BT_CLOSED; + hci_connect_cfm(conn, ev->status); + hci_conn_del(conn); + + unlock: ++ if (pending) ++ hci_le_create_cis_pending(hdev); ++ + hci_dev_unlock(hdev); + } + +@@ -6916,6 +6971,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, + { + struct hci_evt_le_create_big_complete *ev = data; + struct hci_conn *conn; ++ __u8 bis_idx = 0; + + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); + +@@ -6924,33 +6980,44 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, + return; + + hci_dev_lock(hdev); ++ rcu_read_lock(); + +- conn = hci_conn_hash_lookup_big(hdev, ev->handle); +- if (!conn) +- goto unlock; ++ /* Connect all BISes that are bound to the BIG */ ++ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { ++ if (bacmp(&conn->dst, BDADDR_ANY) || ++ conn->type != ISO_LINK || ++ conn->iso_qos.bcast.big != ev->handle) ++ continue; + +- if (conn->type != ISO_LINK) { +- bt_dev_err(hdev, +- "Invalid connection link type handle 0x%2.2x", +- ev->handle); +- goto unlock; +- } ++ conn->handle = __le16_to_cpu(ev->bis_handle[bis_idx++]); + +- if (ev->num_bis) +- conn->handle = __le16_to_cpu(ev->bis_handle[0]); ++ if (!ev->status) { ++ conn->state = BT_CONNECTED; ++ set_bit(HCI_CONN_BIG_CREATED, &conn->flags); ++ rcu_read_unlock(); ++ hci_debugfs_create_conn(conn); ++ hci_conn_add_sysfs(conn); ++ hci_iso_setup_path(conn); ++ rcu_read_lock(); ++ continue; ++ } + +- if (!ev->status) { +- conn->state = BT_CONNECTED; +- hci_debugfs_create_conn(conn); +- hci_conn_add_sysfs(conn); +- hci_iso_setup_path(conn); +- goto unlock; ++ hci_connect_cfm(conn, ev->status); ++ rcu_read_unlock(); ++ hci_conn_del(conn); ++ rcu_read_lock(); + } + +- hci_connect_cfm(conn, ev->status); +- hci_conn_del(conn); ++ if (!ev->status && !bis_idx) ++ /* If no BISes have been connected for the BIG, ++ * terminate. This is in case all bound connections ++ * have been closed before the BIG creation ++ * has completed. ++ */ ++ hci_le_terminate_big_sync(hdev, ev->handle, ++ HCI_ERROR_LOCAL_HOST_TERM); + +-unlock: ++ rcu_read_unlock(); + hci_dev_unlock(hdev); + } + +@@ -6967,9 +7034,6 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, + flex_array_size(ev, bis, ev->num_bis))) + return; + +- if (ev->status) +- return; +- + hci_dev_lock(hdev); + + for (i = 0; i < ev->num_bis; i++) { +@@ -6993,9 +7057,25 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, + bis->iso_qos.bcast.in.latency = le16_to_cpu(ev->interval) * 125 / 100; + bis->iso_qos.bcast.in.sdu = le16_to_cpu(ev->max_pdu); + +- hci_iso_setup_path(bis); ++ if (!ev->status) { ++ set_bit(HCI_CONN_BIG_SYNC, &bis->flags); ++ hci_iso_setup_path(bis); ++ } + } + ++ /* In case BIG sync failed, notify each failed connection to ++ * the user after all hci connections have been added ++ */ ++ if (ev->status) ++ for (i = 0; i < ev->num_bis; i++) { ++ u16 handle = le16_to_cpu(ev->bis[i]); ++ ++ bis = hci_conn_hash_lookup_handle(hdev, handle); ++ ++ set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags); ++ hci_connect_cfm(bis, ev->status); ++ } ++ + hci_dev_unlock(hdev); + } + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 1bcb54272dc67..3177a38ef4d60 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -4684,7 +4684,10 @@ static const struct { + "advertised, but not supported."), + HCI_QUIRK_BROKEN(SET_RPA_TIMEOUT, + "HCI LE Set Random Private Address Timeout command is " +- "advertised, but not supported.") ++ "advertised, but not supported."), ++ HCI_QUIRK_BROKEN(LE_CODED, ++ "HCI LE Coded PHY feature bit is set, " ++ "but its usage is not supported.") + }; + + /* This function handles hdev setup stage: +@@ -5271,22 +5274,27 @@ static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn, + } + + static int hci_le_connect_cancel_sync(struct hci_dev *hdev, +- struct hci_conn *conn) ++ struct hci_conn *conn, u8 reason) + { ++ /* Return reason if scanning since the connection shall probably be ++ * cleanup directly. ++ */ + if (test_bit(HCI_CONN_SCANNING, &conn->flags)) +- return 0; ++ return reason; + +- if (test_and_set_bit(HCI_CONN_CANCEL, &conn->flags)) ++ if (conn->role == HCI_ROLE_SLAVE || ++ test_and_set_bit(HCI_CONN_CANCEL, &conn->flags)) + return 0; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_CREATE_CONN_CANCEL, + 0, NULL, HCI_CMD_TIMEOUT); + } + +-static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn) ++static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn, ++ u8 reason) + { + if (conn->type == LE_LINK) +- return hci_le_connect_cancel_sync(hdev, conn); ++ return hci_le_connect_cancel_sync(hdev, conn, reason); + + if (hdev->hci_ver < BLUETOOTH_VER_1_2) + return 0; +@@ -5332,43 +5340,81 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, + + int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) + { +- int err; ++ int err = 0; ++ u16 handle = conn->handle; ++ struct hci_conn *c; + + switch (conn->state) { + case BT_CONNECTED: + case BT_CONFIG: +- return hci_disconnect_sync(hdev, conn, reason); ++ err = hci_disconnect_sync(hdev, conn, reason); ++ break; + case BT_CONNECT: +- err = hci_connect_cancel_sync(hdev, conn); +- /* Cleanup hci_conn object if it cannot be cancelled as it +- * likelly means the controller and host stack are out of sync. +- */ +- if (err) { ++ err = hci_connect_cancel_sync(hdev, conn, reason); ++ break; ++ case BT_CONNECT2: ++ err = hci_reject_conn_sync(hdev, conn, reason); ++ break; ++ case BT_OPEN: ++ /* Cleanup bises that failed to be established */ ++ if (test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags)) { + hci_dev_lock(hdev); +- hci_conn_failed(conn, err); ++ hci_conn_failed(conn, reason); + hci_dev_unlock(hdev); + } +- return err; +- case BT_CONNECT2: +- return hci_reject_conn_sync(hdev, conn, reason); ++ break; + default: ++ hci_dev_lock(hdev); + conn->state = BT_CLOSED; +- break; ++ hci_disconn_cfm(conn, reason); ++ hci_conn_del(conn); ++ hci_dev_unlock(hdev); ++ return 0; + } + +- return 0; ++ hci_dev_lock(hdev); ++ ++ /* Check if the connection hasn't been cleanup while waiting ++ * commands to complete. ++ */ ++ c = hci_conn_hash_lookup_handle(hdev, handle); ++ if (!c || c != conn) { ++ err = 0; ++ goto unlock; ++ } ++ ++ /* Cleanup hci_conn object if it cannot be cancelled as it ++ * likelly means the controller and host stack are out of sync ++ * or in case of LE it was still scanning so it can be cleanup ++ * safely. ++ */ ++ hci_conn_failed(conn, reason); ++ ++unlock: ++ hci_dev_unlock(hdev); ++ return err; + } + + static int hci_disconnect_all_sync(struct hci_dev *hdev, u8 reason) + { +- struct hci_conn *conn, *tmp; +- int err; ++ struct list_head *head = &hdev->conn_hash.list; ++ struct hci_conn *conn; + +- list_for_each_entry_safe(conn, tmp, &hdev->conn_hash.list, list) { +- err = hci_abort_conn_sync(hdev, conn, reason); +- if (err) +- return err; ++ rcu_read_lock(); ++ while ((conn = list_first_or_null_rcu(head, struct hci_conn, list))) { ++ /* Make sure the connection is not freed while unlocking */ ++ conn = hci_conn_get(conn); ++ rcu_read_unlock(); ++ /* Disregard possible errors since hci_conn_del shall have been ++ * called even in case of errors had occurred since it would ++ * then cause hci_conn_failed to be called which calls ++ * hci_conn_del internally. ++ */ ++ hci_abort_conn_sync(hdev, conn, reason); ++ hci_conn_put(conn); ++ rcu_read_lock(); + } ++ rcu_read_unlock(); + + return 0; + } +@@ -6255,63 +6301,99 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn) + + done: + if (err == -ETIMEDOUT) +- hci_le_connect_cancel_sync(hdev, conn); ++ hci_le_connect_cancel_sync(hdev, conn, 0x00); + + /* Re-enable advertising after the connection attempt is finished. */ + hci_resume_advertising_sync(hdev); + return err; + } + +-int hci_le_create_cis_sync(struct hci_dev *hdev, struct hci_conn *conn) ++int hci_le_create_cis_sync(struct hci_dev *hdev) + { + struct { + struct hci_cp_le_create_cis cp; + struct hci_cis cis[0x1f]; + } cmd; +- u8 cig; +- struct hci_conn *hcon = conn; ++ struct hci_conn *conn; ++ u8 cig = BT_ISO_QOS_CIG_UNSET; ++ ++ /* The spec allows only one pending LE Create CIS command at a time. If ++ * the command is pending now, don't do anything. We check for pending ++ * connections after each CIS Established event. ++ * ++ * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E ++ * page 2566: ++ * ++ * If the Host issues this command before all the ++ * HCI_LE_CIS_Established events from the previous use of the ++ * command have been generated, the Controller shall return the ++ * error code Command Disallowed (0x0C). ++ * ++ * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E ++ * page 2567: ++ * ++ * When the Controller receives the HCI_LE_Create_CIS command, the ++ * Controller sends the HCI_Command_Status event to the Host. An ++ * HCI_LE_CIS_Established event will be generated for each CIS when it ++ * is established or if it is disconnected or considered lost before ++ * being established; until all the events are generated, the command ++ * remains pending. ++ */ + + memset(&cmd, 0, sizeof(cmd)); +- cmd.cis[0].acl_handle = cpu_to_le16(conn->parent->handle); +- cmd.cis[0].cis_handle = cpu_to_le16(conn->handle); +- cmd.cp.num_cis++; +- cig = conn->iso_qos.ucast.cig; + + hci_dev_lock(hdev); + + rcu_read_lock(); + ++ /* Wait until previous Create CIS has completed */ + list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { +- struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis]; ++ if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ++ goto done; ++ } + +- if (conn == hcon || conn->type != ISO_LINK || +- conn->state == BT_CONNECTED || +- conn->iso_qos.ucast.cig != cig) ++ /* Find CIG with all CIS ready */ ++ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { ++ struct hci_conn *link; ++ ++ if (hci_conn_check_create_cis(conn)) + continue; + +- /* Check if all CIS(s) belonging to a CIG are ready */ +- if (!conn->parent || conn->parent->state != BT_CONNECTED || +- conn->state != BT_CONNECT) { +- cmd.cp.num_cis = 0; +- break; ++ cig = conn->iso_qos.ucast.cig; ++ ++ list_for_each_entry_rcu(link, &hdev->conn_hash.list, list) { ++ if (hci_conn_check_create_cis(link) > 0 && ++ link->iso_qos.ucast.cig == cig && ++ link->state != BT_CONNECTED) { ++ cig = BT_ISO_QOS_CIG_UNSET; ++ break; ++ } + } + +- /* Group all CIS with state BT_CONNECT since the spec don't +- * allow to send them individually: +- * +- * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E +- * page 2566: +- * +- * If the Host issues this command before all the +- * HCI_LE_CIS_Established events from the previous use of the +- * command have been generated, the Controller shall return the +- * error code Command Disallowed (0x0C). +- */ ++ if (cig != BT_ISO_QOS_CIG_UNSET) ++ break; ++ } ++ ++ if (cig == BT_ISO_QOS_CIG_UNSET) ++ goto done; ++ ++ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { ++ struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis]; ++ ++ if (hci_conn_check_create_cis(conn) || ++ conn->iso_qos.ucast.cig != cig) ++ continue; ++ ++ set_bit(HCI_CONN_CREATE_CIS, &conn->flags); + cis->acl_handle = cpu_to_le16(conn->parent->handle); + cis->cis_handle = cpu_to_le16(conn->handle); + cmd.cp.num_cis++; ++ ++ if (cmd.cp.num_cis >= ARRAY_SIZE(cmd.cis)) ++ break; + } + ++done: + rcu_read_unlock(); + + hci_dev_unlock(hdev); +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 94d5bc104fede..4f2443e1aab3c 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -48,6 +48,11 @@ static void iso_sock_kill(struct sock *sk); + #define EIR_SERVICE_DATA_LENGTH 4 + #define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH) + ++/* iso_pinfo flags values */ ++enum { ++ BT_SK_BIG_SYNC, ++}; ++ + struct iso_pinfo { + struct bt_sock bt; + bdaddr_t src; +@@ -58,7 +63,7 @@ struct iso_pinfo { + __u8 bc_num_bis; + __u8 bc_bis[ISO_MAX_NUM_BIS]; + __u16 sync_handle; +- __u32 flags; ++ unsigned long flags; + struct bt_iso_qos qos; + bool qos_user_set; + __u8 base_len; +@@ -287,13 +292,24 @@ static int iso_connect_bis(struct sock *sk) + goto unlock; + } + +- hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, +- le_addr_type(iso_pi(sk)->dst_type), +- &iso_pi(sk)->qos, iso_pi(sk)->base_len, +- iso_pi(sk)->base); +- if (IS_ERR(hcon)) { +- err = PTR_ERR(hcon); +- goto unlock; ++ /* Just bind if DEFER_SETUP has been set */ ++ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { ++ hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, ++ &iso_pi(sk)->qos, iso_pi(sk)->base_len, ++ iso_pi(sk)->base); ++ if (IS_ERR(hcon)) { ++ err = PTR_ERR(hcon); ++ goto unlock; ++ } ++ } else { ++ hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, ++ le_addr_type(iso_pi(sk)->dst_type), ++ &iso_pi(sk)->qos, iso_pi(sk)->base_len, ++ iso_pi(sk)->base); ++ if (IS_ERR(hcon)) { ++ err = PTR_ERR(hcon); ++ goto unlock; ++ } + } + + conn = iso_conn_add(hcon); +@@ -317,6 +333,9 @@ static int iso_connect_bis(struct sock *sk) + if (hcon->state == BT_CONNECTED) { + iso_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; ++ } else if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { ++ iso_sock_clear_timer(sk); ++ sk->sk_state = BT_CONNECT; + } else { + sk->sk_state = BT_CONNECT; + iso_sock_set_timer(sk, sk->sk_sndtimeo); +@@ -1202,6 +1221,12 @@ static bool check_io_qos(struct bt_iso_io_qos *qos) + + static bool check_ucast_qos(struct bt_iso_qos *qos) + { ++ if (qos->ucast.cig > 0xef && qos->ucast.cig != BT_ISO_QOS_CIG_UNSET) ++ return false; ++ ++ if (qos->ucast.cis > 0xef && qos->ucast.cis != BT_ISO_QOS_CIS_UNSET) ++ return false; ++ + if (qos->ucast.sca > 0x07) + return false; + +@@ -1466,7 +1491,7 @@ static int iso_sock_release(struct socket *sock) + + iso_sock_close(sk); + +- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && ++ if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) && + !(current->flags & PF_EXITING)) { + lock_sock(sk); + err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); +@@ -1563,6 +1588,12 @@ static void iso_conn_ready(struct iso_conn *conn) + hci_conn_hold(hcon); + iso_chan_add(conn, sk, parent); + ++ if (ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) { ++ /* Trigger error signal on child socket */ ++ sk->sk_err = ECONNREFUSED; ++ sk->sk_error_report(sk); ++ } ++ + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) + sk->sk_state = BT_CONNECT2; + else +@@ -1631,15 +1662,17 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) + if (ev2->num_bis < iso_pi(sk)->bc_num_bis) + iso_pi(sk)->bc_num_bis = ev2->num_bis; + +- err = hci_le_big_create_sync(hdev, +- &iso_pi(sk)->qos, +- iso_pi(sk)->sync_handle, +- iso_pi(sk)->bc_num_bis, +- iso_pi(sk)->bc_bis); +- if (err) { +- bt_dev_err(hdev, "hci_le_big_create_sync: %d", +- err); +- sk = NULL; ++ if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) { ++ err = hci_le_big_create_sync(hdev, ++ &iso_pi(sk)->qos, ++ iso_pi(sk)->sync_handle, ++ iso_pi(sk)->bc_num_bis, ++ iso_pi(sk)->bc_bis); ++ if (err) { ++ bt_dev_err(hdev, "hci_le_big_create_sync: %d", ++ err); ++ sk = NULL; ++ } + } + } + } else { +@@ -1676,13 +1709,18 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) + } + + /* Create CIS if pending */ +- hci_le_create_cis(hcon); ++ hci_le_create_cis_pending(hcon->hdev); + return; + } + + BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); + +- if (!status) { ++ /* Similar to the success case, if HCI_CONN_BIG_SYNC_FAILED is set, ++ * queue the failed bis connection into the accept queue of the ++ * listening socket and wake up userspace, to inform the user about ++ * the BIG sync failed event. ++ */ ++ if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) { + struct iso_conn *conn; + + conn = iso_conn_add(hcon); +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index d4498037fadc6..6240b20f020a8 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -3580,18 +3580,6 @@ unlock: + return err; + } + +-static int abort_conn_sync(struct hci_dev *hdev, void *data) +-{ +- struct hci_conn *conn; +- u16 handle = PTR_ERR(data); +- +- conn = hci_conn_hash_lookup_handle(hdev, handle); +- if (!conn) +- return 0; +- +- return hci_abort_conn_sync(hdev, conn, HCI_ERROR_REMOTE_USER_TERM); +-} +- + static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) + { +@@ -3642,8 +3630,7 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, + le_addr_type(addr->type)); + + if (conn->conn_reason == CONN_REASON_PAIR_DEVICE) +- hci_cmd_sync_queue(hdev, abort_conn_sync, ERR_PTR(conn->handle), +- NULL); ++ hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM); + + unlock: + hci_dev_unlock(hdev); +diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c +index bf5cee48916c7..b80a2162a5c33 100644 +--- a/net/bluetooth/msft.c ++++ b/net/bluetooth/msft.c +@@ -91,6 +91,33 @@ struct msft_ev_le_monitor_device { + struct msft_monitor_advertisement_handle_data { + __u8 msft_handle; + __u16 mgmt_handle; ++ __s8 rssi_high; ++ __s8 rssi_low; ++ __u8 rssi_low_interval; ++ __u8 rssi_sampling_period; ++ __u8 cond_type; ++ struct list_head list; ++}; ++ ++enum monitor_addr_filter_state { ++ AF_STATE_IDLE, ++ AF_STATE_ADDING, ++ AF_STATE_ADDED, ++ AF_STATE_REMOVING, ++}; ++ ++#define MSFT_MONITOR_ADVERTISEMENT_TYPE_ADDR 0x04 ++struct msft_monitor_addr_filter_data { ++ __u8 msft_handle; ++ __u8 pattern_handle; /* address filters pertain to */ ++ __u16 mgmt_handle; ++ int state; ++ __s8 rssi_high; ++ __s8 rssi_low; ++ __u8 rssi_low_interval; ++ __u8 rssi_sampling_period; ++ __u8 addr_type; ++ bdaddr_t bdaddr; + struct list_head list; + }; + +@@ -99,9 +126,12 @@ struct msft_data { + __u8 evt_prefix_len; + __u8 *evt_prefix; + struct list_head handle_map; ++ struct list_head address_filters; + __u8 resuming; + __u8 suspending; + __u8 filter_enabled; ++ /* To synchronize add/remove address filter and monitor device event.*/ ++ struct mutex filter_lock; + }; + + bool msft_monitor_supported(struct hci_dev *hdev) +@@ -180,6 +210,24 @@ static struct msft_monitor_advertisement_handle_data *msft_find_handle_data + return NULL; + } + ++/* This function requires the caller holds msft->filter_lock */ ++static struct msft_monitor_addr_filter_data *msft_find_address_data ++ (struct hci_dev *hdev, u8 addr_type, bdaddr_t *addr, ++ u8 pattern_handle) ++{ ++ struct msft_monitor_addr_filter_data *entry; ++ struct msft_data *msft = hdev->msft_data; ++ ++ list_for_each_entry(entry, &msft->address_filters, list) { ++ if (entry->pattern_handle == pattern_handle && ++ addr_type == entry->addr_type && ++ !bacmp(addr, &entry->bdaddr)) ++ return entry; ++ } ++ ++ return NULL; ++} ++ + /* This function requires the caller holds hdev->lock */ + static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle, + bdaddr_t *bdaddr, __u8 addr_type, +@@ -240,6 +288,7 @@ static int msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u16 opcode, + + handle_data->mgmt_handle = monitor->handle; + handle_data->msft_handle = rp->handle; ++ handle_data->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN; + INIT_LIST_HEAD(&handle_data->list); + list_add(&handle_data->list, &msft->handle_map); + +@@ -254,6 +303,70 @@ unlock: + return status; + } + ++/* This function requires the caller holds hci_req_sync_lock */ ++static void msft_remove_addr_filters_sync(struct hci_dev *hdev, u8 handle) ++{ ++ struct msft_monitor_addr_filter_data *address_filter, *n; ++ struct msft_cp_le_cancel_monitor_advertisement cp; ++ struct msft_data *msft = hdev->msft_data; ++ struct list_head head; ++ struct sk_buff *skb; ++ ++ INIT_LIST_HEAD(&head); ++ ++ /* Cancel all corresponding address monitors */ ++ mutex_lock(&msft->filter_lock); ++ ++ list_for_each_entry_safe(address_filter, n, &msft->address_filters, ++ list) { ++ if (address_filter->pattern_handle != handle) ++ continue; ++ ++ list_del(&address_filter->list); ++ ++ /* Keep the address filter and let ++ * msft_add_address_filter_sync() remove and free the address ++ * filter. ++ */ ++ if (address_filter->state == AF_STATE_ADDING) { ++ address_filter->state = AF_STATE_REMOVING; ++ continue; ++ } ++ ++ /* Keep the address filter and let ++ * msft_cancel_address_filter_sync() remove and free the address ++ * filter ++ */ ++ if (address_filter->state == AF_STATE_REMOVING) ++ continue; ++ ++ list_add_tail(&address_filter->list, &head); ++ } ++ ++ mutex_unlock(&msft->filter_lock); ++ ++ list_for_each_entry_safe(address_filter, n, &head, list) { ++ list_del(&address_filter->list); ++ ++ cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT; ++ cp.handle = address_filter->msft_handle; ++ ++ skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp, ++ HCI_CMD_TIMEOUT); ++ if (IS_ERR_OR_NULL(skb)) { ++ kfree(address_filter); ++ continue; ++ } ++ ++ kfree_skb(skb); ++ ++ bt_dev_dbg(hdev, "MSFT: Canceled device %pMR address filter", ++ &address_filter->bdaddr); ++ ++ kfree(address_filter); ++ } ++} ++ + static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, + u16 opcode, + struct adv_monitor *monitor, +@@ -263,6 +376,7 @@ static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, + struct msft_monitor_advertisement_handle_data *handle_data; + struct msft_data *msft = hdev->msft_data; + int status = 0; ++ u8 msft_handle; + + rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data; + if (skb->len < sizeof(*rp)) { +@@ -293,11 +407,17 @@ static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, + NULL, 0, false); + } + ++ msft_handle = handle_data->msft_handle; ++ + list_del(&handle_data->list); + kfree(handle_data); +- } + +- hci_dev_unlock(hdev); ++ hci_dev_unlock(hdev); ++ ++ msft_remove_addr_filters_sync(hdev, msft_handle); ++ } else { ++ hci_dev_unlock(hdev); ++ } + + done: + return status; +@@ -394,12 +514,14 @@ static int msft_add_monitor_sync(struct hci_dev *hdev, + { + struct msft_cp_le_monitor_advertisement *cp; + struct msft_le_monitor_advertisement_pattern_data *pattern_data; ++ struct msft_monitor_advertisement_handle_data *handle_data; + struct msft_le_monitor_advertisement_pattern *pattern; + struct adv_pattern *entry; + size_t total_size = sizeof(*cp) + sizeof(*pattern_data); + ptrdiff_t offset = 0; + u8 pattern_count = 0; + struct sk_buff *skb; ++ int err; + + if (!msft_monitor_pattern_valid(monitor)) + return -EINVAL; +@@ -436,16 +558,31 @@ static int msft_add_monitor_sync(struct hci_dev *hdev, + + skb = __hci_cmd_sync(hdev, hdev->msft_opcode, total_size, cp, + HCI_CMD_TIMEOUT); +- kfree(cp); + + if (IS_ERR_OR_NULL(skb)) { +- if (!skb) +- return -EIO; +- return PTR_ERR(skb); ++ err = PTR_ERR(skb); ++ goto out_free; + } + +- return msft_le_monitor_advertisement_cb(hdev, hdev->msft_opcode, +- monitor, skb); ++ err = msft_le_monitor_advertisement_cb(hdev, hdev->msft_opcode, ++ monitor, skb); ++ if (err) ++ goto out_free; ++ ++ handle_data = msft_find_handle_data(hdev, monitor->handle, true); ++ if (!handle_data) { ++ err = -ENODATA; ++ goto out_free; ++ } ++ ++ handle_data->rssi_high = cp->rssi_high; ++ handle_data->rssi_low = cp->rssi_low; ++ handle_data->rssi_low_interval = cp->rssi_low_interval; ++ handle_data->rssi_sampling_period = cp->rssi_sampling_period; ++ ++out_free: ++ kfree(cp); ++ return err; + } + + /* This function requires the caller holds hci_req_sync_lock */ +@@ -538,6 +675,7 @@ void msft_do_close(struct hci_dev *hdev) + { + struct msft_data *msft = hdev->msft_data; + struct msft_monitor_advertisement_handle_data *handle_data, *tmp; ++ struct msft_monitor_addr_filter_data *address_filter, *n; + struct adv_monitor *monitor; + + if (!msft) +@@ -559,6 +697,14 @@ void msft_do_close(struct hci_dev *hdev) + kfree(handle_data); + } + ++ mutex_lock(&msft->filter_lock); ++ list_for_each_entry_safe(address_filter, n, &msft->address_filters, ++ list) { ++ list_del(&address_filter->list); ++ kfree(address_filter); ++ } ++ mutex_unlock(&msft->filter_lock); ++ + hci_dev_lock(hdev); + + /* Clear any devices that are being monitored and notify device lost */ +@@ -568,6 +714,49 @@ void msft_do_close(struct hci_dev *hdev) + hci_dev_unlock(hdev); + } + ++static int msft_cancel_address_filter_sync(struct hci_dev *hdev, void *data) ++{ ++ struct msft_monitor_addr_filter_data *address_filter = data; ++ struct msft_cp_le_cancel_monitor_advertisement cp; ++ struct msft_data *msft = hdev->msft_data; ++ struct sk_buff *skb; ++ int err = 0; ++ ++ if (!msft) { ++ bt_dev_err(hdev, "MSFT: msft data is freed"); ++ return -EINVAL; ++ } ++ ++ /* The address filter has been removed by hci dev close */ ++ if (!test_bit(HCI_UP, &hdev->flags)) ++ return 0; ++ ++ mutex_lock(&msft->filter_lock); ++ list_del(&address_filter->list); ++ mutex_unlock(&msft->filter_lock); ++ ++ cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT; ++ cp.handle = address_filter->msft_handle; ++ ++ skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp, ++ HCI_CMD_TIMEOUT); ++ if (IS_ERR_OR_NULL(skb)) { ++ bt_dev_err(hdev, "MSFT: Failed to cancel address (%pMR) filter", ++ &address_filter->bdaddr); ++ err = EIO; ++ goto done; ++ } ++ kfree_skb(skb); ++ ++ bt_dev_dbg(hdev, "MSFT: Canceled device %pMR address filter", ++ &address_filter->bdaddr); ++ ++done: ++ kfree(address_filter); ++ ++ return err; ++} ++ + void msft_register(struct hci_dev *hdev) + { + struct msft_data *msft = NULL; +@@ -581,7 +770,9 @@ void msft_register(struct hci_dev *hdev) + } + + INIT_LIST_HEAD(&msft->handle_map); ++ INIT_LIST_HEAD(&msft->address_filters); + hdev->msft_data = msft; ++ mutex_init(&msft->filter_lock); + } + + void msft_unregister(struct hci_dev *hdev) +@@ -596,6 +787,7 @@ void msft_unregister(struct hci_dev *hdev) + hdev->msft_data = NULL; + + kfree(msft->evt_prefix); ++ mutex_destroy(&msft->filter_lock); + kfree(msft); + } + +@@ -645,11 +837,149 @@ static void *msft_skb_pull(struct hci_dev *hdev, struct sk_buff *skb, + return data; + } + ++static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data) ++{ ++ struct msft_monitor_addr_filter_data *address_filter = data; ++ struct msft_rp_le_monitor_advertisement *rp; ++ struct msft_cp_le_monitor_advertisement *cp; ++ struct msft_data *msft = hdev->msft_data; ++ struct sk_buff *skb = NULL; ++ bool remove = false; ++ size_t size; ++ ++ if (!msft) { ++ bt_dev_err(hdev, "MSFT: msft data is freed"); ++ return -EINVAL; ++ } ++ ++ /* The address filter has been removed by hci dev close */ ++ if (!test_bit(HCI_UP, &hdev->flags)) ++ return -ENODEV; ++ ++ /* We are safe to use the address filter from now on. ++ * msft_monitor_device_evt() wouldn't delete this filter because it's ++ * not been added by now. ++ * And all other functions that requiring hci_req_sync_lock wouldn't ++ * touch this filter before this func completes because it's protected ++ * by hci_req_sync_lock. ++ */ ++ ++ if (address_filter->state == AF_STATE_REMOVING) { ++ mutex_lock(&msft->filter_lock); ++ list_del(&address_filter->list); ++ mutex_unlock(&msft->filter_lock); ++ kfree(address_filter); ++ return 0; ++ } ++ ++ size = sizeof(*cp) + ++ sizeof(address_filter->addr_type) + ++ sizeof(address_filter->bdaddr); ++ cp = kzalloc(size, GFP_KERNEL); ++ if (!cp) { ++ bt_dev_err(hdev, "MSFT: Alloc cmd param err"); ++ remove = true; ++ goto done; ++ } ++ cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT; ++ cp->rssi_high = address_filter->rssi_high; ++ cp->rssi_low = address_filter->rssi_low; ++ cp->rssi_low_interval = address_filter->rssi_low_interval; ++ cp->rssi_sampling_period = address_filter->rssi_sampling_period; ++ cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_ADDR; ++ cp->data[0] = address_filter->addr_type; ++ memcpy(&cp->data[1], &address_filter->bdaddr, ++ sizeof(address_filter->bdaddr)); ++ ++ skb = __hci_cmd_sync(hdev, hdev->msft_opcode, size, cp, ++ HCI_CMD_TIMEOUT); ++ if (IS_ERR_OR_NULL(skb)) { ++ bt_dev_err(hdev, "Failed to enable address %pMR filter", ++ &address_filter->bdaddr); ++ skb = NULL; ++ remove = true; ++ goto done; ++ } ++ ++ rp = skb_pull_data(skb, sizeof(*rp)); ++ if (!rp || rp->sub_opcode != MSFT_OP_LE_MONITOR_ADVERTISEMENT || ++ rp->status) ++ remove = true; ++ ++done: ++ mutex_lock(&msft->filter_lock); ++ ++ if (remove) { ++ bt_dev_warn(hdev, "MSFT: Remove address (%pMR) filter", ++ &address_filter->bdaddr); ++ list_del(&address_filter->list); ++ kfree(address_filter); ++ } else { ++ address_filter->state = AF_STATE_ADDED; ++ address_filter->msft_handle = rp->handle; ++ bt_dev_dbg(hdev, "MSFT: Address %pMR filter enabled", ++ &address_filter->bdaddr); ++ } ++ mutex_unlock(&msft->filter_lock); ++ ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++/* This function requires the caller holds msft->filter_lock */ ++static struct msft_monitor_addr_filter_data *msft_add_address_filter ++ (struct hci_dev *hdev, u8 addr_type, bdaddr_t *bdaddr, ++ struct msft_monitor_advertisement_handle_data *handle_data) ++{ ++ struct msft_monitor_addr_filter_data *address_filter = NULL; ++ struct msft_data *msft = hdev->msft_data; ++ int err; ++ ++ address_filter = kzalloc(sizeof(*address_filter), GFP_KERNEL); ++ if (!address_filter) ++ return NULL; ++ ++ address_filter->state = AF_STATE_ADDING; ++ address_filter->msft_handle = 0xff; ++ address_filter->pattern_handle = handle_data->msft_handle; ++ address_filter->mgmt_handle = handle_data->mgmt_handle; ++ address_filter->rssi_high = handle_data->rssi_high; ++ address_filter->rssi_low = handle_data->rssi_low; ++ address_filter->rssi_low_interval = handle_data->rssi_low_interval; ++ address_filter->rssi_sampling_period = handle_data->rssi_sampling_period; ++ address_filter->addr_type = addr_type; ++ bacpy(&address_filter->bdaddr, bdaddr); ++ ++ /* With the above AF_STATE_ADDING, duplicated address filter can be ++ * avoided when receiving monitor device event (found/lost) frequently ++ * for the same device. ++ */ ++ list_add_tail(&address_filter->list, &msft->address_filters); ++ ++ err = hci_cmd_sync_queue(hdev, msft_add_address_filter_sync, ++ address_filter, NULL); ++ if (err < 0) { ++ bt_dev_err(hdev, "MSFT: Add address %pMR filter err", bdaddr); ++ list_del(&address_filter->list); ++ kfree(address_filter); ++ return NULL; ++ } ++ ++ bt_dev_dbg(hdev, "MSFT: Add device %pMR address filter", ++ &address_filter->bdaddr); ++ ++ return address_filter; ++} ++ + /* This function requires the caller holds hdev->lock */ + static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb) + { ++ struct msft_monitor_addr_filter_data *n, *address_filter = NULL; + struct msft_ev_le_monitor_device *ev; + struct msft_monitor_advertisement_handle_data *handle_data; ++ struct msft_data *msft = hdev->msft_data; ++ u16 mgmt_handle = 0xffff; + u8 addr_type; + + ev = msft_skb_pull(hdev, skb, MSFT_EV_LE_MONITOR_DEVICE, sizeof(*ev)); +@@ -662,9 +992,53 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb) + ev->monitor_state, &ev->bdaddr); + + handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false); +- if (!handle_data) ++ ++ if (!test_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks)) { ++ if (!handle_data) ++ return; ++ mgmt_handle = handle_data->mgmt_handle; ++ goto report_state; ++ } ++ ++ if (handle_data) { ++ /* Don't report any device found/lost event from pattern ++ * monitors. Pattern monitor always has its address filters for ++ * tracking devices. ++ */ ++ ++ address_filter = msft_find_address_data(hdev, ev->addr_type, ++ &ev->bdaddr, ++ handle_data->msft_handle); ++ if (address_filter) ++ return; ++ ++ if (ev->monitor_state && handle_data->cond_type == ++ MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN) ++ msft_add_address_filter(hdev, ev->addr_type, ++ &ev->bdaddr, handle_data); ++ + return; ++ } + ++ /* This device event is not from pattern monitor. ++ * Report it if there is a corresponding address_filter for it. ++ */ ++ list_for_each_entry(n, &msft->address_filters, list) { ++ if (n->state == AF_STATE_ADDED && ++ n->msft_handle == ev->monitor_handle) { ++ mgmt_handle = n->mgmt_handle; ++ address_filter = n; ++ break; ++ } ++ } ++ ++ if (!address_filter) { ++ bt_dev_warn(hdev, "MSFT: Unexpected device event %pMR, %u, %u", ++ &ev->bdaddr, ev->monitor_handle, ev->monitor_state); ++ return; ++ } ++ ++report_state: + switch (ev->addr_type) { + case ADDR_LE_DEV_PUBLIC: + addr_type = BDADDR_LE_PUBLIC; +@@ -681,12 +1055,18 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb) + return; + } + +- if (ev->monitor_state) +- msft_device_found(hdev, &ev->bdaddr, addr_type, +- handle_data->mgmt_handle); +- else +- msft_device_lost(hdev, &ev->bdaddr, addr_type, +- handle_data->mgmt_handle); ++ if (ev->monitor_state) { ++ msft_device_found(hdev, &ev->bdaddr, addr_type, mgmt_handle); ++ } else { ++ if (address_filter && address_filter->state == AF_STATE_ADDED) { ++ address_filter->state = AF_STATE_REMOVING; ++ hci_cmd_sync_queue(hdev, ++ msft_cancel_address_filter_sync, ++ address_filter, ++ NULL); ++ } ++ msft_device_lost(hdev, &ev->bdaddr, addr_type, mgmt_handle); ++ } + } + + void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) +@@ -724,7 +1104,9 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) + + switch (*evt) { + case MSFT_EV_LE_MONITOR_DEVICE: ++ mutex_lock(&msft->filter_lock); + msft_monitor_device_evt(hdev, skb); ++ mutex_unlock(&msft->filter_lock); + break; + + default: +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 7762604ddfc05..99b149261949a 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -1267,7 +1267,7 @@ static int sco_sock_release(struct socket *sock) + + sco_sock_close(sk); + +- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && ++ if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) && + !(current->flags & PF_EXITING)) { + lock_sock(sk); + err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); +diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c +index b65962682771f..75204d36d7f90 100644 +--- a/net/bridge/br_stp_if.c ++++ b/net/bridge/br_stp_if.c +@@ -201,9 +201,6 @@ int br_stp_set_enabled(struct net_bridge *br, unsigned long val, + { + ASSERT_RTNL(); + +- if (!net_eq(dev_net(br->dev), &init_net)) +- NL_SET_ERR_MSG_MOD(extack, "STP does not work in non-root netns"); +- + if (br_mrp_enabled(br)) { + NL_SET_ERR_MSG_MOD(extack, + "STP can't be enabled if MRP is already enabled"); +diff --git a/net/core/filter.c b/net/core/filter.c +index f15ae393c2767..a9e93d528869f 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -7337,6 +7337,8 @@ BPF_CALL_3(bpf_sk_assign, struct sk_buff *, skb, struct sock *, sk, u64, flags) + return -ENETUNREACH; + if (unlikely(sk_fullsock(sk) && sk->sk_reuseport)) + return -ESOCKTNOSUPPORT; ++ if (sk_unhashed(sk)) ++ return -EOPNOTSUPP; + if (sk_is_refcounted(sk) && + unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) + return -ENOENT; +diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c +index 8b6b5e72b2179..4a0797f0a154b 100644 +--- a/net/core/lwt_bpf.c ++++ b/net/core/lwt_bpf.c +@@ -60,9 +60,8 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt, + ret = BPF_OK; + } else { + skb_reset_mac_header(skb); +- ret = skb_do_redirect(skb); +- if (ret == 0) +- ret = BPF_REDIRECT; ++ skb_do_redirect(skb); ++ ret = BPF_REDIRECT; + } + break; + +@@ -255,7 +254,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) + + err = dst_output(dev_net(skb_dst(skb)->dev), skb->sk, skb); + if (unlikely(err)) +- return err; ++ return net_xmit_errno(err); + + /* ip[6]_finish_output2 understand LWTUNNEL_XMIT_DONE */ + return LWTUNNEL_XMIT_DONE; +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 593ec18e3f007..0c0fef73be709 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -559,7 +559,7 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node, + bool *pfmemalloc) + { + bool ret_pfmemalloc = false; +- unsigned int obj_size; ++ size_t obj_size; + void *obj; + + obj_size = SKB_HEAD_ALIGN(*size); +@@ -578,7 +578,13 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node, + goto out; + } + #endif +- *size = obj_size = kmalloc_size_roundup(obj_size); ++ ++ obj_size = kmalloc_size_roundup(obj_size); ++ /* The following cast might truncate high-order bits of obj_size, this ++ * is harmless because kmalloc(obj_size >= 2^32) will fail anyway. ++ */ ++ *size = (unsigned int)obj_size; ++ + /* + * Try a regular allocation, when that fails and we're not entitled + * to the reserves, fail. +@@ -4364,21 +4370,20 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, + struct sk_buff *segs = NULL; + struct sk_buff *tail = NULL; + struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list; +- skb_frag_t *frag = skb_shinfo(head_skb)->frags; + unsigned int mss = skb_shinfo(head_skb)->gso_size; + unsigned int doffset = head_skb->data - skb_mac_header(head_skb); +- struct sk_buff *frag_skb = head_skb; + unsigned int offset = doffset; + unsigned int tnl_hlen = skb_tnl_header_len(head_skb); + unsigned int partial_segs = 0; + unsigned int headroom; + unsigned int len = head_skb->len; ++ struct sk_buff *frag_skb; ++ skb_frag_t *frag; + __be16 proto; + bool csum, sg; +- int nfrags = skb_shinfo(head_skb)->nr_frags; + int err = -ENOMEM; + int i = 0; +- int pos; ++ int nfrags, pos; + + if ((skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY) && + mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb)) { +@@ -4455,6 +4460,13 @@ normal: + headroom = skb_headroom(head_skb); + pos = skb_headlen(head_skb); + ++ if (skb_orphan_frags(head_skb, GFP_ATOMIC)) ++ return ERR_PTR(-ENOMEM); ++ ++ nfrags = skb_shinfo(head_skb)->nr_frags; ++ frag = skb_shinfo(head_skb)->frags; ++ frag_skb = head_skb; ++ + do { + struct sk_buff *nskb; + skb_frag_t *nskb_frag; +@@ -4475,6 +4487,10 @@ normal: + (skb_headlen(list_skb) == len || sg)) { + BUG_ON(skb_headlen(list_skb) > len); + ++ nskb = skb_clone(list_skb, GFP_ATOMIC); ++ if (unlikely(!nskb)) ++ goto err; ++ + i = 0; + nfrags = skb_shinfo(list_skb)->nr_frags; + frag = skb_shinfo(list_skb)->frags; +@@ -4493,12 +4509,8 @@ normal: + frag++; + } + +- nskb = skb_clone(list_skb, GFP_ATOMIC); + list_skb = list_skb->next; + +- if (unlikely(!nskb)) +- goto err; +- + if (unlikely(pskb_trim(nskb, len))) { + kfree_skb(nskb); + goto err; +@@ -4574,12 +4586,16 @@ normal: + skb_shinfo(nskb)->flags |= skb_shinfo(head_skb)->flags & + SKBFL_SHARED_FRAG; + +- if (skb_orphan_frags(frag_skb, GFP_ATOMIC) || +- skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) ++ if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) + goto err; + + while (pos < offset + len) { + if (i >= nfrags) { ++ if (skb_orphan_frags(list_skb, GFP_ATOMIC) || ++ skb_zerocopy_clone(nskb, list_skb, ++ GFP_ATOMIC)) ++ goto err; ++ + i = 0; + nfrags = skb_shinfo(list_skb)->nr_frags; + frag = skb_shinfo(list_skb)->frags; +@@ -4593,10 +4609,6 @@ normal: + i--; + frag--; + } +- if (skb_orphan_frags(frag_skb, GFP_ATOMIC) || +- skb_zerocopy_clone(nskb, frag_skb, +- GFP_ATOMIC)) +- goto err; + + list_skb = list_skb->next; + } +diff --git a/net/core/sock.c b/net/core/sock.c +index 8451a95266bf0..b2083a359ec10 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -425,6 +425,7 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, + { + struct __kernel_sock_timeval tv; + int err = sock_copy_user_timeval(&tv, optval, optlen, old_timeval); ++ long val; + + if (err) + return err; +@@ -435,7 +436,7 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, + if (tv.tv_sec < 0) { + static int warned __read_mostly; + +- *timeo_p = 0; ++ WRITE_ONCE(*timeo_p, 0); + if (warned < 10 && net_ratelimit()) { + warned++; + pr_info("%s: `%s' (pid %d) tries to set negative timeout\n", +@@ -443,11 +444,12 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, + } + return 0; + } +- *timeo_p = MAX_SCHEDULE_TIMEOUT; +- if (tv.tv_sec == 0 && tv.tv_usec == 0) +- return 0; +- if (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1)) +- *timeo_p = tv.tv_sec * HZ + DIV_ROUND_UP((unsigned long)tv.tv_usec, USEC_PER_SEC / HZ); ++ val = MAX_SCHEDULE_TIMEOUT; ++ if ((tv.tv_sec || tv.tv_usec) && ++ (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1))) ++ val = tv.tv_sec * HZ + DIV_ROUND_UP((unsigned long)tv.tv_usec, ++ USEC_PER_SEC / HZ); ++ WRITE_ONCE(*timeo_p, val); + return 0; + } + +@@ -791,7 +793,7 @@ EXPORT_SYMBOL(sock_set_reuseport); + void sock_no_linger(struct sock *sk) + { + lock_sock(sk); +- sk->sk_lingertime = 0; ++ WRITE_ONCE(sk->sk_lingertime, 0); + sock_set_flag(sk, SOCK_LINGER); + release_sock(sk); + } +@@ -809,9 +811,9 @@ void sock_set_sndtimeo(struct sock *sk, s64 secs) + { + lock_sock(sk); + if (secs && secs < MAX_SCHEDULE_TIMEOUT / HZ - 1) +- sk->sk_sndtimeo = secs * HZ; ++ WRITE_ONCE(sk->sk_sndtimeo, secs * HZ); + else +- sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; ++ WRITE_ONCE(sk->sk_sndtimeo, MAX_SCHEDULE_TIMEOUT); + release_sock(sk); + } + EXPORT_SYMBOL(sock_set_sndtimeo); +@@ -1224,15 +1226,15 @@ set_sndbuf: + ret = -EFAULT; + break; + } +- if (!ling.l_onoff) ++ if (!ling.l_onoff) { + sock_reset_flag(sk, SOCK_LINGER); +- else { +-#if (BITS_PER_LONG == 32) +- if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) +- sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; ++ } else { ++ unsigned long t_sec = ling.l_linger; ++ ++ if (t_sec >= MAX_SCHEDULE_TIMEOUT / HZ) ++ WRITE_ONCE(sk->sk_lingertime, MAX_SCHEDULE_TIMEOUT); + else +-#endif +- sk->sk_lingertime = (unsigned int)ling.l_linger * HZ; ++ WRITE_ONCE(sk->sk_lingertime, t_sec * HZ); + sock_set_flag(sk, SOCK_LINGER); + } + break; +@@ -1678,7 +1680,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, + case SO_LINGER: + lv = sizeof(v.ling); + v.ling.l_onoff = sock_flag(sk, SOCK_LINGER); +- v.ling.l_linger = sk->sk_lingertime / HZ; ++ v.ling.l_linger = READ_ONCE(sk->sk_lingertime) / HZ; + break; + + case SO_BSDCOMPAT: +@@ -1710,12 +1712,14 @@ int sk_getsockopt(struct sock *sk, int level, int optname, + + case SO_RCVTIMEO_OLD: + case SO_RCVTIMEO_NEW: +- lv = sock_get_timeout(sk->sk_rcvtimeo, &v, SO_RCVTIMEO_OLD == optname); ++ lv = sock_get_timeout(READ_ONCE(sk->sk_rcvtimeo), &v, ++ SO_RCVTIMEO_OLD == optname); + break; + + case SO_SNDTIMEO_OLD: + case SO_SNDTIMEO_NEW: +- lv = sock_get_timeout(sk->sk_sndtimeo, &v, SO_SNDTIMEO_OLD == optname); ++ lv = sock_get_timeout(READ_ONCE(sk->sk_sndtimeo), &v, ++ SO_SNDTIMEO_OLD == optname); + break; + + case SO_RCVLOWAT: +diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c +index e7b9703bd1a1a..1097a13b07a06 100644 +--- a/net/dccp/ipv4.c ++++ b/net/dccp/ipv4.c +@@ -255,12 +255,17 @@ static int dccp_v4_err(struct sk_buff *skb, u32 info) + int err; + struct net *net = dev_net(skb->dev); + +- /* Only need dccph_dport & dccph_sport which are the first +- * 4 bytes in dccp header. ++ /* For the first __dccp_basic_hdr_len() check, we only need dh->dccph_x, ++ * which is in byte 7 of the dccp header. + * Our caller (icmp_socket_deliver()) already pulled 8 bytes for us. ++ * ++ * Later on, we want to access the sequence number fields, which are ++ * beyond 8 bytes, so we have to pskb_may_pull() ourselves. + */ +- BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8); +- BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8); ++ dh = (struct dccp_hdr *)(skb->data + offset); ++ if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh))) ++ return -EINVAL; ++ iph = (struct iphdr *)skb->data; + dh = (struct dccp_hdr *)(skb->data + offset); + + sk = __inet_lookup_established(net, &dccp_hashinfo, +diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c +index 94b69a50c8b50..278bd6dc043f9 100644 +--- a/net/dccp/ipv6.c ++++ b/net/dccp/ipv6.c +@@ -74,7 +74,7 @@ static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb) + static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) + { +- const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; ++ const struct ipv6hdr *hdr; + const struct dccp_hdr *dh; + struct dccp_sock *dp; + struct ipv6_pinfo *np; +@@ -83,12 +83,17 @@ static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + __u64 seq; + struct net *net = dev_net(skb->dev); + +- /* Only need dccph_dport & dccph_sport which are the first +- * 4 bytes in dccp header. ++ /* For the first __dccp_basic_hdr_len() check, we only need dh->dccph_x, ++ * which is in byte 7 of the dccp header. + * Our caller (icmpv6_notify()) already pulled 8 bytes for us. ++ * ++ * Later on, we want to access the sequence number fields, which are ++ * beyond 8 bytes, so we have to pskb_may_pull() ourselves. + */ +- BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8); +- BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8); ++ dh = (struct dccp_hdr *)(skb->data + offset); ++ if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh))) ++ return -EINVAL; ++ hdr = (const struct ipv6hdr *)skb->data; + dh = (struct dccp_hdr *)(skb->data + offset); + + sk = __inet6_lookup_established(net, &dccp_hashinfo, +diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c +index 48ff5f13e7979..193d8362efe2e 100644 +--- a/net/ipv4/igmp.c ++++ b/net/ipv4/igmp.c +@@ -353,8 +353,9 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) + struct flowi4 fl4; + int hlen = LL_RESERVED_SPACE(dev); + int tlen = dev->needed_tailroom; +- unsigned int size = mtu; ++ unsigned int size; + ++ size = min(mtu, IP_MAX_MTU); + while (1) { + skb = alloc_skb(size + hlen + tlen, + GFP_ATOMIC | __GFP_NOWARN); +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 6f6f63cf9224f..625da48741a4f 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -216,7 +216,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s + if (lwtunnel_xmit_redirect(dst->lwtstate)) { + int res = lwtunnel_xmit(skb); + +- if (res < 0 || res == LWTUNNEL_XMIT_DONE) ++ if (res != LWTUNNEL_XMIT_CONTINUE) + return res; + } + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 57f1e4883b761..094b3e266bbea 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -287,7 +287,7 @@ static void tcp_incr_quickack(struct sock *sk, unsigned int max_quickacks) + icsk->icsk_ack.quick = quickacks; + } + +-void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks) ++static void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks) + { + struct inet_connection_sock *icsk = inet_csk(sk); + +@@ -295,7 +295,6 @@ void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks) + inet_csk_exit_pingpong_mode(sk); + icsk->icsk_ack.ato = TCP_ATO_MIN; + } +-EXPORT_SYMBOL(tcp_enter_quickack_mode); + + /* Send ACKs quickly, if "quick" count is not exhausted + * and the session is not interactive. +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index 366c3c25ebe20..db90bd2d4ed66 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -441,6 +441,22 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req) + req->timeout << req->num_timeout, TCP_RTO_MAX); + } + ++static bool tcp_rtx_probe0_timed_out(const struct sock *sk, ++ const struct sk_buff *skb) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const int timeout = TCP_RTO_MAX * 2; ++ u32 rcv_delta, rtx_delta; ++ ++ rcv_delta = inet_csk(sk)->icsk_timeout - tp->rcv_tstamp; ++ if (rcv_delta <= timeout) ++ return false; ++ ++ rtx_delta = (u32)msecs_to_jiffies(tcp_time_stamp(tp) - ++ (tp->retrans_stamp ?: tcp_skb_timestamp(skb))); ++ ++ return rtx_delta > timeout; ++} + + /** + * tcp_retransmit_timer() - The TCP retransmit timeout handler +@@ -506,7 +522,7 @@ void tcp_retransmit_timer(struct sock *sk) + tp->snd_una, tp->snd_nxt); + } + #endif +- if (tcp_jiffies32 - tp->rcv_tstamp > TCP_RTO_MAX) { ++ if (tcp_rtx_probe0_timed_out(sk, skb)) { + tcp_write_err(sk); + goto out; + } +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 6d327d6d978c5..a3302136ce92e 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -452,14 +452,24 @@ static struct sock *udp4_lib_lookup2(struct net *net, + score = compute_score(sk, net, saddr, sport, + daddr, hnum, dif, sdif); + if (score > badness) { +- result = lookup_reuseport(net, sk, skb, +- saddr, sport, daddr, hnum); ++ badness = score; ++ result = lookup_reuseport(net, sk, skb, saddr, sport, daddr, hnum); ++ if (!result) { ++ result = sk; ++ continue; ++ } ++ + /* Fall back to scoring if group has connections */ +- if (result && !reuseport_has_conns(sk)) ++ if (!reuseport_has_conns(sk)) + return result; + +- result = result ? : sk; +- badness = score; ++ /* Reuseport logic returned an error, keep original score. */ ++ if (IS_ERR(result)) ++ continue; ++ ++ badness = compute_score(result, net, saddr, sport, ++ daddr, hnum, dif, sdif); ++ + } + } + return result; +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 4a27fab1d09a3..50f8d2ac4e246 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -113,7 +113,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * + if (lwtunnel_xmit_redirect(dst->lwtstate)) { + int res = lwtunnel_xmit(skb); + +- if (res < 0 || res == LWTUNNEL_XMIT_DONE) ++ if (res != LWTUNNEL_XMIT_CONTINUE) + return res; + } + +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 8521729fb2375..9c7457823eb97 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -195,14 +195,23 @@ static struct sock *udp6_lib_lookup2(struct net *net, + score = compute_score(sk, net, saddr, sport, + daddr, hnum, dif, sdif); + if (score > badness) { +- result = lookup_reuseport(net, sk, skb, +- saddr, sport, daddr, hnum); ++ badness = score; ++ result = lookup_reuseport(net, sk, skb, saddr, sport, daddr, hnum); ++ if (!result) { ++ result = sk; ++ continue; ++ } ++ + /* Fall back to scoring if group has connections */ +- if (result && !reuseport_has_conns(sk)) ++ if (!reuseport_has_conns(sk)) + return result; + +- result = result ? : sk; +- badness = score; ++ /* Reuseport logic returned an error, keep original score. */ ++ if (IS_ERR(result)) ++ continue; ++ ++ badness = compute_score(sk, net, saddr, sport, ++ daddr, hnum, dif, sdif); + } + } + return result; +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index f2d08dbccfb7d..30d69091064fe 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3640,12 +3640,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + +- if (sdata->vif.bss_conf.eht_puncturing != sdata->vif.bss_conf.csa_punct_bitmap) { +- sdata->vif.bss_conf.eht_puncturing = +- sdata->vif.bss_conf.csa_punct_bitmap; +- changed |= BSS_CHANGED_EHT_PUNCTURING; +- } +- + /* + * using reservation isn't immediate as it may be deferred until later + * with multi-vif. once reservation is complete it will re-schedule the +@@ -3675,6 +3669,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) + if (err) + return err; + ++ if (sdata->vif.bss_conf.eht_puncturing != sdata->vif.bss_conf.csa_punct_bitmap) { ++ sdata->vif.bss_conf.eht_puncturing = ++ sdata->vif.bss_conf.csa_punct_bitmap; ++ changed |= BSS_CHANGED_EHT_PUNCTURING; ++ } ++ + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); + + if (sdata->deflink.csa_block_tx) { +diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c +index 005a7ce87217e..bf4f91b78e1dc 100644 +--- a/net/netfilter/ipset/ip_set_hash_netportnet.c ++++ b/net/netfilter/ipset/ip_set_hash_netportnet.c +@@ -36,6 +36,7 @@ MODULE_ALIAS("ip_set_hash:net,port,net"); + #define IP_SET_HASH_WITH_PROTO + #define IP_SET_HASH_WITH_NETS + #define IPSET_NET_COUNT 2 ++#define IP_SET_HASH_WITH_NET0 + + /* IPv4 variant */ + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index a54a7f772cec2..7effc7260fec8 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -237,7 +237,12 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr, + if (!tcph) + goto err; + ++ if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len)) ++ goto err; ++ ++ tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt)); + opt = (u8 *)tcph; ++ + for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) { + union { + __be16 v16; +@@ -252,15 +257,6 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr, + if (i + optl > tcphdr_len || priv->len + priv->offset > optl) + goto err; + +- if (skb_ensure_writable(pkt->skb, +- nft_thoff(pkt) + i + priv->len)) +- goto err; +- +- tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff, +- &tcphdr_len); +- if (!tcph) +- goto err; +- + offset = i + priv->offset; + + switch (priv->len) { +@@ -324,9 +320,9 @@ static void nft_exthdr_tcp_strip_eval(const struct nft_expr *expr, + if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len)) + goto drop; + +- opt = (u8 *)nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len); +- if (!opt) +- goto err; ++ tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt)); ++ opt = (u8 *)tcph; ++ + for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) { + unsigned int j; + +diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c +index e8961094a2822..b46a6a5120583 100644 +--- a/net/netfilter/xt_sctp.c ++++ b/net/netfilter/xt_sctp.c +@@ -149,6 +149,8 @@ static int sctp_mt_check(const struct xt_mtchk_param *par) + { + const struct xt_sctp_info *info = par->matchinfo; + ++ if (info->flag_count > ARRAY_SIZE(info->flag_info)) ++ return -EINVAL; + if (info->flags & ~XT_SCTP_VALID_FLAGS) + return -EINVAL; + if (info->invflags & ~XT_SCTP_VALID_FLAGS) +diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c +index 177b40d08098b..117d4615d6684 100644 +--- a/net/netfilter/xt_u32.c ++++ b/net/netfilter/xt_u32.c +@@ -96,11 +96,32 @@ static bool u32_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret ^ data->invert; + } + ++static int u32_mt_checkentry(const struct xt_mtchk_param *par) ++{ ++ const struct xt_u32 *data = par->matchinfo; ++ const struct xt_u32_test *ct; ++ unsigned int i; ++ ++ if (data->ntests > ARRAY_SIZE(data->tests)) ++ return -EINVAL; ++ ++ for (i = 0; i < data->ntests; ++i) { ++ ct = &data->tests[i]; ++ ++ if (ct->nnums > ARRAY_SIZE(ct->location) || ++ ct->nvalues > ARRAY_SIZE(ct->value)) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static struct xt_match xt_u32_mt_reg __read_mostly = { + .name = "u32", + .revision = 0, + .family = NFPROTO_UNSPEC, + .match = u32_mt, ++ .checkentry = u32_mt_checkentry, + .matchsize = sizeof(struct xt_u32), + .me = THIS_MODULE, + }; +diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c +index 5a4cb796150f5..ec5747969f964 100644 +--- a/net/netrom/af_netrom.c ++++ b/net/netrom/af_netrom.c +@@ -660,6 +660,11 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, + goto out_release; + } + ++ if (sock->state == SS_CONNECTING) { ++ err = -EALREADY; ++ goto out_release; ++ } ++ + sk->sk_state = TCP_CLOSE; + sock->state = SS_UNCONNECTED; + +diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c +index af85a73c4c545..da34fd4c92695 100644 +--- a/net/sched/em_meta.c ++++ b/net/sched/em_meta.c +@@ -502,7 +502,7 @@ META_COLLECTOR(int_sk_lingertime) + *err = -1; + return; + } +- dst->value = sk->sk_lingertime / HZ; ++ dst->value = READ_ONCE(sk->sk_lingertime) / HZ; + } + + META_COLLECTOR(int_sk_err_qlen) +@@ -568,7 +568,7 @@ META_COLLECTOR(int_sk_rcvtimeo) + *err = -1; + return; + } +- dst->value = sk->sk_rcvtimeo / HZ; ++ dst->value = READ_ONCE(sk->sk_rcvtimeo) / HZ; + } + + META_COLLECTOR(int_sk_sndtimeo) +@@ -579,7 +579,7 @@ META_COLLECTOR(int_sk_sndtimeo) + *err = -1; + return; + } +- dst->value = sk->sk_sndtimeo / HZ; ++ dst->value = READ_ONCE(sk->sk_sndtimeo) / HZ; + } + + META_COLLECTOR(int_sk_sendmsg_off) +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 70b0c5873d326..61d52594ff6d8 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -1012,6 +1012,10 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (parent == NULL) + return -ENOENT; + } ++ if (!(parent->cl_flags & HFSC_FSC) && parent != &q->root) { ++ NL_SET_ERR_MSG(extack, "Invalid parent - parent class must have FSC"); ++ return -EINVAL; ++ } + + if (classid == 0 || TC_H_MAJ(classid ^ sch->handle) != 0) + return -EINVAL; +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index f94e7a04e33d0..462ece6bb1802 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1820,7 +1820,7 @@ void smc_close_non_accepted(struct sock *sk) + lock_sock(sk); + if (!sk->sk_lingertime) + /* wait for peer closing */ +- sk->sk_lingertime = SMC_MAX_STREAM_WAIT_TIMEOUT; ++ WRITE_ONCE(sk->sk_lingertime, SMC_MAX_STREAM_WAIT_TIMEOUT); + __smc_release(smc); + release_sock(sk); + sock_put(sk); /* sock_hold above */ +diff --git a/net/socket.c b/net/socket.c +index b7e01d0fe0824..5da8bb1ff8eab 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -3528,7 +3528,11 @@ EXPORT_SYMBOL(kernel_accept); + int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, + int flags) + { +- return sock->ops->connect(sock, addr, addrlen, flags); ++ struct sockaddr_storage address; ++ ++ memcpy(&address, addr, addrlen); ++ ++ return sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, flags); + } + EXPORT_SYMBOL(kernel_connect); + +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index 1b688745ce0a1..be798ce8a20ff 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -323,6 +323,7 @@ nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { + [NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG }, + [NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG }, + [NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK] = { .type = NLA_FLAG }, ++ [NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR] = { .type = NLA_U8 }, + }; + + static const struct nla_policy +diff --git a/samples/bpf/tracex3_kern.c b/samples/bpf/tracex3_kern.c +index bde6591cb20c5..af235bd6615b1 100644 +--- a/samples/bpf/tracex3_kern.c ++++ b/samples/bpf/tracex3_kern.c +@@ -11,6 +11,12 @@ + #include <bpf/bpf_helpers.h> + #include <bpf/bpf_tracing.h> + ++struct start_key { ++ dev_t dev; ++ u32 _pad; ++ sector_t sector; ++}; ++ + struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, long); +@@ -18,16 +24,17 @@ struct { + __uint(max_entries, 4096); + } my_map SEC(".maps"); + +-/* kprobe is NOT a stable ABI. If kernel internals change this bpf+kprobe +- * example will no longer be meaningful +- */ +-SEC("kprobe/blk_mq_start_request") +-int bpf_prog1(struct pt_regs *ctx) ++/* from /sys/kernel/tracing/events/block/block_io_start/format */ ++SEC("tracepoint/block/block_io_start") ++int bpf_prog1(struct trace_event_raw_block_rq *ctx) + { +- long rq = PT_REGS_PARM1(ctx); + u64 val = bpf_ktime_get_ns(); ++ struct start_key key = { ++ .dev = ctx->dev, ++ .sector = ctx->sector ++ }; + +- bpf_map_update_elem(&my_map, &rq, &val, BPF_ANY); ++ bpf_map_update_elem(&my_map, &key, &val, BPF_ANY); + return 0; + } + +@@ -49,21 +56,26 @@ struct { + __uint(max_entries, SLOTS); + } lat_map SEC(".maps"); + +-SEC("kprobe/__blk_account_io_done") +-int bpf_prog2(struct pt_regs *ctx) ++/* from /sys/kernel/tracing/events/block/block_io_done/format */ ++SEC("tracepoint/block/block_io_done") ++int bpf_prog2(struct trace_event_raw_block_rq *ctx) + { +- long rq = PT_REGS_PARM1(ctx); ++ struct start_key key = { ++ .dev = ctx->dev, ++ .sector = ctx->sector ++ }; ++ + u64 *value, l, base; + u32 index; + +- value = bpf_map_lookup_elem(&my_map, &rq); ++ value = bpf_map_lookup_elem(&my_map, &key); + if (!value) + return 0; + + u64 cur_time = bpf_ktime_get_ns(); + u64 delta = cur_time - *value; + +- bpf_map_delete_elem(&my_map, &rq); ++ bpf_map_delete_elem(&my_map, &key); + + /* the lines below are computing index = log10(delta)*10 + * using integer arithmetic +diff --git a/samples/bpf/tracex6_kern.c b/samples/bpf/tracex6_kern.c +index acad5712d8b4f..fd602c2774b8b 100644 +--- a/samples/bpf/tracex6_kern.c ++++ b/samples/bpf/tracex6_kern.c +@@ -2,6 +2,8 @@ + #include <linux/version.h> + #include <uapi/linux/bpf.h> + #include <bpf/bpf_helpers.h> ++#include <bpf/bpf_tracing.h> ++#include <bpf/bpf_core_read.h> + + struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); +@@ -45,13 +47,24 @@ int bpf_prog1(struct pt_regs *ctx) + return 0; + } + +-SEC("kprobe/htab_map_lookup_elem") +-int bpf_prog2(struct pt_regs *ctx) ++/* ++ * Since *_map_lookup_elem can't be expected to trigger bpf programs ++ * due to potential deadlocks (bpf_disable_instrumentation), this bpf ++ * program will be attached to bpf_map_copy_value (which is called ++ * from map_lookup_elem) and will only filter the hashtable type. ++ */ ++SEC("kprobe/bpf_map_copy_value") ++int BPF_KPROBE(bpf_prog2, struct bpf_map *map) + { + u32 key = bpf_get_smp_processor_id(); + struct bpf_perf_event_value *val, buf; ++ enum bpf_map_type type; + int error; + ++ type = BPF_CORE_READ(map, map_type); ++ if (type != BPF_MAP_TYPE_HASH) ++ return 0; ++ + error = bpf_perf_event_read_value(&counters, key, &buf, sizeof(buf)); + if (error) + return 0; +diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in +index 50a92c4e9984e..fab74ca9df6fc 100644 +--- a/scripts/gdb/linux/constants.py.in ++++ b/scripts/gdb/linux/constants.py.in +@@ -64,6 +64,9 @@ LX_GDBPARSED(IRQ_HIDDEN) + + /* linux/module.h */ + LX_GDBPARSED(MOD_TEXT) ++LX_GDBPARSED(MOD_DATA) ++LX_GDBPARSED(MOD_RODATA) ++LX_GDBPARSED(MOD_RO_AFTER_INIT) + + /* linux/mount.h */ + LX_VALUE(MNT_NOSUID) +diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py +index 261f28640f4cd..f76a43bfa15fc 100644 +--- a/scripts/gdb/linux/modules.py ++++ b/scripts/gdb/linux/modules.py +@@ -73,11 +73,17 @@ class LxLsmod(gdb.Command): + " " if utils.get_long_type().sizeof == 8 else "")) + + for module in module_list(): +- layout = module['mem'][constants.LX_MOD_TEXT] ++ text = module['mem'][constants.LX_MOD_TEXT] ++ text_addr = str(text['base']).split()[0] ++ total_size = 0 ++ ++ for i in range(constants.LX_MOD_TEXT, constants.LX_MOD_RO_AFTER_INIT + 1): ++ total_size += module['mem'][i]['size'] ++ + gdb.write("{address} {name:<19} {size:>8} {ref}".format( +- address=str(layout['base']).split()[0], ++ address=text_addr, + name=module['name'].string(), +- size=str(layout['size']), ++ size=str(total_size), + ref=str(module['refcnt']['counter'] - 1))) + + t = self._module_use_type.get_type().pointer() +diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh +index aebbf19139709..7a925d2b20fc7 100755 +--- a/scripts/rust_is_available.sh ++++ b/scripts/rust_is_available.sh +@@ -2,8 +2,6 @@ + # SPDX-License-Identifier: GPL-2.0 + # + # Tests whether a suitable Rust toolchain is available. +-# +-# Pass `-v` for human output and more checks (as warnings). + + set -e + +@@ -23,21 +21,17 @@ get_canonical_version() + + # Check that the Rust compiler exists. + if ! command -v "$RUSTC" >/dev/null; then +- if [ "$1" = -v ]; then +- echo >&2 "***" +- echo >&2 "*** Rust compiler '$RUSTC' could not be found." +- echo >&2 "***" +- fi ++ echo >&2 "***" ++ echo >&2 "*** Rust compiler '$RUSTC' could not be found." ++ echo >&2 "***" + exit 1 + fi + + # Check that the Rust bindings generator exists. + if ! command -v "$BINDGEN" >/dev/null; then +- if [ "$1" = -v ]; then +- echo >&2 "***" +- echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found." +- echo >&2 "***" +- fi ++ echo >&2 "***" ++ echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found." ++ echo >&2 "***" + exit 1 + fi + +@@ -53,16 +47,14 @@ rust_compiler_min_version=$($min_tool_version rustc) + rust_compiler_cversion=$(get_canonical_version $rust_compiler_version) + rust_compiler_min_cversion=$(get_canonical_version $rust_compiler_min_version) + if [ "$rust_compiler_cversion" -lt "$rust_compiler_min_cversion" ]; then +- if [ "$1" = -v ]; then +- echo >&2 "***" +- echo >&2 "*** Rust compiler '$RUSTC' is too old." +- echo >&2 "*** Your version: $rust_compiler_version" +- echo >&2 "*** Minimum version: $rust_compiler_min_version" +- echo >&2 "***" +- fi ++ echo >&2 "***" ++ echo >&2 "*** Rust compiler '$RUSTC' is too old." ++ echo >&2 "*** Your version: $rust_compiler_version" ++ echo >&2 "*** Minimum version: $rust_compiler_min_version" ++ echo >&2 "***" + exit 1 + fi +-if [ "$1" = -v ] && [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then ++if [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then + echo >&2 "***" + echo >&2 "*** Rust compiler '$RUSTC' is too new. This may or may not work." + echo >&2 "*** Your version: $rust_compiler_version" +@@ -82,16 +74,14 @@ rust_bindings_generator_min_version=$($min_tool_version bindgen) + rust_bindings_generator_cversion=$(get_canonical_version $rust_bindings_generator_version) + rust_bindings_generator_min_cversion=$(get_canonical_version $rust_bindings_generator_min_version) + if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cversion" ]; then +- if [ "$1" = -v ]; then +- echo >&2 "***" +- echo >&2 "*** Rust bindings generator '$BINDGEN' is too old." +- echo >&2 "*** Your version: $rust_bindings_generator_version" +- echo >&2 "*** Minimum version: $rust_bindings_generator_min_version" +- echo >&2 "***" +- fi ++ echo >&2 "***" ++ echo >&2 "*** Rust bindings generator '$BINDGEN' is too old." ++ echo >&2 "*** Your version: $rust_bindings_generator_version" ++ echo >&2 "*** Minimum version: $rust_bindings_generator_min_version" ++ echo >&2 "***" + exit 1 + fi +-if [ "$1" = -v ] && [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then ++if [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then + echo >&2 "***" + echo >&2 "*** Rust bindings generator '$BINDGEN' is too new. This may or may not work." + echo >&2 "*** Your version: $rust_bindings_generator_version" +@@ -100,23 +90,39 @@ if [ "$1" = -v ] && [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_ge + fi + + # Check that the `libclang` used by the Rust bindings generator is suitable. ++# ++# In order to do that, first invoke `bindgen` to get the `libclang` version ++# found by `bindgen`. This step may already fail if, for instance, `libclang` ++# is not found, thus inform the user in such a case. ++bindgen_libclang_output=$( \ ++ LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null ++) || bindgen_libclang_code=$? ++if [ -n "$bindgen_libclang_code" ]; then ++ echo >&2 "***" ++ echo >&2 "*** Running '$BINDGEN' to check the libclang version (used by the Rust" ++ echo >&2 "*** bindings generator) failed with code $bindgen_libclang_code. This may be caused by" ++ echo >&2 "*** a failure to locate libclang. See output and docs below for details:" ++ echo >&2 "***" ++ echo >&2 "$bindgen_libclang_output" ++ echo >&2 "***" ++ exit 1 ++fi ++ ++# `bindgen` returned successfully, thus use the output to check that the version ++# of the `libclang` found by the Rust bindings generator is suitable. + bindgen_libclang_version=$( \ +- LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null \ +- | grep -F 'clang version ' \ +- | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \ +- | head -n 1 \ ++ echo "$bindgen_libclang_output" \ ++ | sed -nE 's:.*clang version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p' + ) + bindgen_libclang_min_version=$($min_tool_version llvm) + bindgen_libclang_cversion=$(get_canonical_version $bindgen_libclang_version) + bindgen_libclang_min_cversion=$(get_canonical_version $bindgen_libclang_min_version) + if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then +- if [ "$1" = -v ]; then +- echo >&2 "***" +- echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') is too old." +- echo >&2 "*** Your version: $bindgen_libclang_version" +- echo >&2 "*** Minimum version: $bindgen_libclang_min_version" +- echo >&2 "***" +- fi ++ echo >&2 "***" ++ echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') is too old." ++ echo >&2 "*** Your version: $bindgen_libclang_version" ++ echo >&2 "*** Minimum version: $bindgen_libclang_min_version" ++ echo >&2 "***" + exit 1 + fi + +@@ -125,21 +131,19 @@ fi + # + # In the future, we might be able to perform a full version check, see + # https://github.com/rust-lang/rust-bindgen/issues/2138. +-if [ "$1" = -v ]; then +- cc_name=$($(dirname $0)/cc-version.sh "$CC" | cut -f1 -d' ') +- if [ "$cc_name" = Clang ]; then +- clang_version=$( \ +- LC_ALL=C "$CC" --version 2>/dev/null \ +- | sed -nE '1s:.*version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p' +- ) +- if [ "$clang_version" != "$bindgen_libclang_version" ]; then +- echo >&2 "***" +- echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN')" +- echo >&2 "*** version does not match Clang's. This may be a problem." +- echo >&2 "*** libclang version: $bindgen_libclang_version" +- echo >&2 "*** Clang version: $clang_version" +- echo >&2 "***" +- fi ++cc_name=$($(dirname $0)/cc-version.sh $CC | cut -f1 -d' ') ++if [ "$cc_name" = Clang ]; then ++ clang_version=$( \ ++ LC_ALL=C $CC --version 2>/dev/null \ ++ | sed -nE '1s:.*version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p' ++ ) ++ if [ "$clang_version" != "$bindgen_libclang_version" ]; then ++ echo >&2 "***" ++ echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN')" ++ echo >&2 "*** version does not match Clang's. This may be a problem." ++ echo >&2 "*** libclang version: $bindgen_libclang_version" ++ echo >&2 "*** Clang version: $clang_version" ++ echo >&2 "***" + fi + fi + +@@ -150,11 +154,9 @@ rustc_sysroot=$("$RUSTC" $KRUSTFLAGS --print sysroot) + rustc_src=${RUST_LIB_SRC:-"$rustc_sysroot/lib/rustlib/src/rust/library"} + rustc_src_core="$rustc_src/core/src/lib.rs" + if [ ! -e "$rustc_src_core" ]; then +- if [ "$1" = -v ]; then +- echo >&2 "***" +- echo >&2 "*** Source code for the 'core' standard library could not be found" +- echo >&2 "*** at '$rustc_src_core'." +- echo >&2 "***" +- fi ++ echo >&2 "***" ++ echo >&2 "*** Source code for the 'core' standard library could not be found" ++ echo >&2 "*** at '$rustc_src_core'." ++ echo >&2 "***" + exit 1 + fi +diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig +index 60a511c6b583e..c17660bf5f347 100644 +--- a/security/integrity/ima/Kconfig ++++ b/security/integrity/ima/Kconfig +@@ -248,18 +248,6 @@ config IMA_APPRAISE_MODSIG + The modsig keyword can be used in the IMA policy to allow a hook + to accept such signatures. + +-config IMA_TRUSTED_KEYRING +- bool "Require all keys on the .ima keyring be signed (deprecated)" +- depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING +- depends on INTEGRITY_ASYMMETRIC_KEYS +- select INTEGRITY_TRUSTED_KEYRING +- default y +- help +- This option requires that all keys added to the .ima +- keyring be signed by a key on the system trusted keyring. +- +- This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING +- + config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY + bool "Permit keys validly signed by a built-in or secondary CA cert (EXPERIMENTAL)" + depends on SYSTEM_TRUSTED_KEYRING +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index d54f73c558f72..19be69fa4d052 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -980,14 +980,19 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) + ret = -EACCES; + down_write(&key->sem); + +- if (!capable(CAP_SYS_ADMIN)) { ++ { ++ bool is_privileged_op = false; ++ + /* only the sysadmin can chown a key to some other UID */ + if (user != (uid_t) -1 && !uid_eq(key->uid, uid)) +- goto error_put; ++ is_privileged_op = true; + + /* only the sysadmin can set the key's GID to a group other + * than one of those that the current process subscribes to */ + if (group != (gid_t) -1 && !gid_eq(gid, key->gid) && !in_group_p(gid)) ++ is_privileged_op = true; ++ ++ if (is_privileged_op && !capable(CAP_SYS_ADMIN)) + goto error_put; + } + +@@ -1088,7 +1093,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) + down_write(&key->sem); + + /* if we're not the sysadmin, we can only change a key that we own */ +- if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { ++ if (uid_eq(key->uid, current_fsuid()) || capable(CAP_SYS_ADMIN)) { + key->perm = perm; + notify_key(key, NOTIFY_KEY_SETATTR, 0); + ret = 0; +diff --git a/security/security.c b/security/security.c +index d5ff7ff45b776..521f74e77dd15 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -1138,6 +1138,20 @@ void security_bprm_committed_creds(struct linux_binprm *bprm) + call_void_hook(bprm_committed_creds, bprm); + } + ++/** ++ * security_fs_context_submount() - Initialise fc->security ++ * @fc: new filesystem context ++ * @reference: dentry reference for submount/remount ++ * ++ * Fill out the ->security field for a new fs_context. ++ * ++ * Return: Returns 0 on success or negative error code on failure. ++ */ ++int security_fs_context_submount(struct fs_context *fc, struct super_block *reference) ++{ ++ return call_int_hook(fs_context_submount, 0, fc, reference); ++} ++ + /** + * security_fs_context_dup() - Duplicate a fs_context LSM blob + * @fc: destination filesystem context +diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c +index 79b4890e9936d..674f43372f490 100644 +--- a/security/selinux/hooks.c ++++ b/security/selinux/hooks.c +@@ -2721,6 +2721,27 @@ static int selinux_umount(struct vfsmount *mnt, int flags) + FILESYSTEM__UNMOUNT, NULL); + } + ++static int selinux_fs_context_submount(struct fs_context *fc, ++ struct super_block *reference) ++{ ++ const struct superblock_security_struct *sbsec; ++ struct selinux_mnt_opts *opts; ++ ++ opts = kzalloc(sizeof(*opts), GFP_KERNEL); ++ if (!opts) ++ return -ENOMEM; ++ ++ sbsec = selinux_superblock(reference); ++ if (sbsec->flags & FSCONTEXT_MNT) ++ opts->fscontext_sid = sbsec->sid; ++ if (sbsec->flags & CONTEXT_MNT) ++ opts->context_sid = sbsec->mntpoint_sid; ++ if (sbsec->flags & DEFCONTEXT_MNT) ++ opts->defcontext_sid = sbsec->def_sid; ++ fc->security = opts; ++ return 0; ++} ++ + static int selinux_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc) + { +@@ -7142,6 +7163,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { + /* + * PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE + */ ++ LSM_HOOK_INIT(fs_context_submount, selinux_fs_context_submount), + LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup), + LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param), + LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts), +diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c +index 7a3e9ab137d85..6bdc01600aa74 100644 +--- a/security/smack/smack_lsm.c ++++ b/security/smack/smack_lsm.c +@@ -614,6 +614,56 @@ out_opt_err: + return -EINVAL; + } + ++/** ++ * smack_fs_context_submount - Initialise security data for a filesystem context ++ * @fc: The filesystem context. ++ * @reference: reference superblock ++ * ++ * Returns 0 on success or -ENOMEM on error. ++ */ ++static int smack_fs_context_submount(struct fs_context *fc, ++ struct super_block *reference) ++{ ++ struct superblock_smack *sbsp; ++ struct smack_mnt_opts *ctx; ++ struct inode_smack *isp; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ fc->security = ctx; ++ ++ sbsp = smack_superblock(reference); ++ isp = smack_inode(reference->s_root->d_inode); ++ ++ if (sbsp->smk_default) { ++ ctx->fsdefault = kstrdup(sbsp->smk_default->smk_known, GFP_KERNEL); ++ if (!ctx->fsdefault) ++ return -ENOMEM; ++ } ++ ++ if (sbsp->smk_floor) { ++ ctx->fsfloor = kstrdup(sbsp->smk_floor->smk_known, GFP_KERNEL); ++ if (!ctx->fsfloor) ++ return -ENOMEM; ++ } ++ ++ if (sbsp->smk_hat) { ++ ctx->fshat = kstrdup(sbsp->smk_hat->smk_known, GFP_KERNEL); ++ if (!ctx->fshat) ++ return -ENOMEM; ++ } ++ ++ if (isp->smk_flags & SMK_INODE_TRANSMUTE) { ++ if (sbsp->smk_root) { ++ ctx->fstransmute = kstrdup(sbsp->smk_root->smk_known, GFP_KERNEL); ++ if (!ctx->fstransmute) ++ return -ENOMEM; ++ } ++ } ++ return 0; ++} ++ + /** + * smack_fs_context_dup - Duplicate the security data on fs_context duplication + * @fc: The new filesystem context. +@@ -4845,6 +4895,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = { + LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), + LSM_HOOK_INIT(syslog, smack_syslog), + ++ LSM_HOOK_INIT(fs_context_submount, smack_fs_context_submount), + LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup), + LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param), + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 5590eaad241bb..25f67d1b5c73e 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -896,7 +896,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, + } + + ret = sscanf(rule, "%d", &catlen); +- if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) ++ if (ret != 1 || catlen < 0 || catlen > SMACK_CIPSO_MAXCATNUM) + goto out; + + if (format == SMK_FIXED24_FMT && +diff --git a/sound/Kconfig b/sound/Kconfig +index 0ddfb717b81dc..466e848689bd1 100644 +--- a/sound/Kconfig ++++ b/sound/Kconfig +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + menuconfig SOUND + tristate "Sound card support" +- depends on HAS_IOMEM ++ depends on HAS_IOMEM || UML + help + If you have a sound card in your computer, i.e. if it can say more + than an occasional beep, say Y. +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index 42c2ada8e8887..c96483091f30a 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -253,10 +253,14 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + goto error; + } + +- if (refine) ++ if (refine) { + err = snd_pcm_hw_refine(substream, data); +- else ++ if (err < 0) ++ goto error; ++ err = fixup_unreferenced_params(substream, data); ++ } else { + err = snd_pcm_hw_params(substream, data); ++ } + if (err < 0) + goto error; + if (copy_to_user(data32, data, sizeof(*data32)) || +diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c +index 80a65b8ad7b9b..25f93e56cfc7a 100644 +--- a/sound/pci/ac97/ac97_codec.c ++++ b/sound/pci/ac97/ac97_codec.c +@@ -2069,10 +2069,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, + .dev_disconnect = snd_ac97_dev_disconnect, + }; + +- if (!rac97) +- return -EINVAL; +- if (snd_BUG_ON(!bus || !template)) ++ if (snd_BUG_ON(!bus || !template || !rac97)) + return -EINVAL; ++ *rac97 = NULL; + if (snd_BUG_ON(template->num >= 4)) + return -EINVAL; + if (bus->codec[template->num]) +diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c +index b288874e401e5..36b411d1a9609 100644 +--- a/sound/pci/hda/patch_cs8409-tables.c ++++ b/sound/pci/hda/patch_cs8409-tables.c +@@ -550,6 +550,10 @@ const struct snd_pci_quirk cs8409_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN), + SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN), + SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN), ++ SND_PCI_QUIRK(0x1028, 0x0C73, "Dolphin", CS8409_DOLPHIN), ++ SND_PCI_QUIRK(0x1028, 0x0C75, "Dolphin", CS8409_DOLPHIN), ++ SND_PCI_QUIRK(0x1028, 0x0C7D, "Dolphin", CS8409_DOLPHIN), ++ SND_PCI_QUIRK(0x1028, 0x0C7F, "Dolphin", CS8409_DOLPHIN), + {} /* terminator */ + }; + +diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c +index 0ba1fbcbb21e4..627899959ffe8 100644 +--- a/sound/pci/hda/patch_cs8409.c ++++ b/sound/pci/hda/patch_cs8409.c +@@ -888,7 +888,7 @@ static void cs42l42_resume(struct sub_codec *cs42l42) + + /* Initialize CS42L42 companion codec */ + cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num); +- usleep_range(30000, 35000); ++ msleep(CS42L42_INIT_TIMEOUT_MS); + + /* Clear interrupts, by reading interrupt status registers */ + cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs)); +diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h +index 2a8dfb4ff046b..937e9387abdc7 100644 +--- a/sound/pci/hda/patch_cs8409.h ++++ b/sound/pci/hda/patch_cs8409.h +@@ -229,6 +229,7 @@ enum cs8409_coefficient_index_registers { + #define CS42L42_I2C_SLEEP_US (2000) + #define CS42L42_PDN_TIMEOUT_US (250000) + #define CS42L42_PDN_SLEEP_US (2000) ++#define CS42L42_INIT_TIMEOUT_MS (45) + #define CS42L42_FULL_SCALE_VOL_MASK (2) + #define CS42L42_FULL_SCALE_VOL_0DB (1) + #define CS42L42_FULL_SCALE_VOL_MINUS6DB (0) +diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c +index 49930baf5e4d6..69a88dc651652 100644 +--- a/sound/soc/atmel/atmel-i2s.c ++++ b/sound/soc/atmel/atmel-i2s.c +@@ -163,11 +163,14 @@ struct atmel_i2s_gck_param { + + #define I2S_MCK_12M288 12288000UL + #define I2S_MCK_11M2896 11289600UL ++#define I2S_MCK_6M144 6144000UL + + /* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */ + static const struct atmel_i2s_gck_param gck_params[] = { ++ /* mck = 6.144Mhz */ ++ { 8000, I2S_MCK_6M144, 1, 47}, /* mck = 768 fs */ ++ + /* mck = 12.288MHz */ +- { 8000, I2S_MCK_12M288, 0, 47}, /* mck = 1536 fs */ + { 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */ + { 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */ + { 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */ +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index 1b50b2d66beb2..3840dd6844974 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -1673,6 +1673,7 @@ config SND_SOC_STA529 + config SND_SOC_STAC9766 + tristate + depends on SND_SOC_AC97_BUS ++ select REGMAP_AC97 + + config SND_SOC_STI_SAS + tristate "codec Audio support for STI SAS codec" +diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c +index 295caad262243..c613a2554fa31 100644 +--- a/sound/soc/codecs/cs35l56-i2c.c ++++ b/sound/soc/codecs/cs35l56-i2c.c +@@ -62,10 +62,19 @@ static const struct i2c_device_id cs35l56_id_i2c[] = { + }; + MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c); + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { ++ { "CSC355C", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); ++#endif ++ + static struct i2c_driver cs35l56_i2c_driver = { + .driver = { + .name = "cs35l56", + .pm = &cs35l56_pm_ops_i2c_spi, ++ .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), + }, + .id_table = cs35l56_id_i2c, + .probe_new = cs35l56_i2c_probe, +diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c +index 996aab10500ee..302f9c47407a4 100644 +--- a/sound/soc/codecs/cs35l56-spi.c ++++ b/sound/soc/codecs/cs35l56-spi.c +@@ -59,10 +59,19 @@ static const struct spi_device_id cs35l56_id_spi[] = { + }; + MODULE_DEVICE_TABLE(spi, cs35l56_id_spi); + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { ++ { "CSC355C", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); ++#endif ++ + static struct spi_driver cs35l56_spi_driver = { + .driver = { + .name = "cs35l56", + .pm = &cs35l56_pm_ops_i2c_spi, ++ .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), + }, + .id_table = cs35l56_id_spi, + .probe = cs35l56_spi_probe, +diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h +index 1dd8936743132..90e8895275e77 100644 +--- a/sound/soc/codecs/cs43130.h ++++ b/sound/soc/codecs/cs43130.h +@@ -381,88 +381,88 @@ struct cs43130_clk_gen { + + /* frm_size = 16 */ + static const struct cs43130_clk_gen cs43130_16_clk_gen[] = { +- { 22579200, 32000, .v = { 441, 10, }, }, +- { 22579200, 44100, .v = { 32, 1, }, }, +- { 22579200, 48000, .v = { 147, 5, }, }, +- { 22579200, 88200, .v = { 16, 1, }, }, +- { 22579200, 96000, .v = { 147, 10, }, }, +- { 22579200, 176400, .v = { 8, 1, }, }, +- { 22579200, 192000, .v = { 147, 20, }, }, +- { 22579200, 352800, .v = { 4, 1, }, }, +- { 22579200, 384000, .v = { 147, 40, }, }, +- { 24576000, 32000, .v = { 48, 1, }, }, +- { 24576000, 44100, .v = { 5120, 147, }, }, +- { 24576000, 48000, .v = { 32, 1, }, }, +- { 24576000, 88200, .v = { 2560, 147, }, }, +- { 24576000, 96000, .v = { 16, 1, }, }, +- { 24576000, 176400, .v = { 1280, 147, }, }, +- { 24576000, 192000, .v = { 8, 1, }, }, +- { 24576000, 352800, .v = { 640, 147, }, }, +- { 24576000, 384000, .v = { 4, 1, }, }, ++ { 22579200, 32000, .v = { 10, 441, }, }, ++ { 22579200, 44100, .v = { 1, 32, }, }, ++ { 22579200, 48000, .v = { 5, 147, }, }, ++ { 22579200, 88200, .v = { 1, 16, }, }, ++ { 22579200, 96000, .v = { 10, 147, }, }, ++ { 22579200, 176400, .v = { 1, 8, }, }, ++ { 22579200, 192000, .v = { 20, 147, }, }, ++ { 22579200, 352800, .v = { 1, 4, }, }, ++ { 22579200, 384000, .v = { 40, 147, }, }, ++ { 24576000, 32000, .v = { 1, 48, }, }, ++ { 24576000, 44100, .v = { 147, 5120, }, }, ++ { 24576000, 48000, .v = { 1, 32, }, }, ++ { 24576000, 88200, .v = { 147, 2560, }, }, ++ { 24576000, 96000, .v = { 1, 16, }, }, ++ { 24576000, 176400, .v = { 147, 1280, }, }, ++ { 24576000, 192000, .v = { 1, 8, }, }, ++ { 24576000, 352800, .v = { 147, 640, }, }, ++ { 24576000, 384000, .v = { 1, 4, }, }, + }; + + /* frm_size = 32 */ + static const struct cs43130_clk_gen cs43130_32_clk_gen[] = { +- { 22579200, 32000, .v = { 441, 20, }, }, +- { 22579200, 44100, .v = { 16, 1, }, }, +- { 22579200, 48000, .v = { 147, 10, }, }, +- { 22579200, 88200, .v = { 8, 1, }, }, +- { 22579200, 96000, .v = { 147, 20, }, }, +- { 22579200, 176400, .v = { 4, 1, }, }, +- { 22579200, 192000, .v = { 147, 40, }, }, +- { 22579200, 352800, .v = { 2, 1, }, }, +- { 22579200, 384000, .v = { 147, 80, }, }, +- { 24576000, 32000, .v = { 24, 1, }, }, +- { 24576000, 44100, .v = { 2560, 147, }, }, +- { 24576000, 48000, .v = { 16, 1, }, }, +- { 24576000, 88200, .v = { 1280, 147, }, }, +- { 24576000, 96000, .v = { 8, 1, }, }, +- { 24576000, 176400, .v = { 640, 147, }, }, +- { 24576000, 192000, .v = { 4, 1, }, }, +- { 24576000, 352800, .v = { 320, 147, }, }, +- { 24576000, 384000, .v = { 2, 1, }, }, ++ { 22579200, 32000, .v = { 20, 441, }, }, ++ { 22579200, 44100, .v = { 1, 16, }, }, ++ { 22579200, 48000, .v = { 10, 147, }, }, ++ { 22579200, 88200, .v = { 1, 8, }, }, ++ { 22579200, 96000, .v = { 20, 147, }, }, ++ { 22579200, 176400, .v = { 1, 4, }, }, ++ { 22579200, 192000, .v = { 40, 147, }, }, ++ { 22579200, 352800, .v = { 1, 2, }, }, ++ { 22579200, 384000, .v = { 80, 147, }, }, ++ { 24576000, 32000, .v = { 1, 24, }, }, ++ { 24576000, 44100, .v = { 147, 2560, }, }, ++ { 24576000, 48000, .v = { 1, 16, }, }, ++ { 24576000, 88200, .v = { 147, 1280, }, }, ++ { 24576000, 96000, .v = { 1, 8, }, }, ++ { 24576000, 176400, .v = { 147, 640, }, }, ++ { 24576000, 192000, .v = { 1, 4, }, }, ++ { 24576000, 352800, .v = { 147, 320, }, }, ++ { 24576000, 384000, .v = { 1, 2, }, }, + }; + + /* frm_size = 48 */ + static const struct cs43130_clk_gen cs43130_48_clk_gen[] = { +- { 22579200, 32000, .v = { 147, 100, }, }, +- { 22579200, 44100, .v = { 32, 3, }, }, +- { 22579200, 48000, .v = { 49, 5, }, }, +- { 22579200, 88200, .v = { 16, 3, }, }, +- { 22579200, 96000, .v = { 49, 10, }, }, +- { 22579200, 176400, .v = { 8, 3, }, }, +- { 22579200, 192000, .v = { 49, 20, }, }, +- { 22579200, 352800, .v = { 4, 3, }, }, +- { 22579200, 384000, .v = { 49, 40, }, }, +- { 24576000, 32000, .v = { 16, 1, }, }, +- { 24576000, 44100, .v = { 5120, 441, }, }, +- { 24576000, 48000, .v = { 32, 3, }, }, +- { 24576000, 88200, .v = { 2560, 441, }, }, +- { 24576000, 96000, .v = { 16, 3, }, }, +- { 24576000, 176400, .v = { 1280, 441, }, }, +- { 24576000, 192000, .v = { 8, 3, }, }, +- { 24576000, 352800, .v = { 640, 441, }, }, +- { 24576000, 384000, .v = { 4, 3, }, }, ++ { 22579200, 32000, .v = { 100, 147, }, }, ++ { 22579200, 44100, .v = { 3, 32, }, }, ++ { 22579200, 48000, .v = { 5, 49, }, }, ++ { 22579200, 88200, .v = { 3, 16, }, }, ++ { 22579200, 96000, .v = { 10, 49, }, }, ++ { 22579200, 176400, .v = { 3, 8, }, }, ++ { 22579200, 192000, .v = { 20, 49, }, }, ++ { 22579200, 352800, .v = { 3, 4, }, }, ++ { 22579200, 384000, .v = { 40, 49, }, }, ++ { 24576000, 32000, .v = { 1, 16, }, }, ++ { 24576000, 44100, .v = { 441, 5120, }, }, ++ { 24576000, 48000, .v = { 3, 32, }, }, ++ { 24576000, 88200, .v = { 441, 2560, }, }, ++ { 24576000, 96000, .v = { 3, 16, }, }, ++ { 24576000, 176400, .v = { 441, 1280, }, }, ++ { 24576000, 192000, .v = { 3, 8, }, }, ++ { 24576000, 352800, .v = { 441, 640, }, }, ++ { 24576000, 384000, .v = { 3, 4, }, }, + }; + + /* frm_size = 64 */ + static const struct cs43130_clk_gen cs43130_64_clk_gen[] = { +- { 22579200, 32000, .v = { 441, 40, }, }, +- { 22579200, 44100, .v = { 8, 1, }, }, +- { 22579200, 48000, .v = { 147, 20, }, }, +- { 22579200, 88200, .v = { 4, 1, }, }, +- { 22579200, 96000, .v = { 147, 40, }, }, +- { 22579200, 176400, .v = { 2, 1, }, }, +- { 22579200, 192000, .v = { 147, 80, }, }, ++ { 22579200, 32000, .v = { 40, 441, }, }, ++ { 22579200, 44100, .v = { 1, 8, }, }, ++ { 22579200, 48000, .v = { 20, 147, }, }, ++ { 22579200, 88200, .v = { 1, 4, }, }, ++ { 22579200, 96000, .v = { 40, 147, }, }, ++ { 22579200, 176400, .v = { 1, 2, }, }, ++ { 22579200, 192000, .v = { 80, 147, }, }, + { 22579200, 352800, .v = { 1, 1, }, }, +- { 24576000, 32000, .v = { 12, 1, }, }, +- { 24576000, 44100, .v = { 1280, 147, }, }, +- { 24576000, 48000, .v = { 8, 1, }, }, +- { 24576000, 88200, .v = { 640, 147, }, }, +- { 24576000, 96000, .v = { 4, 1, }, }, +- { 24576000, 176400, .v = { 320, 147, }, }, +- { 24576000, 192000, .v = { 2, 1, }, }, +- { 24576000, 352800, .v = { 160, 147, }, }, ++ { 24576000, 32000, .v = { 1, 12, }, }, ++ { 24576000, 44100, .v = { 147, 1280, }, }, ++ { 24576000, 48000, .v = { 1, 8, }, }, ++ { 24576000, 88200, .v = { 147, 640, }, }, ++ { 24576000, 96000, .v = { 1, 4, }, }, ++ { 24576000, 176400, .v = { 147, 320, }, }, ++ { 24576000, 192000, .v = { 1, 2, }, }, ++ { 24576000, 352800, .v = { 147, 160, }, }, + { 24576000, 384000, .v = { 1, 1, }, }, + }; + +diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c +index 993a0d00bc48d..70c175744772c 100644 +--- a/sound/soc/codecs/da7219-aad.c ++++ b/sound/soc/codecs/da7219-aad.c +@@ -361,11 +361,15 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + u8 events[DA7219_AAD_IRQ_REG_MAX]; + u8 statusa; +- int i, report = 0, mask = 0; ++ int i, ret, report = 0, mask = 0; + + /* Read current IRQ events */ +- regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, +- events, DA7219_AAD_IRQ_REG_MAX); ++ ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, ++ events, DA7219_AAD_IRQ_REG_MAX); ++ if (ret) { ++ dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret); ++ return IRQ_NONE; ++ } + + if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B]) + return IRQ_NONE; +@@ -910,6 +914,8 @@ void da7219_aad_suspend(struct snd_soc_component *component) + } + } + } ++ ++ synchronize_irq(da7219_aad->irq); + } + + void da7219_aad_resume(struct snd_soc_component *component) +diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c +index ccecfdf700649..9f5522dee501d 100644 +--- a/sound/soc/codecs/es8316.c ++++ b/sound/soc/codecs/es8316.c +@@ -153,7 +153,7 @@ static const char * const es8316_dmic_txt[] = { + "dmic data at high level", + "dmic data at low level", + }; +-static const unsigned int es8316_dmic_values[] = { 0, 1, 2 }; ++static const unsigned int es8316_dmic_values[] = { 0, 2, 3 }; + static const struct soc_enum es8316_dmic_src_enum = + SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3, + ARRAY_SIZE(es8316_dmic_txt), +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index fee970427a243..42de7588fdb68 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -10,6 +10,7 @@ + #include <linux/acpi.h> + #include <linux/clk.h> + #include <linux/delay.h> ++#include <linux/dmi.h> + #include <linux/init.h> + #include <linux/i2c.h> + #include <linux/module.h> +@@ -25,6 +26,13 @@ + #include <sound/tlv.h> + #include "nau8821.h" + ++#define NAU8821_JD_ACTIVE_HIGH BIT(0) ++ ++static int nau8821_quirk; ++static int quirk_override = -1; ++module_param_named(quirk, quirk_override, uint, 0444); ++MODULE_PARM_DESC(quirk, "Board-specific quirk override"); ++ + #define NAU_FREF_MAX 13500000 + #define NAU_FVCO_MAX 100000000 + #define NAU_FVCO_MIN 90000000 +@@ -1792,6 +1800,33 @@ static int nau8821_setup_irq(struct nau8821 *nau8821) + return 0; + } + ++/* Please keep this list alphabetically sorted */ ++static const struct dmi_system_id nau8821_quirk_table[] = { ++ { ++ /* Positivo CW14Q01P-V2 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"), ++ DMI_MATCH(DMI_BOARD_NAME, "CW14Q01P-V2"), ++ }, ++ .driver_data = (void *)(NAU8821_JD_ACTIVE_HIGH), ++ }, ++ {} ++}; ++ ++static void nau8821_check_quirks(void) ++{ ++ const struct dmi_system_id *dmi_id; ++ ++ if (quirk_override != -1) { ++ nau8821_quirk = quirk_override; ++ return; ++ } ++ ++ dmi_id = dmi_first_match(nau8821_quirk_table); ++ if (dmi_id) ++ nau8821_quirk = (unsigned long)dmi_id->driver_data; ++} ++ + static int nau8821_i2c_probe(struct i2c_client *i2c) + { + struct device *dev = &i2c->dev; +@@ -1812,6 +1847,12 @@ static int nau8821_i2c_probe(struct i2c_client *i2c) + + nau8821->dev = dev; + nau8821->irq = i2c->irq; ++ ++ nau8821_check_quirks(); ++ ++ if (nau8821_quirk & NAU8821_JD_ACTIVE_HIGH) ++ nau8821->jkdet_polarity = 0; ++ + nau8821_print_device_properties(nau8821); + + nau8821_reset_chip(nau8821->regmap); +diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c +index 1797af824f60b..e2699c0b117be 100644 +--- a/sound/soc/codecs/rt1308-sdw.c ++++ b/sound/soc/codecs/rt1308-sdw.c +@@ -52,6 +52,7 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg) + case 0x300a: + case 0xc000: + case 0xc710: ++ case 0xcf01: + case 0xc860 ... 0xc863: + case 0xc870 ... 0xc873: + return true; +@@ -213,7 +214,7 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) + { + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); + int ret = 0; +- unsigned int tmp; ++ unsigned int tmp, hibernation_flag; + + if (rt1308->hw_init) + return 0; +@@ -242,6 +243,10 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) + + pm_runtime_get_noresume(&slave->dev); + ++ regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag); ++ if ((hibernation_flag != 0x00) && rt1308->first_hw_init) ++ goto _preset_ready_; ++ + /* sw reset */ + regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0); + +@@ -282,6 +287,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) + regmap_write(rt1308->regmap, 0xc100, 0xd7); + regmap_write(rt1308->regmap, 0xc101, 0xd7); + ++ /* apply BQ params */ ++ rt1308_apply_bq_params(rt1308); ++ ++ regmap_write(rt1308->regmap, 0xcf01, 0x01); ++ ++_preset_ready_: + if (rt1308->first_hw_init) { + regcache_cache_bypass(rt1308->regmap, false); + regcache_mark_dirty(rt1308->regmap); +diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c +index 23f17f70d7e9b..9622aaf1b3e63 100644 +--- a/sound/soc/codecs/rt5682-sdw.c ++++ b/sound/soc/codecs/rt5682-sdw.c +@@ -753,8 +753,15 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) + if (!rt5682->first_hw_init) + return 0; + +- if (!slave->unattach_request) ++ if (!slave->unattach_request) { ++ if (rt5682->disable_irq == true) { ++ mutex_lock(&rt5682->disable_irq_lock); ++ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); ++ rt5682->disable_irq = false; ++ mutex_unlock(&rt5682->disable_irq_lock); ++ } + goto regmap_sync; ++ } + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT5682_PROBE_TIMEOUT)); +diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c +index 51f3335343e08..76ed61e47316d 100644 +--- a/sound/soc/codecs/rt711-sdca-sdw.c ++++ b/sound/soc/codecs/rt711-sdca-sdw.c +@@ -441,8 +441,16 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) + if (!rt711->first_hw_init) + return 0; + +- if (!slave->unattach_request) ++ if (!slave->unattach_request) { ++ if (rt711->disable_irq == true) { ++ mutex_lock(&rt711->disable_irq_lock); ++ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); ++ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); ++ rt711->disable_irq = false; ++ mutex_unlock(&rt711->disable_irq_lock); ++ } + goto regmap_sync; ++ } + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT711_PROBE_TIMEOUT)); +diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c +index 4fe68bcf2a7c2..9545b8a7eb192 100644 +--- a/sound/soc/codecs/rt711-sdw.c ++++ b/sound/soc/codecs/rt711-sdw.c +@@ -541,8 +541,15 @@ static int __maybe_unused rt711_dev_resume(struct device *dev) + if (!rt711->first_hw_init) + return 0; + +- if (!slave->unattach_request) ++ if (!slave->unattach_request) { ++ if (rt711->disable_irq == true) { ++ mutex_lock(&rt711->disable_irq_lock); ++ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); ++ rt711->disable_irq = false; ++ mutex_unlock(&rt711->disable_irq_lock); ++ } + goto regmap_sync; ++ } + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT711_PROBE_TIMEOUT)); +diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c +index 3f319459dfec3..1c9e10fea3ddd 100644 +--- a/sound/soc/codecs/rt712-sdca-sdw.c ++++ b/sound/soc/codecs/rt712-sdca-sdw.c +@@ -441,8 +441,16 @@ static int __maybe_unused rt712_sdca_dev_resume(struct device *dev) + if (!rt712->first_hw_init) + return 0; + +- if (!slave->unattach_request) ++ if (!slave->unattach_request) { ++ if (rt712->disable_irq == true) { ++ mutex_lock(&rt712->disable_irq_lock); ++ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); ++ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); ++ rt712->disable_irq = false; ++ mutex_unlock(&rt712->disable_irq_lock); ++ } + goto regmap_sync; ++ } + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT712_PROBE_TIMEOUT)); +diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c +index 7cbb8e4758ccc..56d6b0b039a2e 100644 +--- a/sound/soc/fsl/fsl_qmc_audio.c ++++ b/sound/soc/fsl/fsl_qmc_audio.c +@@ -372,8 +372,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, + struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + unsigned int channels = params_channels(params); + unsigned int slot_width; ++ snd_pcm_format_t format; + struct snd_mask f_new; +- unsigned int i; + + if (!channels || channels > nb_ts) { + dev_err(qmc_dai->dev, "channels %u not supported\n", +@@ -384,10 +384,10 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, + slot_width = (nb_ts / channels) * 8; + + snd_mask_none(&f_new); +- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { +- if (snd_mask_test(f_old, i)) { +- if (snd_pcm_format_physical_width(i) <= slot_width) +- snd_mask_set(&f_new, i); ++ pcm_for_each_format(format) { ++ if (snd_mask_test_format(f_old, format)) { ++ if (snd_pcm_format_physical_width(format) <= slot_width) ++ snd_mask_set_format(&f_new, format); + } + } + +@@ -551,26 +551,26 @@ static const struct snd_soc_dai_ops qmc_dai_ops = { + + static u64 qmc_audio_formats(u8 nb_ts) + { +- u64 formats; +- unsigned int chan_width; + unsigned int format_width; +- int i; ++ unsigned int chan_width; ++ snd_pcm_format_t format; ++ u64 formats_mask; + + if (!nb_ts) + return 0; + +- formats = 0; ++ formats_mask = 0; + chan_width = nb_ts * 8; +- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { ++ pcm_for_each_format(format) { + /* + * Support format other than little-endian (ie big-endian or + * without endianness such as 8bit formats) + */ +- if (snd_pcm_format_little_endian(i) == 1) ++ if (snd_pcm_format_little_endian(format) == 1) + continue; + + /* Support physical width multiple of 8bit */ +- format_width = snd_pcm_format_physical_width(i); ++ format_width = snd_pcm_format_physical_width(format); + if (format_width == 0 || format_width % 8) + continue; + +@@ -581,9 +581,9 @@ static u64 qmc_audio_formats(u8 nb_ts) + if (format_width > chan_width || chan_width % format_width) + continue; + +- formats |= (1ULL << i); ++ formats_mask |= pcm_format_to_bits(format); + } +- return formats; ++ return formats_mask; + } + + static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np, +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index d8715db5e415e..2117fd61cf8f3 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -194,6 +194,7 @@ open_err: + snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); + out: + dpcm_path_put(&list); ++ snd_soc_dpcm_mutex_unlock(fe); + be_err: + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + snd_soc_card_mutex_unlock(fe->card); +diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c +index 2ae76bcd3590c..973bd81059852 100644 +--- a/sound/soc/sof/amd/acp.c ++++ b/sound/soc/sof/amd/acp.c +@@ -351,9 +351,9 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); +- if (val) { +- val |= ACP_DSP_TO_HOST_IRQ; +- snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val); ++ if (val & ACP_DSP_TO_HOST_IRQ) { ++ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, ++ ACP_DSP_TO_HOST_IRQ); + return IRQ_WAKE_THREAD; + } + +diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c +index b7cbf66badf5b..df87b3791c23e 100644 +--- a/sound/soc/sof/intel/hda-mlink.c ++++ b/sound/soc/sof/intel/hda-mlink.c +@@ -331,14 +331,14 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask) + return !!(val & cmdsync_mask); + } + +-static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num) ++static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num) + { +- u32 val; ++ u16 val; + +- val = readl(lsdiid); ++ val = readw(lsdiid); + val |= BIT(dev_num); + +- writel(val, lsdiid); ++ writew(val, lsdiid); + } + + static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan, +@@ -781,6 +781,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, + { + struct hdac_ext2_link *h2link; + u16 __iomem *pcmsycm; ++ int hchan; ++ int lchan; + u16 val; + + h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); +@@ -791,9 +793,17 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, + h2link->instance_offset * sublink + + AZX_REG_SDW_SHIM_PCMSyCM(y); + ++ if (channel_mask) { ++ hchan = __fls(channel_mask); ++ lchan = __ffs(channel_mask); ++ } else { ++ hchan = 0; ++ lchan = 0; ++ } ++ + mutex_lock(&h2link->eml_lock); + +- hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask), ++ hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan, + stream_id, dir); + + mutex_unlock(&h2link->eml_lock); +diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c +index f4bd1e8ae4b6c..23260aa1919d3 100644 +--- a/sound/usb/mixer_maps.c ++++ b/sound/usb/mixer_maps.c +@@ -374,6 +374,15 @@ static const struct usbmix_name_map corsair_virtuoso_map[] = { + { 0 } + }; + ++/* Microsoft USB Link headset */ ++/* a guess work: raw playback volume values are from 2 to 129 */ ++static const struct usbmix_dB_map ms_usb_link_dB = { -3225, 0, true }; ++static const struct usbmix_name_map ms_usb_link_map[] = { ++ { 9, NULL, .dB = &ms_usb_link_dB }, ++ { 10, NULL }, /* Headset Capture volume; seems non-working, disabled */ ++ { 0 } /* terminator */ ++}; ++ + /* ASUS ROG Zenith II with Realtek ALC1220-VB */ + static const struct usbmix_name_map asus_zenith_ii_map[] = { + { 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */ +@@ -668,6 +677,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { + .id = USB_ID(0x1395, 0x0025), + .map = sennheiser_pc8_map, + }, ++ { ++ /* Microsoft USB Link headset */ ++ .id = USB_ID(0x045e, 0x083c), ++ .map = ms_usb_link_map, ++ }, + { 0 } /* terminator */ + }; + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 6cf55b7f7a041..4667d543f7481 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -1874,8 +1874,10 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + + /* XMOS based USB DACs */ + switch (chip->usb_id) { +- case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */ +- case USB_ID(0x21ed, 0xd75a): /* Accuphase DAC-60 option card */ ++ case USB_ID(0x139f, 0x5504): /* Nagra DAC */ ++ case USB_ID(0x20b1, 0x3089): /* Mola-Mola DAC */ ++ case USB_ID(0x2522, 0x0007): /* LH Labs Geek Out 1V5 */ ++ case USB_ID(0x2522, 0x0009): /* LH Labs Geek Pulse X Inifinity 2V0 */ + case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */ + case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */ + if (fp->altsetting == 2) +@@ -1885,14 +1887,18 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */ + case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */ + case USB_ID(0x16d0, 0x06b2): /* NuPrime DAC-10 */ +- case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */ ++ case USB_ID(0x16d0, 0x06b4): /* NuPrime Audio HD-AVP/AVA */ + case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */ ++ case USB_ID(0x16d0, 0x09d8): /* NuPrime IDA-8 */ + case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */ ++ case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */ + case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */ ++ case USB_ID(0x20a0, 0x4143): /* WaveIO USB Audio 2.0 */ + case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */ + case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */ + case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ + case USB_ID(0x2622, 0x0041): /* Audiolab M-DAC+ */ ++ case USB_ID(0x278b, 0x5100): /* Rotel RC-1590 */ + case USB_ID(0x27f7, 0x3002): /* W4S DAC-2v2SE */ + case USB_ID(0x29a2, 0x0086): /* Mutec MC3+ USB */ + case USB_ID(0x6b42, 0x0042): /* MSB Technology */ +@@ -1902,9 +1908,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + + /* Amanero Combo384 USB based DACs with native DSD support */ + case USB_ID(0x16d0, 0x071a): /* Amanero - Combo384 */ +- case USB_ID(0x2ab6, 0x0004): /* T+A DAC8DSD-V2.0, MP1000E-V2.0, MP2000R-V2.0, MP2500R-V2.0, MP3100HV-V2.0 */ +- case USB_ID(0x2ab6, 0x0005): /* T+A USB HD Audio 1 */ +- case USB_ID(0x2ab6, 0x0006): /* T+A USB HD Audio 2 */ + if (fp->altsetting == 2) { + switch (le16_to_cpu(chip->dev->descriptor.bcdDevice)) { + case 0x199: +@@ -2011,6 +2014,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_IGNORE_CTL_ERROR), + DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */ + QUIRK_FLAG_GET_SAMPLE_RATE), ++ DEVICE_FLG(0x045e, 0x083c, /* MS USB Link headset */ ++ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY | ++ QUIRK_FLAG_DISABLE_AUTOSUSPEND), + DEVICE_FLG(0x046d, 0x084c, /* Logitech ConferenceCam Connect */ + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x046d, 0x0991, /* Logitech QuickCam Pro */ +@@ -2046,6 +2052,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x0644, 0x805f, /* TEAC Model 12 */ + QUIRK_FLAG_FORCE_IFACE_RESET), ++ DEVICE_FLG(0x0644, 0x806b, /* TEAC UD-701 */ ++ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | ++ QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */ + QUIRK_FLAG_IGNORE_CTL_ERROR), + DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */ +@@ -2084,6 +2093,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), + DEVICE_FLG(0x154e, 0x3006, /* Marantz SA-14S1 */ + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), ++ DEVICE_FLG(0x154e, 0x300b, /* Marantz SA-KI RUBY / SA-12 */ ++ QUIRK_FLAG_DSD_RAW), + DEVICE_FLG(0x154e, 0x500e, /* Denon DN-X1600 */ + QUIRK_FLAG_IGNORE_CLOCK_SOURCE), + DEVICE_FLG(0x1686, 0x00dd, /* Zoom R16/24 */ +@@ -2128,6 +2139,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), + DEVICE_FLG(0x21b4, 0x0081, /* AudioQuest DragonFly */ + QUIRK_FLAG_GET_SAMPLE_RATE), ++ DEVICE_FLG(0x21b4, 0x0230, /* Ayre QB-9 Twenty */ ++ QUIRK_FLAG_DSD_RAW), ++ DEVICE_FLG(0x21b4, 0x0232, /* Ayre QX-5 Twenty */ ++ QUIRK_FLAG_DSD_RAW), + DEVICE_FLG(0x2522, 0x0007, /* LH Labs Geek Out HD Audio 1V5 */ + QUIRK_FLAG_SET_IFACE_FIRST), + DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */ +@@ -2170,12 +2185,18 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_VALIDATE_RATES), + VENDOR_FLG(0x1235, /* Focusrite Novation */ + QUIRK_FLAG_VALIDATE_RATES), ++ VENDOR_FLG(0x1511, /* AURALiC */ ++ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x152a, /* Thesycon devices */ + QUIRK_FLAG_DSD_RAW), ++ VENDOR_FLG(0x18d1, /* iBasso devices */ ++ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x1de7, /* Phoenix Audio */ + QUIRK_FLAG_GET_SAMPLE_RATE), + VENDOR_FLG(0x20b1, /* XMOS based devices */ + QUIRK_FLAG_DSD_RAW), ++ VENDOR_FLG(0x21ed, /* Accuphase Laboratory */ ++ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x22d9, /* Oppo */ + QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x23ba, /* Playback Design */ +@@ -2191,10 +2212,14 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x2ab6, /* T+A devices */ + QUIRK_FLAG_DSD_RAW), ++ VENDOR_FLG(0x2d87, /* Cayin device */ ++ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x3336, /* HEM devices */ + QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x3353, /* Khadas devices */ + QUIRK_FLAG_DSD_RAW), ++ VENDOR_FLG(0x35f4, /* MSB Technology */ ++ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x3842, /* EVGA */ + QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0xc502, /* HiBy devices */ +diff --git a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c +index eb05ea53afb12..26004f0c5a6ae 100644 +--- a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c ++++ b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c +@@ -15,6 +15,19 @@ enum bpf_obj_type { + BPF_OBJ_BTF, + }; + ++struct bpf_perf_link___local { ++ struct bpf_link link; ++ struct file *perf_file; ++} __attribute__((preserve_access_index)); ++ ++struct perf_event___local { ++ u64 bpf_cookie; ++} __attribute__((preserve_access_index)); ++ ++enum bpf_link_type___local { ++ BPF_LINK_TYPE_PERF_EVENT___local = 7, ++}; ++ + extern const void bpf_link_fops __ksym; + extern const void bpf_map_fops __ksym; + extern const void bpf_prog_fops __ksym; +@@ -41,10 +54,10 @@ static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type) + /* could be used only with BPF_LINK_TYPE_PERF_EVENT links */ + static __u64 get_bpf_cookie(struct bpf_link *link) + { +- struct bpf_perf_link *perf_link; +- struct perf_event *event; ++ struct bpf_perf_link___local *perf_link; ++ struct perf_event___local *event; + +- perf_link = container_of(link, struct bpf_perf_link, link); ++ perf_link = container_of(link, struct bpf_perf_link___local, link); + event = BPF_CORE_READ(perf_link, perf_file, private_data); + return BPF_CORE_READ(event, bpf_cookie); + } +@@ -84,10 +97,13 @@ int iter(struct bpf_iter__task_file *ctx) + e.pid = task->tgid; + e.id = get_obj_id(file->private_data, obj_type); + +- if (obj_type == BPF_OBJ_LINK) { ++ if (obj_type == BPF_OBJ_LINK && ++ bpf_core_enum_value_exists(enum bpf_link_type___local, ++ BPF_LINK_TYPE_PERF_EVENT___local)) { + struct bpf_link *link = (struct bpf_link *) file->private_data; + +- if (BPF_CORE_READ(link, type) == BPF_LINK_TYPE_PERF_EVENT) { ++ if (link->type == bpf_core_enum_value(enum bpf_link_type___local, ++ BPF_LINK_TYPE_PERF_EVENT___local)) { + e.has_bpf_cookie = true; + e.bpf_cookie = get_bpf_cookie(link); + } +diff --git a/tools/bpf/bpftool/skeleton/profiler.bpf.c b/tools/bpf/bpftool/skeleton/profiler.bpf.c +index ce5b65e07ab10..2f80edc682f11 100644 +--- a/tools/bpf/bpftool/skeleton/profiler.bpf.c ++++ b/tools/bpf/bpftool/skeleton/profiler.bpf.c +@@ -4,6 +4,12 @@ + #include <bpf/bpf_helpers.h> + #include <bpf/bpf_tracing.h> + ++struct bpf_perf_event_value___local { ++ __u64 counter; ++ __u64 enabled; ++ __u64 running; ++} __attribute__((preserve_access_index)); ++ + /* map of perf event fds, num_cpu * num_metric entries */ + struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); +@@ -15,14 +21,14 @@ struct { + struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(u32)); +- __uint(value_size, sizeof(struct bpf_perf_event_value)); ++ __uint(value_size, sizeof(struct bpf_perf_event_value___local)); + } fentry_readings SEC(".maps"); + + /* accumulated readings */ + struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(u32)); +- __uint(value_size, sizeof(struct bpf_perf_event_value)); ++ __uint(value_size, sizeof(struct bpf_perf_event_value___local)); + } accum_readings SEC(".maps"); + + /* sample counts, one per cpu */ +@@ -39,7 +45,7 @@ const volatile __u32 num_metric = 1; + SEC("fentry/XXX") + int BPF_PROG(fentry_XXX) + { +- struct bpf_perf_event_value *ptrs[MAX_NUM_MATRICS]; ++ struct bpf_perf_event_value___local *ptrs[MAX_NUM_MATRICS]; + u32 key = bpf_get_smp_processor_id(); + u32 i; + +@@ -53,10 +59,10 @@ int BPF_PROG(fentry_XXX) + } + + for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { +- struct bpf_perf_event_value reading; ++ struct bpf_perf_event_value___local reading; + int err; + +- err = bpf_perf_event_read_value(&events, key, &reading, ++ err = bpf_perf_event_read_value(&events, key, (void *)&reading, + sizeof(reading)); + if (err) + return 0; +@@ -68,14 +74,14 @@ int BPF_PROG(fentry_XXX) + } + + static inline void +-fexit_update_maps(u32 id, struct bpf_perf_event_value *after) ++fexit_update_maps(u32 id, struct bpf_perf_event_value___local *after) + { +- struct bpf_perf_event_value *before, diff; ++ struct bpf_perf_event_value___local *before, diff; + + before = bpf_map_lookup_elem(&fentry_readings, &id); + /* only account samples with a valid fentry_reading */ + if (before && before->counter) { +- struct bpf_perf_event_value *accum; ++ struct bpf_perf_event_value___local *accum; + + diff.counter = after->counter - before->counter; + diff.enabled = after->enabled - before->enabled; +@@ -93,7 +99,7 @@ fexit_update_maps(u32 id, struct bpf_perf_event_value *after) + SEC("fexit/XXX") + int BPF_PROG(fexit_XXX) + { +- struct bpf_perf_event_value readings[MAX_NUM_MATRICS]; ++ struct bpf_perf_event_value___local readings[MAX_NUM_MATRICS]; + u32 cpu = bpf_get_smp_processor_id(); + u32 i, zero = 0; + int err; +@@ -102,7 +108,8 @@ int BPF_PROG(fexit_XXX) + /* read all events before updating the maps, to reduce error */ + for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { + err = bpf_perf_event_read_value(&events, cpu + i * num_cpu, +- readings + i, sizeof(*readings)); ++ (void *)(readings + i), ++ sizeof(*readings)); + if (err) + return 0; + } +diff --git a/tools/hv/vmbus_testing b/tools/hv/vmbus_testing +index e7212903dd1d9..4467979d8f699 100755 +--- a/tools/hv/vmbus_testing ++++ b/tools/hv/vmbus_testing +@@ -164,7 +164,7 @@ def recursive_file_lookup(path, file_map): + def get_all_devices_test_status(file_map): + + for device in file_map: +- if (get_test_state(locate_state(device, file_map)) is 1): ++ if (get_test_state(locate_state(device, file_map)) == 1): + print("Testing = ON for: {}" + .format(device.split("/")[5])) + else: +@@ -203,7 +203,7 @@ def write_test_files(path, value): + def set_test_state(state_path, state_value, quiet): + + write_test_files(state_path, state_value) +- if (get_test_state(state_path) is 1): ++ if (get_test_state(state_path) == 1): + if (not quiet): + print("Testing = ON for device: {}" + .format(state_path.split("/")[5])) +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index a27f6e9ccce75..2a4dbe7d9b3d4 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -6136,7 +6136,11 @@ static int append_subprog_relos(struct bpf_program *main_prog, struct bpf_progra + if (main_prog == subprog) + return 0; + relos = libbpf_reallocarray(main_prog->reloc_desc, new_cnt, sizeof(*relos)); +- if (!relos) ++ /* if new count is zero, reallocarray can return a valid NULL result; ++ * in this case the previous pointer will be freed, so we *have to* ++ * reassign old pointer to the new value (even if it's NULL) ++ */ ++ if (!relos && new_cnt) + return -ENOMEM; + if (subprog->nr_reloc) + memcpy(relos + main_prog->nr_reloc, subprog->reloc_desc, +@@ -8504,7 +8508,8 @@ int bpf_program__set_insns(struct bpf_program *prog, + return -EBUSY; + + insns = libbpf_reallocarray(prog->insns, new_insn_cnt, sizeof(*insns)); +- if (!insns) { ++ /* NULL is a valid return from reallocarray if the new count is zero */ ++ if (!insns && new_insn_cnt) { + pr_warn("prog '%s': failed to realloc prog code\n", prog->name); + return -ENOMEM; + } +@@ -8534,13 +8539,31 @@ enum bpf_prog_type bpf_program__type(const struct bpf_program *prog) + return prog->type; + } + ++static size_t custom_sec_def_cnt; ++static struct bpf_sec_def *custom_sec_defs; ++static struct bpf_sec_def custom_fallback_def; ++static bool has_custom_fallback_def; ++static int last_custom_sec_def_handler_id; ++ + int bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type) + { + if (prog->obj->loaded) + return libbpf_err(-EBUSY); + ++ /* if type is not changed, do nothing */ ++ if (prog->type == type) ++ return 0; ++ + prog->type = type; +- prog->sec_def = NULL; ++ ++ /* If a program type was changed, we need to reset associated SEC() ++ * handler, as it will be invalid now. The only exception is a generic ++ * fallback handler, which by definition is program type-agnostic and ++ * is a catch-all custom handler, optionally set by the application, ++ * so should be able to handle any type of BPF program. ++ */ ++ if (prog->sec_def != &custom_fallback_def) ++ prog->sec_def = NULL; + return 0; + } + +@@ -8716,13 +8739,6 @@ static const struct bpf_sec_def section_defs[] = { + SEC_DEF("netfilter", NETFILTER, BPF_NETFILTER, SEC_NONE), + }; + +-static size_t custom_sec_def_cnt; +-static struct bpf_sec_def *custom_sec_defs; +-static struct bpf_sec_def custom_fallback_def; +-static bool has_custom_fallback_def; +- +-static int last_custom_sec_def_handler_id; +- + int libbpf_register_prog_handler(const char *sec, + enum bpf_prog_type prog_type, + enum bpf_attach_type exp_attach_type, +@@ -8802,7 +8818,11 @@ int libbpf_unregister_prog_handler(int handler_id) + + /* try to shrink the array, but it's ok if we couldn't */ + sec_defs = libbpf_reallocarray(custom_sec_defs, custom_sec_def_cnt, sizeof(*sec_defs)); +- if (sec_defs) ++ /* if new count is zero, reallocarray can return a valid NULL result; ++ * in this case the previous pointer will be freed, so we *have to* ++ * reassign old pointer to the new value (even if it's NULL) ++ */ ++ if (sec_defs || custom_sec_def_cnt == 0) + custom_sec_defs = sec_defs; + + return 0; +diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c +index 086eef355ab3d..1af77f9935833 100644 +--- a/tools/lib/bpf/usdt.c ++++ b/tools/lib/bpf/usdt.c +@@ -852,8 +852,11 @@ static int bpf_link_usdt_detach(struct bpf_link *link) + * system is so exhausted on memory, it's the least of user's + * concerns, probably. + * So just do our best here to return those IDs to usdt_manager. ++ * Another edge case when we can legitimately get NULL is when ++ * new_cnt is zero, which can happen in some edge cases, so we ++ * need to be careful about that. + */ +- if (new_free_ids) { ++ if (new_free_ids || new_cnt == 0) { + memcpy(new_free_ids + man->free_spec_cnt, usdt_link->spec_ids, + usdt_link->spec_cnt * sizeof(*usdt_link->spec_ids)); + man->free_spec_ids = new_free_ids; +diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c +index e00520cc63498..cffaf2245d4f1 100644 +--- a/tools/testing/radix-tree/multiorder.c ++++ b/tools/testing/radix-tree/multiorder.c +@@ -159,7 +159,7 @@ void multiorder_tagged_iteration(struct xarray *xa) + item_kill_tree(xa); + } + +-bool stop_iteration = false; ++bool stop_iteration; + + static void *creator_func(void *ptr) + { +@@ -201,6 +201,7 @@ static void multiorder_iteration_race(struct xarray *xa) + pthread_t worker_thread[num_threads]; + int i; + ++ stop_iteration = false; + pthread_create(&worker_thread[0], NULL, &creator_func, xa); + for (i = 1; i < num_threads; i++) + pthread_create(&worker_thread[i], NULL, &iterator_func, xa); +@@ -211,6 +212,61 @@ static void multiorder_iteration_race(struct xarray *xa) + item_kill_tree(xa); + } + ++static void *load_creator(void *ptr) ++{ ++ /* 'order' is set up to ensure we have sibling entries */ ++ unsigned int order; ++ struct radix_tree_root *tree = ptr; ++ int i; ++ ++ rcu_register_thread(); ++ item_insert_order(tree, 3 << RADIX_TREE_MAP_SHIFT, 0); ++ item_insert_order(tree, 2 << RADIX_TREE_MAP_SHIFT, 0); ++ for (i = 0; i < 10000; i++) { ++ for (order = 1; order < RADIX_TREE_MAP_SHIFT; order++) { ++ unsigned long index = (3 << RADIX_TREE_MAP_SHIFT) - ++ (1 << order); ++ item_insert_order(tree, index, order); ++ item_delete_rcu(tree, index); ++ } ++ } ++ rcu_unregister_thread(); ++ ++ stop_iteration = true; ++ return NULL; ++} ++ ++static void *load_worker(void *ptr) ++{ ++ unsigned long index = (3 << RADIX_TREE_MAP_SHIFT) - 1; ++ ++ rcu_register_thread(); ++ while (!stop_iteration) { ++ struct item *item = xa_load(ptr, index); ++ assert(!xa_is_internal(item)); ++ } ++ rcu_unregister_thread(); ++ ++ return NULL; ++} ++ ++static void load_race(struct xarray *xa) ++{ ++ const int num_threads = sysconf(_SC_NPROCESSORS_ONLN) * 4; ++ pthread_t worker_thread[num_threads]; ++ int i; ++ ++ stop_iteration = false; ++ pthread_create(&worker_thread[0], NULL, &load_creator, xa); ++ for (i = 1; i < num_threads; i++) ++ pthread_create(&worker_thread[i], NULL, &load_worker, xa); ++ ++ for (i = 0; i < num_threads; i++) ++ pthread_join(worker_thread[i], NULL); ++ ++ item_kill_tree(xa); ++} ++ + static DEFINE_XARRAY(array); + + void multiorder_checks(void) +@@ -218,12 +274,20 @@ void multiorder_checks(void) + multiorder_iteration(&array); + multiorder_tagged_iteration(&array); + multiorder_iteration_race(&array); ++ load_race(&array); + + radix_tree_cpu_dead(0); + } + +-int __weak main(void) ++int __weak main(int argc, char **argv) + { ++ int opt; ++ ++ while ((opt = getopt(argc, argv, "ls:v")) != -1) { ++ if (opt == 'v') ++ test_verbose++; ++ } ++ + rcu_register_thread(); + radix_tree_init(); + multiorder_checks(); +diff --git a/tools/testing/selftests/bpf/benchs/run_bench_rename.sh b/tools/testing/selftests/bpf/benchs/run_bench_rename.sh +index 16f774b1cdbed..7b281dbe41656 100755 +--- a/tools/testing/selftests/bpf/benchs/run_bench_rename.sh ++++ b/tools/testing/selftests/bpf/benchs/run_bench_rename.sh +@@ -2,7 +2,7 @@ + + set -eufo pipefail + +-for i in base kprobe kretprobe rawtp fentry fexit fmodret ++for i in base kprobe kretprobe rawtp fentry fexit + do + summary=$(sudo ./bench -w2 -d5 -a rename-$i | tail -n1 | cut -d'(' -f1 | cut -d' ' -f3-) + printf "%-10s: %s\n" $i "$summary" +diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c +index c8ba4009e4ab9..b30ff6b3b81ae 100644 +--- a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c ++++ b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c +@@ -123,12 +123,13 @@ static void test_bpf_nf_ct(int mode) + ASSERT_EQ(skel->data->test_snat_addr, 0, "Test for source natting"); + ASSERT_EQ(skel->data->test_dnat_addr, 0, "Test for destination natting"); + end: +- if (srv_client_fd != -1) +- close(srv_client_fd); + if (client_fd != -1) + close(client_fd); ++ if (srv_client_fd != -1) ++ close(srv_client_fd); + if (srv_fd != -1) + close(srv_fd); ++ + snprintf(cmd, sizeof(cmd), iptables, "-D"); + system(cmd); + test_bpf_nf__destroy(skel); +diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +index a543742cd7bd1..2eb71559713c9 100644 +--- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c ++++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +@@ -173,8 +173,8 @@ static void verify_fail(struct kfunc_test_params *param) + case tc_test: + topts.data_in = &pkt_v4; + topts.data_size_in = sizeof(pkt_v4); +- break; + topts.repeat = 1; ++ break; + } + + skel = kfunc_call_fail__open_opts(&opts); +diff --git a/tools/testing/selftests/bpf/progs/test_cls_redirect.h b/tools/testing/selftests/bpf/progs/test_cls_redirect.h +index 76eab0aacba0c..233b089d1fbac 100644 +--- a/tools/testing/selftests/bpf/progs/test_cls_redirect.h ++++ b/tools/testing/selftests/bpf/progs/test_cls_redirect.h +@@ -12,6 +12,15 @@ + #include <linux/ipv6.h> + #include <linux/udp.h> + ++/* offsetof() is used in static asserts, and the libbpf-redefined CO-RE ++ * friendly version breaks compilation for older clang versions <= 15 ++ * when invoked in a static assert. Restore original here. ++ */ ++#ifdef offsetof ++#undef offsetof ++#define offsetof(type, member) __builtin_offsetof(type, member) ++#endif ++ + struct gre_base_hdr { + uint16_t flags; + uint16_t protocol; +diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c +index 3651ce17beeb9..d183f878360bc 100644 +--- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c ++++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c +@@ -24,6 +24,7 @@ + + static long timeout_ns = 100000; /* 100us default timeout */ + static futex_t futex_pi; ++static pthread_barrier_t barrier; + + void usage(char *prog) + { +@@ -48,6 +49,8 @@ void *get_pi_lock(void *arg) + if (ret != 0) + error("futex_lock_pi failed\n", ret); + ++ pthread_barrier_wait(&barrier); ++ + /* Blocks forever */ + ret = futex_wait(&lock, 0, NULL, 0); + error("futex_wait failed\n", ret); +@@ -130,6 +133,7 @@ int main(int argc, char *argv[]) + basename(argv[0])); + ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns); + ++ pthread_barrier_init(&barrier, NULL, 2); + pthread_create(&thread, NULL, get_pi_lock, NULL); + + /* initialize relative timeout */ +@@ -163,6 +167,9 @@ int main(int argc, char *argv[]) + res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, 0); + test_timeout(res, &ret, "futex_wait_requeue_pi monotonic", ETIMEDOUT); + ++ /* Wait until the other thread calls futex_lock_pi() */ ++ pthread_barrier_wait(&barrier); ++ pthread_barrier_destroy(&barrier); + /* + * FUTEX_LOCK_PI with CLOCK_REALTIME + * Due to historical reasons, FUTEX_LOCK_PI supports only realtime +diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h +index 5fd49ad0c696f..e05ac82610467 100644 +--- a/tools/testing/selftests/kselftest_harness.h ++++ b/tools/testing/selftests/kselftest_harness.h +@@ -938,7 +938,11 @@ void __wait_for_test(struct __test_metadata *t) + fprintf(TH_LOG_STREAM, + "# %s: Test terminated by timeout\n", t->name); + } else if (WIFEXITED(status)) { +- if (t->termsig != -1) { ++ if (WEXITSTATUS(status) == 255) { ++ /* SKIP */ ++ t->passed = 1; ++ t->skip = 1; ++ } else if (t->termsig != -1) { + t->passed = 0; + fprintf(TH_LOG_STREAM, + "# %s: Test exited normally instead of by signal (code: %d)\n", +@@ -950,11 +954,6 @@ void __wait_for_test(struct __test_metadata *t) + case 0: + t->passed = 1; + break; +- /* SKIP */ +- case 255: +- t->passed = 1; +- t->skip = 1; +- break; + /* Other failure, assume step report. */ + default: + t->passed = 0; +diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c +index dba0e8ba002f8..8b7390ad81d11 100644 +--- a/tools/testing/selftests/memfd/memfd_test.c ++++ b/tools/testing/selftests/memfd/memfd_test.c +@@ -1145,8 +1145,25 @@ static void test_sysctl_child(void) + + printf("%s sysctl 2\n", memfd_str); + sysctl_assert_write("2"); +- mfd_fail_new("kern_memfd_sysctl_2", +- MFD_CLOEXEC | MFD_ALLOW_SEALING); ++ mfd_fail_new("kern_memfd_sysctl_2_exec", ++ MFD_EXEC | MFD_CLOEXEC | MFD_ALLOW_SEALING); ++ ++ fd = mfd_assert_new("kern_memfd_sysctl_2_dfl", ++ mfd_def_size, ++ MFD_CLOEXEC | MFD_ALLOW_SEALING); ++ mfd_assert_mode(fd, 0666); ++ mfd_assert_has_seals(fd, F_SEAL_EXEC); ++ mfd_fail_chmod(fd, 0777); ++ close(fd); ++ ++ fd = mfd_assert_new("kern_memfd_sysctl_2_noexec_seal", ++ mfd_def_size, ++ MFD_NOEXEC_SEAL | MFD_CLOEXEC | MFD_ALLOW_SEALING); ++ mfd_assert_mode(fd, 0666); ++ mfd_assert_has_seals(fd, F_SEAL_EXEC); ++ mfd_fail_chmod(fd, 0777); ++ close(fd); ++ + sysctl_fail_write("0"); + sysctl_fail_write("1"); + } +@@ -1202,7 +1219,24 @@ static pid_t spawn_newpid_thread(unsigned int flags, int (*fn)(void *)) + + static void join_newpid_thread(pid_t pid) + { +- waitpid(pid, NULL, 0); ++ int wstatus; ++ ++ if (waitpid(pid, &wstatus, 0) < 0) { ++ printf("newpid thread: waitpid() failed: %m\n"); ++ abort(); ++ } ++ ++ if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0) { ++ printf("newpid thread: exited with non-zero error code %d\n", ++ WEXITSTATUS(wstatus)); ++ abort(); ++ } ++ ++ if (WIFSIGNALED(wstatus)) { ++ printf("newpid thread: killed by signal %d\n", ++ WTERMSIG(wstatus)); ++ abort(); ++ } + } + + /* +diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile +index 73d53257df42f..5073dbc961258 100644 +--- a/tools/testing/selftests/resctrl/Makefile ++++ b/tools/testing/selftests/resctrl/Makefile +@@ -7,4 +7,4 @@ TEST_GEN_PROGS := resctrl_tests + + include ../lib.mk + +-$(OUTPUT)/resctrl_tests: $(wildcard *.c) ++$(OUTPUT)/resctrl_tests: $(wildcard *.[ch]) +diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c +index 8a4fe8693be63..289b619116fec 100644 +--- a/tools/testing/selftests/resctrl/cache.c ++++ b/tools/testing/selftests/resctrl/cache.c +@@ -87,21 +87,19 @@ static int reset_enable_llc_perf(pid_t pid, int cpu_no) + static int get_llc_perf(unsigned long *llc_perf_miss) + { + __u64 total_misses; ++ int ret; + + /* Stop counters after one span to get miss rate */ + + ioctl(fd_lm, PERF_EVENT_IOC_DISABLE, 0); + +- if (read(fd_lm, &rf_cqm, sizeof(struct read_format)) == -1) { ++ ret = read(fd_lm, &rf_cqm, sizeof(struct read_format)); ++ if (ret == -1) { + perror("Could not get llc misses through perf"); +- + return -1; + } + + total_misses = rf_cqm.values[0].value; +- +- close(fd_lm); +- + *llc_perf_miss = total_misses; + + return 0; +@@ -253,19 +251,25 @@ int cat_val(struct resctrl_val_param *param) + memflush, operation, resctrl_val)) { + fprintf(stderr, "Error-running fill buffer\n"); + ret = -1; +- break; ++ goto pe_close; + } + + sleep(1); + ret = measure_cache_vals(param, bm_pid); + if (ret) +- break; ++ goto pe_close; ++ ++ close(fd_lm); + } else { + break; + } + } + + return ret; ++ ++pe_close: ++ close(fd_lm); ++ return ret; + } + + /* +diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c +index 341cc93ca84c4..3b328c8448964 100644 +--- a/tools/testing/selftests/resctrl/fill_buf.c ++++ b/tools/testing/selftests/resctrl/fill_buf.c +@@ -177,12 +177,13 @@ fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush, + else + ret = fill_cache_write(start_ptr, end_ptr, resctrl_val); + ++ free(startptr); ++ + if (ret) { + printf("\n Error in fill cache read/write...\n"); + return -1; + } + +- free(startptr); + + return 0; + } +diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h +index 87e39456dee08..f455f0b7e314b 100644 +--- a/tools/testing/selftests/resctrl/resctrl.h ++++ b/tools/testing/selftests/resctrl/resctrl.h +@@ -43,6 +43,7 @@ + do { \ + perror(err_msg); \ + kill(ppid, SIGKILL); \ ++ umount_resctrlfs(); \ + exit(EXIT_FAILURE); \ + } while (0) + +diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c +index 9584eb57e0eda..365d30779768a 100644 +--- a/virt/kvm/vfio.c ++++ b/virt/kvm/vfio.c +@@ -21,7 +21,7 @@ + #include <asm/kvm_ppc.h> + #endif + +-struct kvm_vfio_group { ++struct kvm_vfio_file { + struct list_head node; + struct file *file; + #ifdef CONFIG_SPAPR_TCE_IOMMU +@@ -30,7 +30,7 @@ struct kvm_vfio_group { + }; + + struct kvm_vfio { +- struct list_head group_list; ++ struct list_head file_list; + struct mutex lock; + bool noncoherent; + }; +@@ -98,34 +98,35 @@ static struct iommu_group *kvm_vfio_file_iommu_group(struct file *file) + } + + static void kvm_spapr_tce_release_vfio_group(struct kvm *kvm, +- struct kvm_vfio_group *kvg) ++ struct kvm_vfio_file *kvf) + { +- if (WARN_ON_ONCE(!kvg->iommu_group)) ++ if (WARN_ON_ONCE(!kvf->iommu_group)) + return; + +- kvm_spapr_tce_release_iommu_group(kvm, kvg->iommu_group); +- iommu_group_put(kvg->iommu_group); +- kvg->iommu_group = NULL; ++ kvm_spapr_tce_release_iommu_group(kvm, kvf->iommu_group); ++ iommu_group_put(kvf->iommu_group); ++ kvf->iommu_group = NULL; + } + #endif + + /* +- * Groups can use the same or different IOMMU domains. If the same then +- * adding a new group may change the coherency of groups we've previously +- * been told about. We don't want to care about any of that so we retest +- * each group and bail as soon as we find one that's noncoherent. This +- * means we only ever [un]register_noncoherent_dma once for the whole device. ++ * Groups/devices can use the same or different IOMMU domains. If the same ++ * then adding a new group/device may change the coherency of groups/devices ++ * we've previously been told about. We don't want to care about any of ++ * that so we retest each group/device and bail as soon as we find one that's ++ * noncoherent. This means we only ever [un]register_noncoherent_dma once ++ * for the whole device. + */ + static void kvm_vfio_update_coherency(struct kvm_device *dev) + { + struct kvm_vfio *kv = dev->private; + bool noncoherent = false; +- struct kvm_vfio_group *kvg; ++ struct kvm_vfio_file *kvf; + + mutex_lock(&kv->lock); + +- list_for_each_entry(kvg, &kv->group_list, node) { +- if (!kvm_vfio_file_enforced_coherent(kvg->file)) { ++ list_for_each_entry(kvf, &kv->file_list, node) { ++ if (!kvm_vfio_file_enforced_coherent(kvf->file)) { + noncoherent = true; + break; + } +@@ -143,10 +144,10 @@ static void kvm_vfio_update_coherency(struct kvm_device *dev) + mutex_unlock(&kv->lock); + } + +-static int kvm_vfio_group_add(struct kvm_device *dev, unsigned int fd) ++static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd) + { + struct kvm_vfio *kv = dev->private; +- struct kvm_vfio_group *kvg; ++ struct kvm_vfio_file *kvf; + struct file *filp; + int ret; + +@@ -162,27 +163,27 @@ static int kvm_vfio_group_add(struct kvm_device *dev, unsigned int fd) + + mutex_lock(&kv->lock); + +- list_for_each_entry(kvg, &kv->group_list, node) { +- if (kvg->file == filp) { ++ list_for_each_entry(kvf, &kv->file_list, node) { ++ if (kvf->file == filp) { + ret = -EEXIST; + goto err_unlock; + } + } + +- kvg = kzalloc(sizeof(*kvg), GFP_KERNEL_ACCOUNT); +- if (!kvg) { ++ kvf = kzalloc(sizeof(*kvf), GFP_KERNEL_ACCOUNT); ++ if (!kvf) { + ret = -ENOMEM; + goto err_unlock; + } + +- kvg->file = filp; +- list_add_tail(&kvg->node, &kv->group_list); ++ kvf->file = filp; ++ list_add_tail(&kvf->node, &kv->file_list); + + kvm_arch_start_assignment(dev->kvm); ++ kvm_vfio_file_set_kvm(kvf->file, dev->kvm); + + mutex_unlock(&kv->lock); + +- kvm_vfio_file_set_kvm(kvg->file, dev->kvm); + kvm_vfio_update_coherency(dev); + + return 0; +@@ -193,10 +194,10 @@ err_fput: + return ret; + } + +-static int kvm_vfio_group_del(struct kvm_device *dev, unsigned int fd) ++static int kvm_vfio_file_del(struct kvm_device *dev, unsigned int fd) + { + struct kvm_vfio *kv = dev->private; +- struct kvm_vfio_group *kvg; ++ struct kvm_vfio_file *kvf; + struct fd f; + int ret; + +@@ -208,18 +209,18 @@ static int kvm_vfio_group_del(struct kvm_device *dev, unsigned int fd) + + mutex_lock(&kv->lock); + +- list_for_each_entry(kvg, &kv->group_list, node) { +- if (kvg->file != f.file) ++ list_for_each_entry(kvf, &kv->file_list, node) { ++ if (kvf->file != f.file) + continue; + +- list_del(&kvg->node); ++ list_del(&kvf->node); + kvm_arch_end_assignment(dev->kvm); + #ifdef CONFIG_SPAPR_TCE_IOMMU +- kvm_spapr_tce_release_vfio_group(dev->kvm, kvg); ++ kvm_spapr_tce_release_vfio_group(dev->kvm, kvf); + #endif +- kvm_vfio_file_set_kvm(kvg->file, NULL); +- fput(kvg->file); +- kfree(kvg); ++ kvm_vfio_file_set_kvm(kvf->file, NULL); ++ fput(kvf->file); ++ kfree(kvf); + ret = 0; + break; + } +@@ -234,12 +235,12 @@ static int kvm_vfio_group_del(struct kvm_device *dev, unsigned int fd) + } + + #ifdef CONFIG_SPAPR_TCE_IOMMU +-static int kvm_vfio_group_set_spapr_tce(struct kvm_device *dev, +- void __user *arg) ++static int kvm_vfio_file_set_spapr_tce(struct kvm_device *dev, ++ void __user *arg) + { + struct kvm_vfio_spapr_tce param; + struct kvm_vfio *kv = dev->private; +- struct kvm_vfio_group *kvg; ++ struct kvm_vfio_file *kvf; + struct fd f; + int ret; + +@@ -254,20 +255,20 @@ static int kvm_vfio_group_set_spapr_tce(struct kvm_device *dev, + + mutex_lock(&kv->lock); + +- list_for_each_entry(kvg, &kv->group_list, node) { +- if (kvg->file != f.file) ++ list_for_each_entry(kvf, &kv->file_list, node) { ++ if (kvf->file != f.file) + continue; + +- if (!kvg->iommu_group) { +- kvg->iommu_group = kvm_vfio_file_iommu_group(kvg->file); +- if (WARN_ON_ONCE(!kvg->iommu_group)) { ++ if (!kvf->iommu_group) { ++ kvf->iommu_group = kvm_vfio_file_iommu_group(kvf->file); ++ if (WARN_ON_ONCE(!kvf->iommu_group)) { + ret = -EIO; + goto err_fdput; + } + } + + ret = kvm_spapr_tce_attach_iommu_group(dev->kvm, param.tablefd, +- kvg->iommu_group); ++ kvf->iommu_group); + break; + } + +@@ -278,8 +279,8 @@ err_fdput: + } + #endif + +-static int kvm_vfio_set_group(struct kvm_device *dev, long attr, +- void __user *arg) ++static int kvm_vfio_set_file(struct kvm_device *dev, long attr, ++ void __user *arg) + { + int32_t __user *argp = arg; + int32_t fd; +@@ -288,16 +289,16 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, + case KVM_DEV_VFIO_GROUP_ADD: + if (get_user(fd, argp)) + return -EFAULT; +- return kvm_vfio_group_add(dev, fd); ++ return kvm_vfio_file_add(dev, fd); + + case KVM_DEV_VFIO_GROUP_DEL: + if (get_user(fd, argp)) + return -EFAULT; +- return kvm_vfio_group_del(dev, fd); ++ return kvm_vfio_file_del(dev, fd); + + #ifdef CONFIG_SPAPR_TCE_IOMMU + case KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: +- return kvm_vfio_group_set_spapr_tce(dev, arg); ++ return kvm_vfio_file_set_spapr_tce(dev, arg); + #endif + } + +@@ -309,8 +310,8 @@ static int kvm_vfio_set_attr(struct kvm_device *dev, + { + switch (attr->group) { + case KVM_DEV_VFIO_GROUP: +- return kvm_vfio_set_group(dev, attr->attr, +- u64_to_user_ptr(attr->addr)); ++ return kvm_vfio_set_file(dev, attr->attr, ++ u64_to_user_ptr(attr->addr)); + } + + return -ENXIO; +@@ -339,16 +340,16 @@ static int kvm_vfio_has_attr(struct kvm_device *dev, + static void kvm_vfio_release(struct kvm_device *dev) + { + struct kvm_vfio *kv = dev->private; +- struct kvm_vfio_group *kvg, *tmp; ++ struct kvm_vfio_file *kvf, *tmp; + +- list_for_each_entry_safe(kvg, tmp, &kv->group_list, node) { ++ list_for_each_entry_safe(kvf, tmp, &kv->file_list, node) { + #ifdef CONFIG_SPAPR_TCE_IOMMU +- kvm_spapr_tce_release_vfio_group(dev->kvm, kvg); ++ kvm_spapr_tce_release_vfio_group(dev->kvm, kvf); + #endif +- kvm_vfio_file_set_kvm(kvg->file, NULL); +- fput(kvg->file); +- list_del(&kvg->node); +- kfree(kvg); ++ kvm_vfio_file_set_kvm(kvf->file, NULL); ++ fput(kvf->file); ++ list_del(&kvf->node); ++ kfree(kvf); + kvm_arch_end_assignment(dev->kvm); + } + +@@ -382,7 +383,7 @@ static int kvm_vfio_create(struct kvm_device *dev, u32 type) + if (!kv) + return -ENOMEM; + +- INIT_LIST_HEAD(&kv->group_list); ++ INIT_LIST_HEAD(&kv->file_list); + mutex_init(&kv->lock); + + dev->private = kv; |